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 v3: - fix mix-up of pre- and post-xfb prim count (Nils Wallménius) Cc: mesa-stable@lists.freedesktop.org Reviewed-by: Timothy Arceri <tarceri@itsqueeze.com> Reviewed-by: Marek Olšák <marek.olsak@amd.com>tags/17.2-branchpoint
| @@ -10219,7 +10219,7 @@ | |||
| </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 *"/> | |||
| @@ -921,6 +921,60 @@ _mesa_validate_DrawArraysInstanced(struct gl_context *ctx, GLenum mode, GLint fi | |||
| } | |||
| /** | |||
| * 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 xfb_prim_count = 0; | |||
| for (i = 0; i < primcount; ++i) | |||
| xfb_prim_count += vbo_count_tessellated_primitives(mode, count[i], 1); | |||
| if (xfb_obj->GlesRemainingPrims < xfb_prim_count) { | |||
| _mesa_error(ctx, GL_INVALID_OPERATION, | |||
| "glMultiDrawArrays(exceeds transform feedback size)"); | |||
| return false; | |||
| } | |||
| xfb_obj->GlesRemainingPrims -= xfb_prim_count; | |||
| } | |||
| return true; | |||
| } | |||
| GLboolean | |||
| _mesa_validate_DrawElementsInstanced(struct gl_context *ctx, | |||
| GLenum mode, GLsizei count, GLenum type, | |||
| @@ -48,6 +48,10 @@ _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, | |||
| @@ -1539,24 +1539,6 @@ _mesa_UnlockArraysEXT( void ) | |||
| } | |||
| /* 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, | |||
| @@ -637,6 +637,38 @@ vbo_exec_DrawArraysInstancedBaseInstance(GLenum mode, GLint first, | |||
| } | |||
| /** | |||
| * 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. | |||
| @@ -1641,6 +1673,7 @@ vbo_initialize_exec_dispatch(const struct gl_context *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) { | |||
| @@ -1176,6 +1176,40 @@ _save_OBE_DrawArrays(GLenum mode, GLint start, GLsizei count) | |||
| } | |||
| 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. | |||
| */ | |||
| @@ -1484,6 +1518,7 @@ 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); | |||