X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fvbo%2Fvbo_exec_array.c;h=16aee3be7a45efe7728e5f4dd3185007c3d91f93;hb=5306ee736ebcce0c1cf899589c2344acdedc2162;hp=e829b2b89f1f16b03bd431c269f5227414b7d387;hpb=ed42c2580717527b2005580940fc766d95bb6b0b;p=mesa.git diff --git a/src/mesa/vbo/vbo_exec_array.c b/src/mesa/vbo/vbo_exec_array.c index e829b2b89f1..16aee3be7a4 100644 --- a/src/mesa/vbo/vbo_exec_array.c +++ b/src/mesa/vbo/vbo_exec_array.c @@ -1,6 +1,6 @@ /************************************************************************** * - * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * Copyright 2003 VMware, Inc. * Copyright 2009 VMware, Inc. * All Rights Reserved. * @@ -19,7 +19,7 @@ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. - * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -30,10 +30,12 @@ #include "main/context.h" #include "main/state.h" #include "main/api_validate.h" +#include "main/dispatch.h" #include "main/varray.h" #include "main/bufferobj.h" #include "main/enums.h" #include "main/macros.h" +#include "main/transformfeedback.h" #include "vbo_context.h" @@ -82,40 +84,24 @@ vbo_check_buffers_are_unmapped(struct gl_context *ctx) * If primitive restart is enabled, we need to ignore restart * indexes when computing min/max. */ -void +static void vbo_get_minmax_index(struct gl_context *ctx, const struct _mesa_prim *prim, const struct _mesa_index_buffer *ib, - GLuint *min_index, GLuint *max_index) + GLuint *min_index, GLuint *max_index, + const GLuint count) { - const GLboolean restart = ctx->Array.PrimitiveRestart; - const GLuint restartIndex = ctx->Array.RestartIndex; - const GLuint count = prim->count; - const void *indices; + const GLboolean restart = ctx->Array._PrimitiveRestart; + const GLuint restartIndex = _mesa_primitive_restart_index(ctx, ib->type); + const int index_size = vbo_sizeof_ib_type(ib->type); + const char *indices; GLuint i; + indices = (char *) ib->ptr + prim->start * index_size; if (_mesa_is_bufferobj(ib->obj)) { - unsigned map_size; - - switch (ib->type) { - case GL_UNSIGNED_INT: - map_size = count * sizeof(GLuint); - break; - case GL_UNSIGNED_SHORT: - map_size = count * sizeof(GLushort); - break; - case GL_UNSIGNED_BYTE: - map_size = count * sizeof(GLubyte); - break; - default: - assert(0); - map_size = 0; - } - - indices = ctx->Driver.MapBufferRange(ctx, (GLsizeiptr) ib->ptr, map_size, - GL_MAP_READ_BIT, ib->obj); - } else { - indices = ib->ptr; + GLsizeiptr size = MIN2(count * index_size, ib->obj->Size); + indices = ctx->Driver.MapBufferRange(ctx, (GLintptr) indices, size, + GL_MAP_READ_BIT, ib->obj); } switch (ib->type) { @@ -195,6 +181,41 @@ vbo_get_minmax_index(struct gl_context *ctx, } } +/** + * Compute min and max elements for nr_prims + */ +void +vbo_get_minmax_indices(struct gl_context *ctx, + const struct _mesa_prim *prims, + const struct _mesa_index_buffer *ib, + GLuint *min_index, + GLuint *max_index, + GLuint nr_prims) +{ + GLuint tmp_min, tmp_max; + GLuint i; + GLuint count; + + *min_index = ~0; + *max_index = 0; + + for (i = 0; i < nr_prims; i++) { + const struct _mesa_prim *start_prim; + + start_prim = &prims[i]; + count = start_prim->count; + /* Do combination if possible to reduce map/unmap count */ + while ((i + 1 < nr_prims) && + (prims[i].start + prims[i].count == prims[i+1].start)) { + count += prims[i+1].count; + i++; + } + vbo_get_minmax_index(ctx, start_prim, ib, &tmp_min, &tmp_max, count); + *min_index = MIN2(*min_index, tmp_min); + *max_index = MAX2(*max_index, tmp_max); + } +} + /** * Check that element 'j' of the array has reasonable data. @@ -297,16 +318,8 @@ check_draw_elements_data(struct gl_context *ctx, GLsizei count, GLenum elemType, } /* check element j of each enabled array */ - check_array_data(ctx, &arrayObj->Vertex, VERT_ATTRIB_POS, j); - check_array_data(ctx, &arrayObj->Normal, VERT_ATTRIB_NORMAL, j); - check_array_data(ctx, &arrayObj->Color, VERT_ATTRIB_COLOR0, j); - check_array_data(ctx, &arrayObj->SecondaryColor, VERT_ATTRIB_COLOR1, j); - for (k = 0; k < Elements(arrayObj->TexCoord); k++) { - check_array_data(ctx, &arrayObj->TexCoord[k], VERT_ATTRIB_TEX0 + k, j); - } - for (k = 0; k < Elements(arrayObj->VertexAttrib); k++) { - check_array_data(ctx, &arrayObj->VertexAttrib[k], - VERT_ATTRIB_GENERIC0 + k, j); + for (k = 0; k < Elements(arrayObj->_VertexAttrib); k++) { + check_array_data(ctx, &arrayObj->_VertexAttrib[k], k, j); } } @@ -314,14 +327,8 @@ check_draw_elements_data(struct gl_context *ctx, GLsizei count, GLenum elemType, ctx->Driver.UnmapBuffer(ctx, ctx->Array.ArrayObj->ElementArrayBufferObj); } - unmap_array_buffer(ctx, &arrayObj->Vertex); - unmap_array_buffer(ctx, &arrayObj->Normal); - unmap_array_buffer(ctx, &arrayObj->Color); - for (k = 0; k < Elements(arrayObj->TexCoord); k++) { - unmap_array_buffer(ctx, &arrayObj->TexCoord[k]); - } - for (k = 0; k < Elements(arrayObj->VertexAttrib); k++) { - unmap_array_buffer(ctx, &arrayObj->VertexAttrib[k]); + for (k = 0; k < Elements(arrayObj->_VertexAttrib); k++) { + unmap_array_buffer(ctx, &arrayObj->_VertexAttrib[k]); } } @@ -345,6 +352,7 @@ print_draw_arrays(struct gl_context *ctx, { struct vbo_context *vbo = vbo_context(ctx); struct vbo_exec_context *exec = &vbo->exec; + struct gl_array_object *arrayObj = ctx->Array.ArrayObj; int i; printf("vbo_exec_DrawArrays(mode 0x%x, start %d, count %d):\n", @@ -360,7 +368,7 @@ print_draw_arrays(struct gl_context *ctx, exec->array.inputs[i]->Size, stride, /*exec->array.inputs[i]->Enabled,*/ - exec->array.legacy_array[i]->Enabled, + arrayObj->_VertexAttrib[VERT_ATTRIB_FF(i)].Enabled, exec->array.inputs[i]->Ptr, bufName); @@ -384,47 +392,6 @@ print_draw_arrays(struct gl_context *ctx, } -/** - * Bind the VBO executor to the current vertex array object prior - * to drawing. - * - * Just translate the arrayobj into a sane layout. - */ -static void -bind_array_obj(struct gl_context *ctx) -{ - struct vbo_context *vbo = vbo_context(ctx); - struct vbo_exec_context *exec = &vbo->exec; - struct gl_array_object *arrayObj = ctx->Array.ArrayObj; - GLuint i; - - /* TODO: Fix the ArrayObj struct to keep legacy arrays in an array - * rather than as individual named arrays. Then this function can - * go away. - */ - exec->array.legacy_array[VERT_ATTRIB_POS] = &arrayObj->Vertex; - exec->array.legacy_array[VERT_ATTRIB_WEIGHT] = &arrayObj->Weight; - exec->array.legacy_array[VERT_ATTRIB_NORMAL] = &arrayObj->Normal; - exec->array.legacy_array[VERT_ATTRIB_COLOR0] = &arrayObj->Color; - exec->array.legacy_array[VERT_ATTRIB_COLOR1] = &arrayObj->SecondaryColor; - exec->array.legacy_array[VERT_ATTRIB_FOG] = &arrayObj->FogCoord; - exec->array.legacy_array[VERT_ATTRIB_COLOR_INDEX] = &arrayObj->Index; - if (arrayObj->PointSize.Enabled) { - /* this aliases COLOR_INDEX */ - exec->array.legacy_array[VERT_ATTRIB_POINT_SIZE] = &arrayObj->PointSize; - } - exec->array.legacy_array[VERT_ATTRIB_EDGEFLAG] = &arrayObj->EdgeFlag; - - for (i = 0; i < Elements(arrayObj->TexCoord); i++) - exec->array.legacy_array[VERT_ATTRIB_TEX0 + i] = &arrayObj->TexCoord[i]; - - for (i = 0; i < Elements(arrayObj->VertexAttrib); i++) { - assert(i < Elements(exec->array.generic_array)); - exec->array.generic_array[i] = &arrayObj->VertexAttrib[i]; - } -} - - /** * Set the vbo->exec->inputs[] pointers to point to the enabled * vertex arrays. This depends on the current vertex program/shader @@ -438,8 +405,9 @@ recalculate_input_bindings(struct gl_context *ctx) { struct vbo_context *vbo = vbo_context(ctx); struct vbo_exec_context *exec = &vbo->exec; + struct gl_client_array *vertexAttrib = ctx->Array.ArrayObj->_VertexAttrib; const struct gl_client_array **inputs = &exec->array.inputs[0]; - GLbitfield const_inputs = 0x0; + GLbitfield64 const_inputs = 0x0; GLuint i; switch (get_program_mode(ctx)) { @@ -450,16 +418,17 @@ recalculate_input_bindings(struct gl_context *ctx) * are available as per-vertex attributes. */ for (i = 0; i < VERT_ATTRIB_FF_MAX; i++) { - if (exec->array.legacy_array[i]->Enabled) - inputs[i] = exec->array.legacy_array[i]; + if (vertexAttrib[VERT_ATTRIB_FF(i)].Enabled) + inputs[i] = &vertexAttrib[VERT_ATTRIB_FF(i)]; else { - inputs[i] = &vbo->legacy_currval[i]; + inputs[i] = &vbo->currval[VBO_ATTRIB_POS+i]; const_inputs |= VERT_BIT(i); } } for (i = 0; i < MAT_ATTRIB_MAX; i++) { - inputs[VERT_ATTRIB_GENERIC(i)] = &vbo->mat_currval[i]; + inputs[VERT_ATTRIB_GENERIC(i)] = + &vbo->currval[VBO_ATTRIB_MAT_FRONT_AMBIENT+i]; const_inputs |= VERT_BIT_GENERIC(i); } @@ -467,88 +436,88 @@ recalculate_input_bindings(struct gl_context *ctx) * slots: */ for (i = MAT_ATTRIB_MAX; i < VERT_ATTRIB_GENERIC_MAX; i++) { - inputs[VERT_ATTRIB_GENERIC(i)] = &vbo->generic_currval[i]; + inputs[VERT_ATTRIB_GENERIC(i)] = &vbo->currval[VBO_ATTRIB_GENERIC0+i]; const_inputs |= VERT_BIT_GENERIC(i); } - - /* There is no need to make _NEW_ARRAY dirty here for the TnL program, - * because it already takes care of invalidating the state necessary - * to revalidate vertex arrays. Not marking the state as dirty also - * improves performance (quite significantly in some apps). - */ - if (!ctx->VertexProgram._MaintainTnlProgram) - ctx->NewState |= _NEW_ARRAY; break; - case VP_NV: - /* NV_vertex_program - attribute arrays alias and override - * conventional, legacy arrays. No materials, and the generic - * slots are vacant. - */ - for (i = 0; i < VERT_ATTRIB_FF_MAX; i++) { - if (i < VERT_ATTRIB_GENERIC_MAX - && exec->array.generic_array[i]->Enabled) - inputs[i] = exec->array.generic_array[i]; - else if (exec->array.legacy_array[i]->Enabled) - inputs[i] = exec->array.legacy_array[i]; - else { - inputs[i] = &vbo->legacy_currval[i]; - const_inputs |= VERT_BIT_FF(i); - } - } - - /* Could use just about anything, just to fill in the empty - * slots: + case VP_ARB: + /* There are no shaders in OpenGL ES 1.x, so this code path should be + * impossible to reach. The meta code is careful to not use shaders in + * ES1. */ - for (i = 0; i < VERT_ATTRIB_GENERIC_MAX; i++) { - inputs[VERT_ATTRIB_GENERIC(i)] = &vbo->generic_currval[i]; - const_inputs |= VERT_BIT_GENERIC(i); - } - - ctx->NewState |= _NEW_ARRAY; - break; + assert(ctx->API != API_OPENGLES); - case VP_ARB: - /* GL_ARB_vertex_program or GLSL vertex shader - Only the generic[0] + /* In the compatibility profile of desktop OpenGL, the generic[0] * attribute array aliases and overrides the legacy position array. - * * Otherwise, legacy attributes available in the legacy slots, * generic attributes in the generic slots and materials are not * available as per-vertex attributes. + * + * In all other APIs, only the generic attributes exist, and none of the + * slots are considered "magic." */ - if (exec->array.generic_array[0]->Enabled) - inputs[0] = exec->array.generic_array[0]; - else if (exec->array.legacy_array[0]->Enabled) - inputs[0] = exec->array.legacy_array[0]; - else { - inputs[0] = &vbo->legacy_currval[0]; - const_inputs |= VERT_BIT_POS; - } + if (ctx->API == API_OPENGL_COMPAT) { + if (vertexAttrib[VERT_ATTRIB_GENERIC0].Enabled) + inputs[0] = &vertexAttrib[VERT_ATTRIB_GENERIC0]; + else if (vertexAttrib[VERT_ATTRIB_POS].Enabled) + inputs[0] = &vertexAttrib[VERT_ATTRIB_POS]; + else { + inputs[0] = &vbo->currval[VBO_ATTRIB_POS]; + const_inputs |= VERT_BIT_POS; + } - for (i = 1; i < VERT_ATTRIB_FF_MAX; i++) { - if (exec->array.legacy_array[i]->Enabled) - inputs[i] = exec->array.legacy_array[i]; - else { - inputs[i] = &vbo->legacy_currval[i]; + for (i = 1; i < VERT_ATTRIB_FF_MAX; i++) { + if (vertexAttrib[VERT_ATTRIB_FF(i)].Enabled) + inputs[i] = &vertexAttrib[VERT_ATTRIB_FF(i)]; + else { + inputs[i] = &vbo->currval[VBO_ATTRIB_POS+i]; + const_inputs |= VERT_BIT_FF(i); + } + } + + for (i = 1; i < VERT_ATTRIB_GENERIC_MAX; i++) { + if (vertexAttrib[VERT_ATTRIB_GENERIC(i)].Enabled) + inputs[VERT_ATTRIB_GENERIC(i)] = + &vertexAttrib[VERT_ATTRIB_GENERIC(i)]; + else { + inputs[VERT_ATTRIB_GENERIC(i)] = + &vbo->currval[VBO_ATTRIB_GENERIC0+i]; + const_inputs |= VERT_BIT_GENERIC(i); + } + } + + inputs[VERT_ATTRIB_GENERIC0] = inputs[0]; + } else { + /* Other parts of the code assume that inputs[0] through + * inputs[VERT_ATTRIB_FF_MAX] will be non-NULL. However, in OpenGL + * ES 2.0+ or OpenGL core profile, none of these arrays should ever + * be enabled. + */ + for (i = 0; i < VERT_ATTRIB_FF_MAX; i++) { + assert(!vertexAttrib[VERT_ATTRIB_FF(i)].Enabled); + + inputs[i] = &vbo->currval[VBO_ATTRIB_POS+i]; const_inputs |= VERT_BIT_FF(i); } - } - for (i = 1; i < VERT_ATTRIB_GENERIC_MAX; i++) { - if (exec->array.generic_array[i]->Enabled) - inputs[VERT_ATTRIB_GENERIC(i)] = exec->array.generic_array[i]; - else { - inputs[VERT_ATTRIB_GENERIC(i)] = &vbo->generic_currval[i]; - const_inputs |= VERT_BIT_GENERIC(i); + for (i = 0; i < VERT_ATTRIB_GENERIC_MAX; i++) { + if (vertexAttrib[VERT_ATTRIB_GENERIC(i)].Enabled) + inputs[VERT_ATTRIB_GENERIC(i)] = + &vertexAttrib[VERT_ATTRIB_GENERIC(i)]; + else { + inputs[VERT_ATTRIB_GENERIC(i)] = + &vbo->currval[VBO_ATTRIB_GENERIC0+i]; + const_inputs |= VERT_BIT_GENERIC(i); + } } } - inputs[VERT_ATTRIB_GENERIC0] = inputs[0]; - ctx->NewState |= _NEW_ARRAY; break; } - _mesa_set_varying_vp_inputs( ctx, ~const_inputs ); + _mesa_set_varying_vp_inputs( ctx, VERT_BIT_ALL & (~const_inputs) ); + ctx->NewDriverState |= ctx->DriverFlags.NewArray; } @@ -556,19 +525,66 @@ recalculate_input_bindings(struct gl_context *ctx) * Examine the enabled vertex arrays to set the exec->array.inputs[] values. * These will point to the arrays to actually use for drawing. Some will * be user-provided arrays, other will be zero-stride const-valued arrays. - * Note that this might set the _NEW_ARRAY dirty flag so state validation - * must be done after this call. + * Note that this might set the _NEW_VARYING_VP_INPUTS dirty flag so state + * validation must be done after this call. */ void vbo_bind_arrays(struct gl_context *ctx) { - if (!ctx->Array.RebindArrays) { - return; + struct vbo_context *vbo = vbo_context(ctx); + struct vbo_exec_context *exec = &vbo->exec; + + vbo_draw_method(vbo, DRAW_ARRAYS); + + if (exec->array.recalculate_inputs) { + recalculate_input_bindings(ctx); + exec->array.recalculate_inputs = GL_FALSE; + + /* Again... because we may have changed the bitmask of per-vertex varying + * attributes. If we regenerate the fixed-function vertex program now + * we may be able to prune down the number of vertex attributes which we + * need in the shader. + */ + if (ctx->NewState) { + /* Setting "validating" to TRUE prevents _mesa_update_state from + * invalidating what we just did. + */ + exec->validating = GL_TRUE; + _mesa_update_state(ctx); + exec->validating = GL_FALSE; + } } +} + + +/** + * Handle a draw case that potentially has primitive restart enabled. + * + * If primitive restart is enabled, and PrimitiveRestartInSoftware is + * set, then vbo_sw_primitive_restart is used to handle the primitive + * restart case in software. + */ +static void +vbo_handle_primitive_restart(struct gl_context *ctx, + const struct _mesa_prim *prim, + GLuint nr_prims, + const struct _mesa_index_buffer *ib, + GLboolean index_bounds_valid, + GLuint min_index, + GLuint max_index) +{ + struct vbo_context *vbo = vbo_context(ctx); - bind_array_obj(ctx); - recalculate_input_bindings(ctx); - ctx->Array.RebindArrays = GL_FALSE; + if ((ib != NULL) && + ctx->Const.PrimitiveRestartInSoftware && + ctx->Array._PrimitiveRestart) { + /* Handle primitive restart in software */ + vbo_sw_primitive_restart(ctx, prim, nr_prims, ib, NULL); + } else { + /* Call driver directly for draw_prims */ + vbo->draw_prims(ctx, prim, nr_prims, ib, + index_bounds_valid, min_index, max_index, NULL, NULL); + } } @@ -580,7 +596,7 @@ vbo_bind_arrays(struct gl_context *ctx) */ static void vbo_draw_arrays(struct gl_context *ctx, GLenum mode, GLint start, - GLsizei count, GLuint numInstances) + GLsizei count, GLuint numInstances, GLuint baseInstance) { struct vbo_context *vbo = vbo_context(ctx); struct vbo_exec_context *exec = &vbo->exec; @@ -588,20 +604,14 @@ vbo_draw_arrays(struct gl_context *ctx, GLenum mode, GLint start, vbo_bind_arrays(ctx); - /* Again... because we may have changed the bitmask of per-vertex varying - * attributes. If we regenerate the fixed-function vertex program now - * we may be able to prune down the number of vertex attributes which we - * need in the shader. - */ - if (ctx->NewState) - _mesa_update_state(ctx); - /* init most fields to zero */ memset(prim, 0, sizeof(prim)); prim[0].begin = 1; prim[0].end = 1; prim[0].mode = mode; prim[0].num_instances = numInstances; + prim[0].base_instance = baseInstance; + prim[0].is_indirect = 0; /* Implement the primitive restart index */ if (ctx->Array.PrimitiveRestart && ctx->Array.RestartIndex < count) { @@ -638,8 +648,8 @@ vbo_draw_arrays(struct gl_context *ctx, GLenum mode, GLint start, if (primCount > 0) { /* draw one or two prims */ check_buffers_are_unmapped(exec->array.inputs); - vbo->draw_prims(ctx, exec->array.inputs, prim, primCount, NULL, - GL_TRUE, start, start + count - 1); + vbo->draw_prims(ctx, prim, primCount, NULL, + GL_TRUE, start, start + count - 1, NULL, NULL); } } else { @@ -648,12 +658,139 @@ vbo_draw_arrays(struct gl_context *ctx, GLenum mode, GLint start, prim[0].count = count; check_buffers_are_unmapped(exec->array.inputs); - vbo->draw_prims(ctx, exec->array.inputs, prim, 1, NULL, - GL_TRUE, start, start + count - 1); + vbo->draw_prims(ctx, prim, 1, NULL, + GL_TRUE, start, start + count - 1, + NULL, NULL); + } + + if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) { + _mesa_flush(ctx); } } +/** + * Execute a glRectf() function. + */ +static void GLAPIENTRY +vbo_exec_Rectf(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + CALL_Begin(GET_DISPATCH(), (GL_QUADS)); + CALL_Vertex2f(GET_DISPATCH(), (x1, y1)); + CALL_Vertex2f(GET_DISPATCH(), (x2, y1)); + CALL_Vertex2f(GET_DISPATCH(), (x2, y2)); + CALL_Vertex2f(GET_DISPATCH(), (x1, y2)); + CALL_End(GET_DISPATCH(), ()); +} + + +static void GLAPIENTRY +vbo_exec_EvalMesh1(GLenum mode, GLint i1, GLint i2) +{ + GET_CURRENT_CONTEXT(ctx); + GLint i; + GLfloat u, du; + GLenum prim; + + switch (mode) { + case GL_POINT: + prim = GL_POINTS; + break; + case GL_LINE: + prim = GL_LINE_STRIP; + break; + default: + _mesa_error( ctx, GL_INVALID_ENUM, "glEvalMesh1(mode)" ); + return; + } + + /* No effect if vertex maps disabled. + */ + if (!ctx->Eval.Map1Vertex4 && + !ctx->Eval.Map1Vertex3) + return; + + du = ctx->Eval.MapGrid1du; + u = ctx->Eval.MapGrid1u1 + i1 * du; + + CALL_Begin(GET_DISPATCH(), (prim)); + for (i=i1;i<=i2;i++,u+=du) { + CALL_EvalCoord1f(GET_DISPATCH(), (u)); + } + CALL_End(GET_DISPATCH(), ()); +} + + +static void GLAPIENTRY +vbo_exec_EvalMesh2(GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2) +{ + GET_CURRENT_CONTEXT(ctx); + GLfloat u, du, v, dv, v1, u1; + GLint i, j; + + switch (mode) { + case GL_POINT: + case GL_LINE: + case GL_FILL: + break; + default: + _mesa_error( ctx, GL_INVALID_ENUM, "glEvalMesh2(mode)" ); + return; + } + + /* No effect if vertex maps disabled. + */ + if (!ctx->Eval.Map2Vertex4 && + !ctx->Eval.Map2Vertex3) + return; + + du = ctx->Eval.MapGrid2du; + dv = ctx->Eval.MapGrid2dv; + v1 = ctx->Eval.MapGrid2v1 + j1 * dv; + u1 = ctx->Eval.MapGrid2u1 + i1 * du; + + switch (mode) { + case GL_POINT: + CALL_Begin(GET_DISPATCH(), (GL_POINTS)); + for (v=v1,j=j1;j<=j2;j++,v+=dv) { + for (u=u1,i=i1;i<=i2;i++,u+=du) { + CALL_EvalCoord2f(GET_DISPATCH(), (u, v)); + } + } + CALL_End(GET_DISPATCH(), ()); + break; + case GL_LINE: + for (v=v1,j=j1;j<=j2;j++,v+=dv) { + CALL_Begin(GET_DISPATCH(), (GL_LINE_STRIP)); + for (u=u1,i=i1;i<=i2;i++,u+=du) { + CALL_EvalCoord2f(GET_DISPATCH(), (u, v)); + } + CALL_End(GET_DISPATCH(), ()); + } + for (u=u1,i=i1;i<=i2;i++,u+=du) { + CALL_Begin(GET_DISPATCH(), (GL_LINE_STRIP)); + for (v=v1,j=j1;j<=j2;j++,v+=dv) { + CALL_EvalCoord2f(GET_DISPATCH(), (u, v)); + } + CALL_End(GET_DISPATCH(), ()); + } + break; + case GL_FILL: + for (v=v1,j=j1;jDriver.UnmapBuffer(ctx, ctx->Array.ArrayObj->ElementArrayBufferObj); } +#endif /** @@ -787,24 +943,15 @@ vbo_validated_drawrangeelements(struct gl_context *ctx, GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices, - GLint basevertex, GLint numInstances) + GLint basevertex, GLuint numInstances, + GLuint baseInstance) { struct vbo_context *vbo = vbo_context(ctx); struct vbo_exec_context *exec = &vbo->exec; struct _mesa_index_buffer ib; struct _mesa_prim prim[1]; - FLUSH_CURRENT( ctx, 0 ); - - if (!_mesa_valid_to_render(ctx, "glDraw[Range]Elements")) { - return; - } - - vbo_bind_arrays( ctx ); - - /* check for dirty state again */ - if (ctx->NewState) - _mesa_update_state( ctx ); + vbo_bind_arrays(ctx); ib.count = count; ib.type = type; @@ -819,8 +966,10 @@ vbo_validated_drawrangeelements(struct gl_context *ctx, GLenum mode, prim[0].start = 0; prim[0].count = count; prim[0].indexed = 1; + prim[0].is_indirect = 0; prim[0].basevertex = basevertex; prim[0].num_instances = numInstances; + prim[0].base_instance = baseInstance; /* Need to give special consideration to rendering a range of * indices starting somewhere above zero. Typically the @@ -854,8 +1003,12 @@ vbo_validated_drawrangeelements(struct gl_context *ctx, GLenum mode, */ check_buffers_are_unmapped(exec->array.inputs); - vbo->draw_prims( ctx, exec->array.inputs, prim, 1, &ib, - index_bounds_valid, start, end ); + vbo_handle_primitive_restart(ctx, prim, 1, &ib, + index_bounds_valid, start, end); + + if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) { + _mesa_flush(ctx); + } } @@ -870,6 +1023,8 @@ vbo_exec_DrawRangeElementsBaseVertex(GLenum mode, GLint basevertex) { static GLuint warnCount = 0; + GLboolean index_bounds_valid = GL_TRUE; + GLuint max_element; GET_CURRENT_CONTEXT(ctx); if (MESA_VERBOSE & VERBOSE_DRAW) @@ -882,6 +1037,45 @@ vbo_exec_DrawRangeElementsBaseVertex(GLenum mode, type, indices, basevertex )) return; + if (ctx->Const.CheckArrayBounds) { + /* _MaxElement was computed, so we can use it. + * This path is used for drivers which need strict bounds checking. + */ + max_element = ctx->Array.ArrayObj->_MaxElement; + } + else { + /* Generally, hardware drivers don't need to know the buffer bounds + * if all vertex attributes are in VBOs. + * However, if none of vertex attributes are in VBOs, _MaxElement + * is always set to some random big number anyway, so bounds checking + * is mostly useless. + * + * This is only useful to catch invalid values in the "end" parameter + * like ~0. + */ + max_element = 2 * 1000 * 1000 * 1000; /* just a big number */ + } + + if ((int) end + basevertex < 0 || + start + basevertex >= max_element) { + /* The application requested we draw using a range of indices that's + * outside the bounds of the current VBO. This is invalid and appears + * to give undefined results. The safest thing to do is to simply + * ignore the range, in case the application botched their range tracking + * but did provide valid indices. Also issue a warning indicating that + * the application is broken. + */ + if (warnCount++ < 10) { + _mesa_warning(ctx, "glDrawRangeElements(start %u, end %u, " + "basevertex %d, count %d, type 0x%x, indices=%p):\n" + "\trange is outside VBO bounds (max=%u); ignoring.\n" + "\tThis should be fixed in the application.", + start, end, basevertex, count, type, indices, + max_element - 1); + } + index_bounds_valid = GL_FALSE; + } + /* NOTE: It's important that 'end' is a reasonable value. * in _tnl_draw_prims(), we use end to determine how many vertices * to transform. If it's too large, we can unnecessarily split prims @@ -898,62 +1092,6 @@ vbo_exec_DrawRangeElementsBaseVertex(GLenum mode, end = MIN2(end, 0xffff); } - if (end >= ctx->Array.ArrayObj->_MaxElement) { - /* the max element is out of bounds of one or more enabled arrays */ - warnCount++; - - if (warnCount < 10) { - _mesa_warning(ctx, "glDraw[Range]Elements(start %u, end %u, count %d, " - "type 0x%x, indices=%p)\n" - "\tend is out of bounds (max=%u) " - "Element Buffer %u (size %d)\n" - "\tThis should probably be fixed in the application.", - start, end, count, type, indices, - ctx->Array.ArrayObj->_MaxElement - 1, - ctx->Array.ArrayObj->ElementArrayBufferObj->Name, - (int) ctx->Array.ArrayObj->ElementArrayBufferObj->Size); - } - - if (0) - dump_element_buffer(ctx, type); - - if (0) - _mesa_print_arrays(ctx); - - /* 'end' was out of bounds, but now let's check the actual array - * indexes to see if any of them are out of bounds. - */ - if (0) { - GLuint max = _mesa_max_buffer_index(ctx, count, type, indices, - ctx->Array.ArrayObj->ElementArrayBufferObj); - if (max >= ctx->Array.ArrayObj->_MaxElement) { - if (warnCount < 10) { - _mesa_warning(ctx, "glDraw[Range]Elements(start %u, end %u, " - "count %d, type 0x%x, indices=%p)\n" - "\tindex=%u is out of bounds (max=%u) " - "Element Buffer %u (size %d)\n" - "\tSkipping the glDrawRangeElements() call", - start, end, count, type, indices, max, - ctx->Array.ArrayObj->_MaxElement - 1, - ctx->Array.ArrayObj->ElementArrayBufferObj->Name, - (int) ctx->Array.ArrayObj->ElementArrayBufferObj->Size); - } - } - /* XXX we could also find the min index and compare to 'start' - * to see if start is correct. But it's more likely to get the - * upper bound wrong. - */ - } - - /* Set 'end' to the max possible legal value */ - assert(ctx->Array.ArrayObj->_MaxElement >= 1); - end = ctx->Array.ArrayObj->_MaxElement - 1; - - if (end < start) { - return; - } - } - if (0) { printf("glDraw[Range]Elements{,BaseVertex}" "(start %u, end %u, type 0x%x, count %d) ElemBuf %u, " @@ -963,14 +1101,18 @@ vbo_exec_DrawRangeElementsBaseVertex(GLenum mode, basevertex); } + if ((int) start + basevertex < 0 || + end + basevertex >= max_element) + index_bounds_valid = GL_FALSE; + #if 0 check_draw_elements_data(ctx, count, type, indices); #else (void) check_draw_elements_data; #endif - vbo_validated_drawrangeelements(ctx, mode, GL_TRUE, start, end, - count, type, indices, basevertex, 1); + vbo_validated_drawrangeelements(ctx, mode, index_bounds_valid, start, end, + count, type, indices, basevertex, 1, 0); } @@ -1012,7 +1154,7 @@ vbo_exec_DrawElements(GLenum mode, GLsizei count, GLenum type, return; vbo_validated_drawrangeelements(ctx, mode, GL_FALSE, ~0, ~0, - count, type, indices, 0, 1); + count, type, indices, 0, 1, 0); } @@ -1035,7 +1177,7 @@ vbo_exec_DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, return; vbo_validated_drawrangeelements(ctx, mode, GL_FALSE, ~0, ~0, - count, type, indices, basevertex, 1); + count, type, indices, basevertex, 1, 0); } @@ -1058,9 +1200,10 @@ vbo_exec_DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, return; vbo_validated_drawrangeelements(ctx, mode, GL_FALSE, ~0, ~0, - count, type, indices, 0, numInstances); + count, type, indices, 0, numInstances, 0); } + /** * Called by glDrawElementsInstancedBaseVertex() in immediate mode. */ @@ -1082,7 +1225,59 @@ vbo_exec_DrawElementsInstancedBaseVertex(GLenum mode, GLsizei count, GLenum type return; vbo_validated_drawrangeelements(ctx, mode, GL_FALSE, ~0, ~0, - count, type, indices, basevertex, numInstances); + count, type, indices, basevertex, numInstances, 0); +} + + +/** + * Called by glDrawElementsInstancedBaseInstance() in immediate mode. + */ +static void GLAPIENTRY +vbo_exec_DrawElementsInstancedBaseInstance(GLenum mode, GLsizei count, GLenum type, + const GLvoid *indices, GLsizei numInstances, + GLuint baseInstance) +{ + GET_CURRENT_CONTEXT(ctx); + + if (MESA_VERBOSE & VERBOSE_DRAW) + _mesa_debug(ctx, "glDrawElementsInstancedBaseInstance(%s, %d, %s, %p, %d, %d)\n", + _mesa_lookup_enum_by_nr(mode), count, + _mesa_lookup_enum_by_nr(type), indices, + numInstances, baseInstance); + + if (!_mesa_validate_DrawElementsInstanced(ctx, mode, count, type, indices, + numInstances, 0)) + return; + + vbo_validated_drawrangeelements(ctx, mode, GL_FALSE, ~0, ~0, + count, type, indices, 0, numInstances, + baseInstance); +} + + +/** + * Called by glDrawElementsInstancedBaseVertexBaseInstance() in immediate mode. + */ +static void GLAPIENTRY +vbo_exec_DrawElementsInstancedBaseVertexBaseInstance(GLenum mode, GLsizei count, GLenum type, + const GLvoid *indices, GLsizei numInstances, + GLint basevertex, GLuint baseInstance) +{ + GET_CURRENT_CONTEXT(ctx); + + if (MESA_VERBOSE & VERBOSE_DRAW) + _mesa_debug(ctx, "glDrawElementsInstancedBaseVertexBaseInstance(%s, %d, %s, %p, %d, %d, %d)\n", + _mesa_lookup_enum_by_nr(mode), count, + _mesa_lookup_enum_by_nr(type), indices, + numInstances, basevertex, baseInstance); + + if (!_mesa_validate_DrawElementsInstanced(ctx, mode, count, type, indices, + numInstances, basevertex)) + return; + + vbo_validated_drawrangeelements(ctx, mode, GL_FALSE, ~0, ~0, + count, type, indices, basevertex, numInstances, + baseInstance); } @@ -1094,14 +1289,15 @@ vbo_exec_DrawElementsInstancedBaseVertex(GLenum mode, GLsizei count, GLenum type static void vbo_validated_multidrawelements(struct gl_context *ctx, GLenum mode, const GLsizei *count, GLenum type, - const GLvoid **indices, GLsizei primcount, + const GLvoid * const *indices, + GLsizei primcount, const GLint *basevertex) { struct vbo_context *vbo = vbo_context(ctx); struct vbo_exec_context *exec = &vbo->exec; struct _mesa_index_buffer ib; struct _mesa_prim *prim; - unsigned int index_type_size = 0; + unsigned int index_type_size = vbo_sizeof_ib_type(type); uintptr_t min_index_ptr, max_index_ptr; GLboolean fallback = GL_FALSE; int i; @@ -1109,41 +1305,13 @@ vbo_validated_multidrawelements(struct gl_context *ctx, GLenum mode, if (primcount == 0) return; - FLUSH_CURRENT( ctx, 0 ); - - if (!_mesa_valid_to_render(ctx, "glMultiDrawElements")) { - return; - } - prim = calloc(1, primcount * sizeof(*prim)); if (prim == NULL) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMultiDrawElements"); return; } - /* Decide if we can do this all as one set of primitives sharing the - * same index buffer, or if we have to reset the index pointer per - * primitive. - */ - vbo_bind_arrays( ctx ); - - /* check for dirty state again */ - if (ctx->NewState) - _mesa_update_state( ctx ); - - switch (type) { - case GL_UNSIGNED_INT: - index_type_size = 4; - break; - case GL_UNSIGNED_SHORT: - index_type_size = 2; - break; - case GL_UNSIGNED_BYTE: - index_type_size = 1; - break; - default: - assert(0); - } + vbo_bind_arrays(ctx); min_index_ptr = (uintptr_t)indices[0]; max_index_ptr = 0; @@ -1168,6 +1336,16 @@ vbo_validated_multidrawelements(struct gl_context *ctx, GLenum mode, } } + /* Draw primitives individually if one count is zero, so we can easily skip + * that primitive. + */ + for (i = 0; i < primcount; i++) { + if (count[i] == 0) { + fallback = GL_TRUE; + break; + } + } + /* If the index buffer isn't in a VBO, then treating the application's * subranges of the index buffer as one large index buffer may lead to * us reading unmapped memory. @@ -1191,6 +1369,8 @@ vbo_validated_multidrawelements(struct gl_context *ctx, GLenum mode, prim[i].count = count[i]; prim[i].indexed = 1; prim[i].num_instances = 1; + prim[i].base_instance = 0; + prim[i].is_indirect = 0; if (basevertex != NULL) prim[i].basevertex = basevertex[i]; else @@ -1198,11 +1378,13 @@ vbo_validated_multidrawelements(struct gl_context *ctx, GLenum mode, } check_buffers_are_unmapped(exec->array.inputs); - vbo->draw_prims(ctx, exec->array.inputs, prim, primcount, &ib, - GL_FALSE, ~0, ~0); + vbo_handle_primitive_restart(ctx, prim, primcount, &ib, + GL_FALSE, ~0, ~0); } else { /* render one prim at a time */ for (i = 0; i < primcount; i++) { + if (count[i] == 0) + continue; ib.count = count[i]; ib.type = type; ib.obj = ctx->Array.ArrayObj->ElementArrayBufferObj; @@ -1217,37 +1399,38 @@ vbo_validated_multidrawelements(struct gl_context *ctx, GLenum mode, prim[0].count = count[i]; prim[0].indexed = 1; prim[0].num_instances = 1; + prim[0].base_instance = 0; + prim[0].is_indirect = 0; if (basevertex != NULL) prim[0].basevertex = basevertex[i]; else prim[0].basevertex = 0; check_buffers_are_unmapped(exec->array.inputs); - vbo->draw_prims(ctx, exec->array.inputs, prim, 1, &ib, - GL_FALSE, ~0, ~0); + vbo_handle_primitive_restart(ctx, prim, 1, &ib, + GL_FALSE, ~0, ~0); } } free(prim); + + if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) { + _mesa_flush(ctx); + } } static void GLAPIENTRY vbo_exec_MultiDrawElements(GLenum mode, const GLsizei *count, GLenum type, - const GLvoid **indices, + const GLvoid * const *indices, GLsizei primcount) { GET_CURRENT_CONTEXT(ctx); - GLint i; - - ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); - for (i = 0; i < primcount; i++) { - if (!_mesa_validate_DrawElements(ctx, mode, count[i], type, indices[i], - 0)) - return; - } + if (!_mesa_validate_MultiDrawElements(ctx, mode, count, type, indices, + primcount, NULL)) + return; vbo_validated_multidrawelements(ctx, mode, count, type, indices, primcount, NULL); @@ -1257,50 +1440,432 @@ vbo_exec_MultiDrawElements(GLenum mode, static void GLAPIENTRY vbo_exec_MultiDrawElementsBaseVertex(GLenum mode, const GLsizei *count, GLenum type, - const GLvoid **indices, + const GLvoid * const *indices, GLsizei primcount, const GLsizei *basevertex) { GET_CURRENT_CONTEXT(ctx); - GLint i; - - ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); - for (i = 0; i < primcount; i++) { - if (!_mesa_validate_DrawElements(ctx, mode, count[i], type, indices[i], - basevertex[i])) - return; - } + if (!_mesa_validate_MultiDrawElements(ctx, mode, count, type, indices, + primcount, basevertex)) + return; vbo_validated_multidrawelements(ctx, mode, count, type, indices, primcount, basevertex); } +static void +vbo_draw_transform_feedback(struct gl_context *ctx, GLenum mode, + struct gl_transform_feedback_object *obj, + GLuint stream, GLuint numInstances) +{ + struct vbo_context *vbo = vbo_context(ctx); + struct vbo_exec_context *exec = &vbo->exec; + struct _mesa_prim prim[2]; + + if (!_mesa_validate_DrawTransformFeedback(ctx, mode, obj, stream, + numInstances)) { + return; + } + + if (ctx->Driver.GetTransformFeedbackVertexCount && + (ctx->Const.AlwaysUseGetTransformFeedbackVertexCount || + (ctx->Const.PrimitiveRestartInSoftware && + ctx->Array._PrimitiveRestart) || + !vbo_all_varyings_in_vbos(exec->array.inputs))) { + GLsizei n = ctx->Driver.GetTransformFeedbackVertexCount(ctx, obj, stream); + vbo_draw_arrays(ctx, mode, 0, n, numInstances, 0); + return; + } + + vbo_bind_arrays(ctx); + + /* init most fields to zero */ + memset(prim, 0, sizeof(prim)); + prim[0].begin = 1; + prim[0].end = 1; + prim[0].mode = mode; + prim[0].num_instances = numInstances; + prim[0].base_instance = 0; + prim[0].is_indirect = 0; + + /* Maybe we should do some primitive splitting for primitive restart + * (like in DrawArrays), but we have no way to know how many vertices + * will be rendered. */ + + check_buffers_are_unmapped(exec->array.inputs); + vbo->draw_prims(ctx, prim, 1, NULL, + GL_TRUE, 0, 0, obj, NULL); + + if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) { + _mesa_flush(ctx); + } +} /** - * Plug in the immediate-mode vertex array drawing commands into the - * givven vbo_exec_context object. + * Like DrawArrays, but take the count from a transform feedback object. + * \param mode GL_POINTS, GL_LINES, GL_TRIANGLE_STRIP, etc. + * \param name the transform feedback object + * User still has to setup of the vertex attribute info with + * glVertexPointer, glColorPointer, etc. + * Part of GL_ARB_transform_feedback2. */ -void -vbo_exec_array_init( struct vbo_exec_context *exec ) +static void GLAPIENTRY +vbo_exec_DrawTransformFeedback(GLenum mode, GLuint name) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_transform_feedback_object *obj = + _mesa_lookup_transform_feedback_object(ctx, name); + + if (MESA_VERBOSE & VERBOSE_DRAW) + _mesa_debug(ctx, "glDrawTransformFeedback(%s, %d)\n", + _mesa_lookup_enum_by_nr(mode), name); + + vbo_draw_transform_feedback(ctx, mode, obj, 0, 1); +} + +static void GLAPIENTRY +vbo_exec_DrawTransformFeedbackStream(GLenum mode, GLuint name, GLuint stream) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_transform_feedback_object *obj = + _mesa_lookup_transform_feedback_object(ctx, name); + + if (MESA_VERBOSE & VERBOSE_DRAW) + _mesa_debug(ctx, "glDrawTransformFeedbackStream(%s, %u, %u)\n", + _mesa_lookup_enum_by_nr(mode), name, stream); + + vbo_draw_transform_feedback(ctx, mode, obj, stream, 1); +} + +static void GLAPIENTRY +vbo_exec_DrawTransformFeedbackInstanced(GLenum mode, GLuint name, + GLsizei primcount) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_transform_feedback_object *obj = + _mesa_lookup_transform_feedback_object(ctx, name); + + if (MESA_VERBOSE & VERBOSE_DRAW) + _mesa_debug(ctx, "glDrawTransformFeedbackInstanced(%s, %d)\n", + _mesa_lookup_enum_by_nr(mode), name); + + vbo_draw_transform_feedback(ctx, mode, obj, 0, primcount); +} + +static void GLAPIENTRY +vbo_exec_DrawTransformFeedbackStreamInstanced(GLenum mode, GLuint name, + GLuint stream, GLsizei primcount) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_transform_feedback_object *obj = + _mesa_lookup_transform_feedback_object(ctx, name); + + if (MESA_VERBOSE & VERBOSE_DRAW) + _mesa_debug(ctx, "glDrawTransformFeedbackStreamInstanced" + "(%s, %u, %u, %i)\n", + _mesa_lookup_enum_by_nr(mode), name, stream, primcount); + + vbo_draw_transform_feedback(ctx, mode, obj, stream, primcount); +} + +static void +vbo_validated_drawarraysindirect(struct gl_context *ctx, + GLenum mode, const GLvoid *indirect) +{ + struct vbo_context *vbo = vbo_context(ctx); + struct vbo_exec_context *exec = &vbo->exec; + struct _mesa_prim prim[1]; + + vbo_bind_arrays(ctx); + + memset(prim, 0, sizeof(prim)); + prim[0].begin = 1; + prim[0].end = 1; + prim[0].mode = mode; + prim[0].is_indirect = 1; + prim[0].indirect_offset = (GLsizeiptr)indirect; + + /* NOTE: We do NOT want to handle primitive restart here, nor perform any + * other checks that require knowledge of the values in the command buffer. + * That would defeat the whole purpose of this function. + */ + + check_buffers_are_unmapped(exec->array.inputs); + vbo->draw_prims(ctx, prim, 1, + NULL, GL_TRUE, 0, ~0, + NULL, + ctx->DrawIndirectBuffer); + + if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) + _mesa_flush(ctx); +} + +static void +vbo_validated_multidrawarraysindirect(struct gl_context *ctx, + GLenum mode, + const GLvoid *indirect, + GLsizei primcount, GLsizei stride) +{ + struct vbo_context *vbo = vbo_context(ctx); + struct vbo_exec_context *exec = &vbo->exec; + struct _mesa_prim *prim; + GLsizei i; + GLsizeiptr offset = (GLsizeiptr)indirect; + + if (primcount == 0) + return; + prim = calloc(primcount, sizeof(*prim)); + if (prim == NULL) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMultiDrawArraysIndirect"); + return; + } + + vbo_bind_arrays(ctx); + + prim[0].begin = 1; + prim[primcount - 1].end = 1; + for (i = 0; i < primcount; ++i, offset += stride) { + prim[i].mode = mode; + prim[i].indirect_offset = offset; + prim[i].is_indirect = 1; + } + + check_buffers_are_unmapped(exec->array.inputs); + vbo->draw_prims(ctx, prim, primcount, + NULL, GL_TRUE, 0, ~0, + NULL, + ctx->DrawIndirectBuffer); + + free(prim); + + if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) + _mesa_flush(ctx); +} + +static void +vbo_validated_drawelementsindirect(struct gl_context *ctx, + GLenum mode, GLenum type, + const GLvoid *indirect) +{ + struct vbo_context *vbo = vbo_context(ctx); + struct vbo_exec_context *exec = &vbo->exec; + struct _mesa_index_buffer ib; + struct _mesa_prim prim[1]; + + vbo_bind_arrays(ctx); + + ib.count = 0; /* unknown */ + ib.type = type; + ib.obj = ctx->Array.ArrayObj->ElementArrayBufferObj; + ib.ptr = NULL; + + memset(prim, 0, sizeof(prim)); + prim[0].begin = 1; + prim[0].end = 1; + prim[0].mode = mode; + prim[0].indexed = 1; + prim[0].indirect_offset = (GLsizeiptr)indirect; + prim[0].is_indirect = 1; + + check_buffers_are_unmapped(exec->array.inputs); + vbo->draw_prims(ctx, prim, 1, + &ib, GL_TRUE, 0, ~0, + NULL, + ctx->DrawIndirectBuffer); + + if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) + _mesa_flush(ctx); +} + +static void +vbo_validated_multidrawelementsindirect(struct gl_context *ctx, + GLenum mode, GLenum type, + const GLvoid *indirect, + GLsizei primcount, GLsizei stride) +{ + struct vbo_context *vbo = vbo_context(ctx); + struct vbo_exec_context *exec = &vbo->exec; + struct _mesa_index_buffer ib; + struct _mesa_prim *prim; + GLsizei i; + GLsizeiptr offset = (GLsizeiptr)indirect; + + if (primcount == 0) + return; + prim = calloc(primcount, sizeof(*prim)); + if (prim == NULL) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMultiDrawElementsIndirect"); + return; + } + + vbo_bind_arrays(ctx); + + /* NOTE: ElementArrayBufferObj is guaranteed to be a VBO. */ + + ib.count = 0; /* unknown */ + ib.type = type; + ib.obj = ctx->Array.ArrayObj->ElementArrayBufferObj; + ib.ptr = NULL; + + prim[0].begin = 1; + prim[primcount - 1].end = 1; + for (i = 0; i < primcount; ++i, offset += stride) { + prim[i].mode = mode; + prim[i].indexed = 1; + prim[i].indirect_offset = offset; + prim[i].is_indirect = 1; + } + + check_buffers_are_unmapped(exec->array.inputs); + vbo->draw_prims(ctx, prim, primcount, + &ib, GL_TRUE, 0, ~0, + NULL, + ctx->DrawIndirectBuffer); + + free(prim); + + if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) + _mesa_flush(ctx); +} + +/** + * Like [Multi]DrawArrays/Elements, but they take most arguments from + * a buffer object. + */ +static void GLAPIENTRY +vbo_exec_DrawArraysIndirect(GLenum mode, const GLvoid *indirect) +{ + GET_CURRENT_CONTEXT(ctx); + + if (MESA_VERBOSE & VERBOSE_DRAW) + _mesa_debug(ctx, "glDrawArraysIndirect(%s, %p)\n", + _mesa_lookup_enum_by_nr(mode), indirect); + + if (!_mesa_validate_DrawArraysIndirect(ctx, mode, indirect)) + return; + + vbo_validated_drawarraysindirect(ctx, mode, indirect); +} + +static void GLAPIENTRY +vbo_exec_DrawElementsIndirect(GLenum mode, GLenum type, + const GLvoid *indirect) { - exec->vtxfmt.DrawArrays = vbo_exec_DrawArrays; - exec->vtxfmt.DrawElements = vbo_exec_DrawElements; - exec->vtxfmt.DrawRangeElements = vbo_exec_DrawRangeElements; - exec->vtxfmt.MultiDrawElementsEXT = vbo_exec_MultiDrawElements; - exec->vtxfmt.DrawElementsBaseVertex = vbo_exec_DrawElementsBaseVertex; - exec->vtxfmt.DrawRangeElementsBaseVertex = vbo_exec_DrawRangeElementsBaseVertex; - exec->vtxfmt.MultiDrawElementsBaseVertex = vbo_exec_MultiDrawElementsBaseVertex; - exec->vtxfmt.DrawArraysInstanced = vbo_exec_DrawArraysInstanced; - exec->vtxfmt.DrawElementsInstanced = vbo_exec_DrawElementsInstanced; - exec->vtxfmt.DrawElementsInstancedBaseVertex = vbo_exec_DrawElementsInstancedBaseVertex; + GET_CURRENT_CONTEXT(ctx); + + if (MESA_VERBOSE & VERBOSE_DRAW) + _mesa_debug(ctx, "glDrawElementsIndirect(%s, %s, %p)\n", + _mesa_lookup_enum_by_nr(mode), + _mesa_lookup_enum_by_nr(type), indirect); + + if (!_mesa_validate_DrawElementsIndirect(ctx, mode, type, indirect)) + return; + + vbo_validated_drawelementsindirect(ctx, mode, type, indirect); +} + +static void GLAPIENTRY +vbo_exec_MultiDrawArraysIndirect(GLenum mode, + const GLvoid *indirect, + GLsizei primcount, GLsizei stride) +{ + GET_CURRENT_CONTEXT(ctx); + + if (MESA_VERBOSE & VERBOSE_DRAW) + _mesa_debug(ctx, "glMultiDrawArraysIndirect(%s, %p, %i, %i)\n", + _mesa_lookup_enum_by_nr(mode), indirect, primcount, stride); + + /* If is zero, the array elements are treated as tightly packed. */ + if (stride == 0) + stride = 4 * sizeof(GLuint); /* sizeof(DrawArraysIndirectCommand) */ + + if (!_mesa_validate_MultiDrawArraysIndirect(ctx, mode, + indirect, + primcount, stride)) + return; + + vbo_validated_multidrawarraysindirect(ctx, mode, + indirect, + primcount, stride); } +static void GLAPIENTRY +vbo_exec_MultiDrawElementsIndirect(GLenum mode, GLenum type, + const GLvoid *indirect, + GLsizei primcount, GLsizei stride) +{ + GET_CURRENT_CONTEXT(ctx); + + if (MESA_VERBOSE & VERBOSE_DRAW) + _mesa_debug(ctx, "glMultiDrawElementsIndirect(%s, %s, %p, %i, %i)\n", + _mesa_lookup_enum_by_nr(mode), + _mesa_lookup_enum_by_nr(type), indirect, primcount, stride); + + /* If is zero, the array elements are treated as tightly packed. */ + if (stride == 0) + stride = 5 * sizeof(GLuint); /* sizeof(DrawElementsIndirectCommand) */ + if (!_mesa_validate_MultiDrawElementsIndirect(ctx, mode, type, + indirect, + primcount, stride)) + return; + + vbo_validated_multidrawelementsindirect(ctx, mode, type, + indirect, + primcount, stride); +} + +/** + * Initialize the dispatch table with the VBO functions for drawing. + */ void -vbo_exec_array_destroy( struct vbo_exec_context *exec ) +vbo_initialize_exec_dispatch(const struct gl_context *ctx, + struct _glapi_table *exec) { - /* nothing to do */ + SET_DrawArrays(exec, vbo_exec_DrawArrays); + SET_DrawElements(exec, vbo_exec_DrawElements); + + if (_mesa_is_desktop_gl(ctx) || _mesa_is_gles3(ctx)) { + SET_DrawRangeElements(exec, vbo_exec_DrawRangeElements); + } + + SET_MultiDrawElementsEXT(exec, vbo_exec_MultiDrawElements); + + if (ctx->API == API_OPENGL_COMPAT) { + SET_Rectf(exec, vbo_exec_Rectf); + SET_EvalMesh1(exec, vbo_exec_EvalMesh1); + SET_EvalMesh2(exec, vbo_exec_EvalMesh2); + } + + if (_mesa_is_desktop_gl(ctx)) { + SET_DrawElementsBaseVertex(exec, vbo_exec_DrawElementsBaseVertex); + SET_DrawRangeElementsBaseVertex(exec, vbo_exec_DrawRangeElementsBaseVertex); + SET_MultiDrawElementsBaseVertex(exec, vbo_exec_MultiDrawElementsBaseVertex); + SET_DrawArraysInstancedBaseInstance(exec, vbo_exec_DrawArraysInstancedBaseInstance); + SET_DrawElementsInstancedBaseInstance(exec, vbo_exec_DrawElementsInstancedBaseInstance); + SET_DrawElementsInstancedBaseVertex(exec, vbo_exec_DrawElementsInstancedBaseVertex); + SET_DrawElementsInstancedBaseVertexBaseInstance(exec, vbo_exec_DrawElementsInstancedBaseVertexBaseInstance); + } + + if (ctx->API == API_OPENGL_CORE) { + SET_DrawArraysIndirect(exec, vbo_exec_DrawArraysIndirect); + SET_DrawElementsIndirect(exec, vbo_exec_DrawElementsIndirect); + SET_MultiDrawArraysIndirect(exec, vbo_exec_MultiDrawArraysIndirect); + SET_MultiDrawElementsIndirect(exec, vbo_exec_MultiDrawElementsIndirect); + } + + if (_mesa_is_desktop_gl(ctx) || _mesa_is_gles3(ctx)) { + SET_DrawArraysInstancedARB(exec, vbo_exec_DrawArraysInstanced); + SET_DrawElementsInstancedARB(exec, vbo_exec_DrawElementsInstanced); + } + + if (_mesa_is_desktop_gl(ctx)) { + SET_DrawTransformFeedback(exec, vbo_exec_DrawTransformFeedback); + SET_DrawTransformFeedbackStream(exec, vbo_exec_DrawTransformFeedbackStream); + SET_DrawTransformFeedbackInstanced(exec, vbo_exec_DrawTransformFeedbackInstanced); + SET_DrawTransformFeedbackStreamInstanced(exec, vbo_exec_DrawTransformFeedbackStreamInstanced); + } } @@ -1369,3 +1934,9 @@ _mesa_MultiDrawElementsBaseVertex(GLenum mode, vbo_exec_MultiDrawElementsBaseVertex(mode, count, type, indices, primcount, basevertex); } + +void GLAPIENTRY +_mesa_DrawTransformFeedback(GLenum mode, GLuint name) +{ + vbo_exec_DrawTransformFeedback(mode, name); +}