mesa: move glMultiDrawArrays to vbo and fix error handling
authorNicolai Hähnle <nicolai.haehnle@amd.com>
Fri, 7 Apr 2017 16:20:34 +0000 (18:20 +0200)
committerNicolai Hähnle <nicolai.haehnle@amd.com>
Wed, 19 Apr 2017 06:10:19 +0000 (08:10 +0200)
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>
src/mapi/glapi/gen/gl_API.xml
src/mesa/main/api_validate.c
src/mesa/main/api_validate.h
src/mesa/main/varray.c
src/mesa/vbo/vbo_exec_array.c
src/mesa/vbo/vbo_save_api.c

index c0ee2f20f14e53220c2410647bec78dd8a83a72f..522d2e5e80bf07f378df44a880ff0ba25bf88a84 100644 (file)
 </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 *"/>
index 2e1829bb13aa4e3ddba81183b103367fa80975ed..e23be60b2b45fbd1042822796b824c4d2a7054eb 100644 (file)
@@ -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,
index de520c98dcbb1f51d942eb25d70af219054effc8..93ec93d7bcbecfc3aada4d24b182e360b4c87314 100644 (file)
@@ -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,
index 233dc0dc4190d874a34da2fb62b181862b077836..205498501a3b27243a6ceb799dc58f930e8e1cce 100644 (file)
@@ -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,
index 30c52d5fa4fccfd4e0be4b22643a0e51d8743ca4..6858eb30b73dcd09fdfd9d491717a529ed340e8c 100644 (file)
@@ -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) {
index f8dab0cdaa728e7e08cb9fbbce6785023316baa5..ad54c3b38b35090435c44d0212179cc330d88ef3 100644 (file)
@@ -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);