From: Nicolai Hähnle <nicolai.haeh...@amd.com> When any count[i] is negative, we must skip all draws.
Moving to vbo makes the subsequent change easier. v2: - provide the function in all contexts, including GLES - adjust validation accordingly to include the xfb check --- src/mapi/glapi/gen/gl_API.xml | 2 +- src/mesa/main/api_validate.c | 54 +++++++++++++++++++++++++++++++++++++++++++ src/mesa/main/api_validate.h | 4 ++++ src/mesa/main/varray.c | 18 --------------- src/mesa/vbo/vbo_exec_array.c | 33 ++++++++++++++++++++++++++ src/mesa/vbo/vbo_save_api.c | 35 ++++++++++++++++++++++++++++ 6 files changed, 127 insertions(+), 19 deletions(-) diff --git a/src/mapi/glapi/gen/gl_API.xml b/src/mapi/glapi/gen/gl_API.xml index c0ee2f2..522d2e5 100644 --- a/src/mapi/glapi/gen/gl_API.xml +++ b/src/mapi/glapi/gen/gl_API.xml @@ -10212,21 +10212,21 @@ </function> </category> <category name="GL_EXT_texture_perturb_normal" number="147"> <function name="TextureNormalEXT" exec="skip"> <param name="mode" type="GLenum"/> </function> </category> <category name="GL_EXT_multi_draw_arrays" number="148"> - <function name="MultiDrawArraysEXT" es1="1.0" es2="2.0" alias="MultiDrawArrays"> + <function name="MultiDrawArraysEXT" es1="1.0" es2="2.0" exec="dynamic" alias="MultiDrawArrays"> <param name="mode" type="GLenum"/> <param name="first" type="const GLint *"/> <param name="count" type="const GLsizei *"/> <param name="primcount" type="GLsizei"/> </function> <function name="MultiDrawElementsEXT" es1="1.0" es2="2.0" exec="dynamic" marshal="draw" marshal_fail="_mesa_glthread_is_non_vbo_draw_elements(ctx)"> <param name="mode" type="GLenum"/> <param name="count" type="const GLsizei *"/> diff --git a/src/mesa/main/api_validate.c b/src/mesa/main/api_validate.c index 2e1829b..827b64a 100644 --- a/src/mesa/main/api_validate.c +++ b/src/mesa/main/api_validate.c @@ -914,20 +914,74 @@ _mesa_validate_DrawArraysInstanced(struct gl_context *ctx, GLenum mode, GLint fi if (numInstances < 0) _mesa_error(ctx, GL_INVALID_VALUE, "glDrawArraysInstanced(numInstances=%d)", numInstances); return GL_FALSE; } return validate_draw_arrays(ctx, "glDrawArraysInstanced", mode, count, 1); } +/** + * Called to error check the function parameters. + * + * Note that glMultiDrawArrays is not part of GLES, so there's limited scope + * for sharing code with the validation of glDrawArrays. + */ +bool +_mesa_validate_MultiDrawArrays(struct gl_context *ctx, GLenum mode, + const GLsizei *count, GLsizei primcount) +{ + int i; + + FLUSH_CURRENT(ctx, 0); + + if (!_mesa_valid_prim_mode(ctx, mode, "glMultiDrawArrays")) + return false; + + if (!check_valid_to_render(ctx, "glMultiDrawArrays")) + return false; + + if (primcount < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, "glMultiDrawArrays(primcount=%d)", + primcount); + return false; + } + + for (i = 0; i < primcount; ++i) { + if (count[i] < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, "glMultiDrawArrays(count[%d]=%d)", + i, count[i]); + return false; + } + } + + if (need_xfb_remaining_prims_check(ctx)) { + struct gl_transform_feedback_object *xfb_obj + = ctx->TransformFeedback.CurrentObject; + size_t prim_count = 0; + + for (i = 0; i < prim_count; ++i) + prim_count += vbo_count_tessellated_primitives(mode, count[i], 1); + + if (xfb_obj->GlesRemainingPrims < prim_count) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glMultiDrawArrays(exceeds transform feedback size)"); + return false; + } + xfb_obj->GlesRemainingPrims -= prim_count; + } + + return true; +} + + GLboolean _mesa_validate_DrawElementsInstanced(struct gl_context *ctx, GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei numInstances) { FLUSH_CURRENT(ctx, 0); if (numInstances < 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glDrawElementsInstanced(numInstances=%d)", numInstances); diff --git a/src/mesa/main/api_validate.h b/src/mesa/main/api_validate.h index de520c9..93ec93d 100644 --- a/src/mesa/main/api_validate.h +++ b/src/mesa/main/api_validate.h @@ -41,20 +41,24 @@ _mesa_valid_to_render(struct gl_context *ctx, const char *where); extern bool _mesa_is_valid_prim_mode(struct gl_context *ctx, GLenum mode); extern GLboolean _mesa_valid_prim_mode(struct gl_context *ctx, GLenum mode, const char *name); extern GLboolean _mesa_validate_DrawArrays(struct gl_context *ctx, GLenum mode, GLsizei count); +extern bool +_mesa_validate_MultiDrawArrays(struct gl_context *ctx, GLenum mode, + const GLsizei *count, GLsizei primcount); + extern GLboolean _mesa_validate_DrawElements(struct gl_context *ctx, GLenum mode, GLsizei count, GLenum type, const GLvoid *indices); extern GLboolean _mesa_validate_MultiDrawElements(struct gl_context *ctx, GLenum mode, const GLsizei *count, GLenum type, const GLvoid * const *indices, GLsizei primcount); diff --git a/src/mesa/main/varray.c b/src/mesa/main/varray.c index 233dc0d..2054985 100644 --- a/src/mesa/main/varray.c +++ b/src/mesa/main/varray.c @@ -1532,38 +1532,20 @@ _mesa_UnlockArraysEXT( void ) _mesa_error( ctx, GL_INVALID_OPERATION, "glUnlockArraysEXT(reexit)" ); return; } ctx->Array.LockFirst = 0; ctx->Array.LockCount = 0; ctx->NewState |= _NEW_ARRAY; } -/* GL_EXT_multi_draw_arrays */ -void GLAPIENTRY -_mesa_MultiDrawArrays( GLenum mode, const GLint *first, - const GLsizei *count, GLsizei primcount ) -{ - GET_CURRENT_CONTEXT(ctx); - GLint i; - - FLUSH_VERTICES(ctx, 0); - - for (i = 0; i < primcount; i++) { - if (count[i] > 0) { - CALL_DrawArrays(ctx->CurrentClientDispatch, (mode, first[i], count[i])); - } - } -} - - /* GL_IBM_multimode_draw_arrays */ void GLAPIENTRY _mesa_MultiModeDrawArraysIBM( const GLenum * mode, const GLint * first, const GLsizei * count, GLsizei primcount, GLint modestride ) { GET_CURRENT_CONTEXT(ctx); GLint i; FLUSH_VERTICES(ctx, 0); diff --git a/src/mesa/vbo/vbo_exec_array.c b/src/mesa/vbo/vbo_exec_array.c index 30c52d5..6858eb3 100644 --- a/src/mesa/vbo/vbo_exec_array.c +++ b/src/mesa/vbo/vbo_exec_array.c @@ -630,20 +630,52 @@ vbo_exec_DrawArraysInstancedBaseInstance(GLenum mode, GLint first, if (0) check_draw_arrays_data(ctx, first, count); vbo_draw_arrays(ctx, mode, first, count, numInstances, baseInstance); if (0) print_draw_arrays(ctx, mode, first, count); } +/** + * Called from glMultiDrawArrays when in immediate mode. + */ +static void GLAPIENTRY +vbo_exec_MultiDrawArrays(GLenum mode, const GLint *first, + const GLsizei *count, GLsizei primcount) +{ + GET_CURRENT_CONTEXT(ctx); + GLint i; + + if (MESA_VERBOSE & VERBOSE_DRAW) + _mesa_debug(ctx, + "glMultiDrawArrays(%s, %p, %p, %d)\n", + _mesa_enum_to_string(mode), first, count, primcount); + + if (!_mesa_validate_MultiDrawArrays(ctx, mode, count, primcount)) + return; + + for (i = 0; i < primcount; i++) { + if (count[i] > 0) { + if (0) + check_draw_arrays_data(ctx, first[i], count[i]); + + vbo_draw_arrays(ctx, mode, first[i], count[i], 1, 0); + + if (0) + print_draw_arrays(ctx, mode, first[i], count[i]); + } + } +} + + /** * Map GL_ELEMENT_ARRAY_BUFFER and print contents. * For debugging. */ #if 0 static void dump_element_buffer(struct gl_context *ctx, GLenum type) { const GLvoid *map = @@ -1634,20 +1666,21 @@ void vbo_initialize_exec_dispatch(const struct gl_context *ctx, struct _glapi_table *exec) { 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_MultiDrawArrays(exec, vbo_exec_MultiDrawArrays); 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 (ctx->API != API_OPENGLES && ctx->Extensions.ARB_draw_elements_base_vertex) { diff --git a/src/mesa/vbo/vbo_save_api.c b/src/mesa/vbo/vbo_save_api.c index f8dab0c..ad54c3b 100644 --- a/src/mesa/vbo/vbo_save_api.c +++ b/src/mesa/vbo/vbo_save_api.c @@ -1169,20 +1169,54 @@ _save_OBE_DrawArrays(GLenum mode, GLint start, GLsizei count) | VBO_SAVE_PRIM_NO_CURRENT_UPDATE)); for (i = 0; i < count; i++) CALL_ArrayElement(GET_DISPATCH(), (start + i)); CALL_End(GET_DISPATCH(), ()); _ae_unmap_vbos(ctx); } +static void GLAPIENTRY +_save_OBE_MultiDrawArrays(GLenum mode, const GLint *first, + const GLsizei *count, GLsizei primcount) +{ + GET_CURRENT_CONTEXT(ctx); + GLint i; + + if (!_mesa_is_valid_prim_mode(ctx, mode)) { + _mesa_compile_error(ctx, GL_INVALID_ENUM, "glMultiDrawArrays(mode)"); + return; + } + + if (primcount < 0) { + _mesa_compile_error(ctx, GL_INVALID_VALUE, + "glMultiDrawArrays(primcount<0)"); + return; + } + + for (i = 0; i < primcount; i++) { + if (count[i] < 0) { + _mesa_compile_error(ctx, GL_INVALID_VALUE, + "glMultiDrawArrays(count[i]<0)"); + return; + } + } + + for (i = 0; i < primcount; i++) { + if (count[i] > 0) { + _save_OBE_DrawArrays(mode, first[i], count[i]); + } + } +} + + /* Could do better by copying the arrays and element list intact and * then emitting an indexed prim at runtime. */ static void GLAPIENTRY _save_OBE_DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, const GLvoid * indices, GLint basevertex) { GET_CURRENT_CONTEXT(ctx); struct vbo_save_context *save = &vbo_context(ctx)->save; struct gl_buffer_object *indexbuf = ctx->Array.VAO->IndexBufferObj; @@ -1477,20 +1511,21 @@ _save_vtxfmt_init(struct gl_context *ctx) /** * Initialize the dispatch table with the VBO functions for display * list compilation. */ void vbo_initialize_save_dispatch(const struct gl_context *ctx, struct _glapi_table *exec) { SET_DrawArrays(exec, _save_OBE_DrawArrays); + SET_MultiDrawArrays(exec, _save_OBE_MultiDrawArrays); SET_DrawElements(exec, _save_OBE_DrawElements); SET_DrawElementsBaseVertex(exec, _save_OBE_DrawElementsBaseVertex); SET_DrawRangeElements(exec, _save_OBE_DrawRangeElements); SET_MultiDrawElementsEXT(exec, _save_OBE_MultiDrawElements); SET_MultiDrawElementsBaseVertex(exec, _save_OBE_MultiDrawElementsBaseVertex); SET_Rectf(exec, _save_OBE_Rectf); /* Note: other glDraw functins aren't compiled into display lists */ } -- 2.9.3 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev