[Mesa-dev] [PATCH 10/14] mesa/vbo: move some Draw checks out of validation

Timothy Arceri tarceri at itsqueeze.com
Tue Apr 18 00:09:49 UTC 2017


These checks do not generate any errors. Move them so we can add
KHR_no_error support and still make sure we do these checks.

Reviewed-by: Nicolai Hähnle <nicolai.haehnle at amd.com>
---
 src/mesa/main/api_validate.c  |  43 +----------------
 src/mesa/vbo/vbo_exec_array.c | 106 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 108 insertions(+), 41 deletions(-)

diff --git a/src/mesa/main/api_validate.c b/src/mesa/main/api_validate.c
index af4f7cb..843cdf6 100644
--- a/src/mesa/main/api_validate.c
+++ b/src/mesa/main/api_validate.c
@@ -283,68 +283,37 @@ check_valid_to_render(struct gl_context *ctx, const char *function)
        *  transfers vertices to the GL if the current program state has
        *  one but not both of a tessellation control shader and tessellation
        *  evaluation shader."
        */
       if (_mesa_is_gles3(ctx) &&
           ctx->TessEvalProgram._Current && !ctx->TessCtrlProgram._Current) {
          _mesa_error(ctx, GL_INVALID_OPERATION,
                      "%s(tess ctrl shader is missing)", function);
          return false;
       }
-
-      /* For ES2, we can draw if we have a vertex program/shader). */
-      return ctx->VertexProgram._Current != NULL;
-
-   case API_OPENGLES:
-      /* For OpenGL ES, only draw if we have vertex positions
-       */
-      if (!ctx->Array.VAO->VertexAttrib[VERT_ATTRIB_POS].Enabled)
-         return false;
       break;
 
    case API_OPENGL_CORE:
       /* Section 10.4 (Drawing Commands Using Vertex Arrays) of the OpenGL 4.5
        * Core Profile spec says:
        *
        *     "An INVALID_OPERATION error is generated if no vertex array
        *     object is bound (see section 10.3.1)."
        */
       if (ctx->Array.VAO == ctx->Array.DefaultVAO) {
          _mesa_error(ctx, GL_INVALID_OPERATION, "%s(no VAO bound)", function);
          return false;
       }
+      break;
 
-      /* Section 7.3 (Program Objects) of the OpenGL 4.5 Core Profile spec
-       * says:
-       *
-       *     "If there is no active program for the vertex or fragment shader
-       *     stages, the results of vertex and/or fragment processing will be
-       *     undefined. However, this is not an error."
-       *
-       * The fragment shader is not tested here because other state (e.g.,
-       * GL_RASTERIZER_DISCARD) affects whether or not we actually care.
-       */
-      return ctx->VertexProgram._Current != NULL;
-
+   case API_OPENGLES:
    case API_OPENGL_COMPAT:
-      if (ctx->VertexProgram._Current != NULL) {
-         /* Draw regardless of whether or not we have any vertex arrays.
-          * (Ex: could draw a point using a constant vertex pos)
-          */
-         return true;
-      } else {
-         /* Draw if we have vertex positions (GL_VERTEX_ARRAY or generic
-          * array [0]).
-          */
-         return (ctx->Array.VAO->VertexAttrib[VERT_ATTRIB_POS].Enabled ||
-                 ctx->Array.VAO->VertexAttrib[VERT_ATTRIB_GENERIC0].Enabled);
-      }
       break;
 
    default:
       unreachable("Invalid API value in check_valid_to_render()");
    }
 
    return true;
 }
 
 
@@ -693,28 +662,20 @@ validate_DrawElements_common(struct gl_context *ctx,
    if (!_mesa_valid_prim_mode(ctx, mode, caller)) {
       return false;
    }
 
    if (!valid_elements_type(ctx, type, caller))
       return false;
 
    if (!check_valid_to_render(ctx, caller))
       return false;
 
-   /* Not using a VBO for indices, so avoid NULL pointer derefs later.
-    */
-   if (!_mesa_is_bufferobj(ctx->Array.VAO->IndexBufferObj) && indices == NULL)
-      return false;
-
-   if (count == 0)
-      return false;
-
    return true;
 }
 
 /**
  * Error checking for glDrawElements().  Includes parameter checking
  * and VBO bounds checking.
  * \return GL_TRUE if OK to render, GL_FALSE if error found
  */
 GLboolean
 _mesa_validate_DrawElements(struct gl_context *ctx,
diff --git a/src/mesa/vbo/vbo_exec_array.c b/src/mesa/vbo/vbo_exec_array.c
index 30c52d5..9452c65 100644
--- a/src/mesa/vbo/vbo_exec_array.c
+++ b/src/mesa/vbo/vbo_exec_array.c
@@ -173,20 +173,74 @@ check_draw_elements_data(struct gl_context *ctx, GLsizei count,
  * Check array data, looking for NaNs, etc.
  */
 static void
 check_draw_arrays_data(struct gl_context *ctx, GLint start, GLsizei count)
 {
    /* TO DO */
 }
 
 
 /**
+ * Check if we should skip the draw call even after validation was successful.
+ */
+static bool
+skip_validated_draw(struct gl_context *ctx)
+{
+   switch (ctx->API) {
+   case API_OPENGLES2:
+      /* For ES2, we can draw if we have a vertex program/shader). */
+      return ctx->VertexProgram._Current == NULL;
+
+   case API_OPENGLES:
+      /* For OpenGL ES, only draw if we have vertex positions
+       */
+      if (ctx->Array.VAO->VertexAttrib[VERT_ATTRIB_POS].Enabled)
+         return false;
+      break;
+
+   case API_OPENGL_CORE:
+      /* Section 7.3 (Program Objects) of the OpenGL 4.5 Core Profile spec
+       * says:
+       *
+       *     "If there is no active program for the vertex or fragment shader
+       *     stages, the results of vertex and/or fragment processing will be
+       *     undefined. However, this is not an error."
+       *
+       * The fragment shader is not tested here because other state (e.g.,
+       * GL_RASTERIZER_DISCARD) affects whether or not we actually care.
+       */
+      return ctx->VertexProgram._Current == NULL;
+
+   case API_OPENGL_COMPAT:
+      if (ctx->VertexProgram._Current != NULL) {
+         /* Draw regardless of whether or not we have any vertex arrays.
+          * (Ex: could draw a point using a constant vertex pos)
+          */
+         return false;
+      } else {
+         /* Draw if we have vertex positions (GL_VERTEX_ARRAY or generic
+          * array [0]).
+          */
+         return (!ctx->Array.VAO->VertexAttrib[VERT_ATTRIB_POS].Enabled &&
+                 !ctx->Array.VAO->VertexAttrib[VERT_ATTRIB_GENERIC0].Enabled);
+      }
+      break;
+
+   default:
+      unreachable("Invalid API value in check_valid_to_render()");
+   }
+
+   return false;
+}
+
+
+/**
  * Print info/data for glDrawArrays(), for debugging.
  */
 static void
 print_draw_arrays(struct gl_context *ctx,
                   GLenum mode, GLint start, GLsizei count)
 {
    const struct gl_vertex_array_object *vao = ctx->Array.VAO;
 
    printf("vbo_exec_DrawArrays(mode 0x%x, start %d, count %d):\n",
           mode, start, count);
@@ -402,20 +456,23 @@ vbo_bind_arrays(struct gl_context *ctx)
  * arrays.  If primitive restart is enabled, it typically means
  * splitting one DrawArrays() into two.
  */
 static void
 vbo_draw_arrays(struct gl_context *ctx, GLenum mode, GLint start,
                 GLsizei count, GLuint numInstances, GLuint baseInstance)
 {
    struct vbo_context *vbo = vbo_context(ctx);
    struct _mesa_prim prim[2];
 
+   if (skip_validated_draw(ctx))
+      return;
+
    vbo_bind_arrays(ctx);
 
    /* OpenGL 4.5 says that primitive restart is ignored with non-indexed
     * draws.
     */
    memset(prim, 0, sizeof(prim));
    prim[0].begin = 1;
    prim[0].end = 1;
    prim[0].mode = mode;
    prim[0].num_instances = numInstances;
@@ -691,38 +748,60 @@ dump_element_buffer(struct gl_context *ctx, GLenum type)
       break;
    default:
       ;
    }
 
    ctx->Driver.UnmapBuffer(ctx, ctx->Array.VAO->IndexBufferObj, MAP_INTERNAL);
 }
 #endif
 
 
+static bool
+skip_draw_elements(struct gl_context *ctx, GLsizei count,
+                   const GLvoid *indices)
+{
+   if (count == 0)
+      return true;
+
+   /* Not using a VBO for indices, so avoid NULL pointer derefs later.
+    */
+   if (!_mesa_is_bufferobj(ctx->Array.VAO->IndexBufferObj) && indices == NULL)
+      return true;
+
+   if (skip_validated_draw(ctx))
+      return true;
+
+   return false;
+}
+
+
 /**
  * Inner support for both _mesa_DrawElements and _mesa_DrawRangeElements.
  * Do the rendering for a glDrawElements or glDrawRangeElements call after
  * we've validated buffer bounds, etc.
  */
 static void
 vbo_validated_drawrangeelements(struct gl_context *ctx, GLenum mode,
                                 GLboolean index_bounds_valid,
                                 GLuint start, GLuint end,
                                 GLsizei count, GLenum type,
                                 const GLvoid * indices,
                                 GLint basevertex, GLuint numInstances,
                                 GLuint baseInstance)
 {
    struct vbo_context *vbo = vbo_context(ctx);
    struct _mesa_index_buffer ib;
    struct _mesa_prim prim[1];
 
+   if (skip_draw_elements(ctx, count, indices))
+      return;
+
    vbo_bind_arrays(ctx);
 
    ib.count = count;
    ib.type = type;
    ib.obj = ctx->Array.VAO->IndexBufferObj;
    ib.ptr = indices;
 
    prim[0].begin = 1;
    prim[0].end = 1;
    prim[0].weak = 0;
@@ -1182,38 +1261,44 @@ static void GLAPIENTRY
 vbo_exec_MultiDrawElements(GLenum mode,
                            const GLsizei *count, GLenum type,
                            const GLvoid * const *indices, GLsizei primcount)
 {
    GET_CURRENT_CONTEXT(ctx);
 
    if (!_mesa_validate_MultiDrawElements(ctx, mode, count, type, indices,
                                          primcount))
       return;
 
+   if (skip_validated_draw(ctx))
+      return;
+
    vbo_validated_multidrawelements(ctx, mode, count, type, indices, primcount,
                                    NULL);
 }
 
 
 static void GLAPIENTRY
 vbo_exec_MultiDrawElementsBaseVertex(GLenum mode,
                                      const GLsizei *count, GLenum type,
                                      const GLvoid * const *indices,
                                      GLsizei primcount,
                                      const GLsizei *basevertex)
 {
    GET_CURRENT_CONTEXT(ctx);
 
    if (!_mesa_validate_MultiDrawElements(ctx, mode, count, type, indices,
                                          primcount))
       return;
 
+   if (skip_validated_draw(ctx))
+      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)
 {
@@ -1227,20 +1312,23 @@ vbo_draw_transform_feedback(struct gl_context *ctx, GLenum mode,
 
    if (ctx->Driver.GetTransformFeedbackVertexCount &&
        (ctx->Const.AlwaysUseGetTransformFeedbackVertexCount ||
         !_mesa_all_varyings_in_vbos(ctx->Array.VAO))) {
       GLsizei n =
          ctx->Driver.GetTransformFeedbackVertexCount(ctx, obj, stream);
       vbo_draw_arrays(ctx, mode, 0, n, numInstances, 0);
       return;
    }
 
+   if (skip_validated_draw(ctx))
+      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;
@@ -1434,37 +1522,43 @@ 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_enum_to_string(mode), indirect);
 
    if (!_mesa_validate_DrawArraysIndirect(ctx, mode, indirect))
       return;
 
+   if (skip_validated_draw(ctx))
+      return;
+
    vbo_validated_drawarraysindirect(ctx, mode, indirect);
 }
 
 
 static void GLAPIENTRY
 vbo_exec_DrawElementsIndirect(GLenum mode, GLenum type, const GLvoid *indirect)
 {
    GET_CURRENT_CONTEXT(ctx);
 
    if (MESA_VERBOSE & VERBOSE_DRAW)
       _mesa_debug(ctx, "glDrawElementsIndirect(%s, %s, %p)\n",
                   _mesa_enum_to_string(mode),
                   _mesa_enum_to_string(type), indirect);
 
    if (!_mesa_validate_DrawElementsIndirect(ctx, mode, type, indirect))
       return;
 
+   if (skip_validated_draw(ctx))
+      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);
 
@@ -1473,20 +1567,23 @@ vbo_exec_MultiDrawArraysIndirect(GLenum mode, const GLvoid *indirect,
                   _mesa_enum_to_string(mode), indirect, primcount, stride);
 
    /* If <stride> 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;
 
+   if (skip_validated_draw(ctx))
+      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)
 {
@@ -1498,20 +1595,23 @@ vbo_exec_MultiDrawElementsIndirect(GLenum mode, GLenum type,
                   _mesa_enum_to_string(type), indirect, primcount, stride);
 
    /* If <stride> 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;
 
+   if (skip_validated_draw(ctx))
+      return;
+
    vbo_validated_multidrawelementsindirect(ctx, mode, type, indirect,
                                            primcount, stride);
 }
 
 
 static void
 vbo_validated_multidrawarraysindirectcount(struct gl_context *ctx,
                                            GLenum mode,
                                            GLintptr indirect,
                                            GLintptr drawcount,
@@ -1586,20 +1686,23 @@ vbo_exec_MultiDrawArraysIndirectCount(GLenum mode, GLintptr indirect,
 
    /* If <stride> is zero, the array elements are treated as tightly packed. */
    if (stride == 0)
       stride = 4 * sizeof(GLuint);      /* sizeof(DrawArraysIndirectCommand) */
 
    if (!_mesa_validate_MultiDrawArraysIndirectCount(ctx, mode,
                                                     indirect, drawcount,
                                                     maxdrawcount, stride))
       return;
 
+   if (skip_validated_draw(ctx))
+      return;
+
    vbo_validated_multidrawarraysindirectcount(ctx, mode, indirect, drawcount,
                                               maxdrawcount, stride);
 }
 
 
 static void GLAPIENTRY
 vbo_exec_MultiDrawElementsIndirectCount(GLenum mode, GLenum type,
                                         GLintptr indirect, GLintptr drawcount,
                                         GLsizei maxdrawcount, GLsizei stride)
 {
@@ -1614,20 +1717,23 @@ vbo_exec_MultiDrawElementsIndirectCount(GLenum mode, GLenum type,
 
    /* If <stride> is zero, the array elements are treated as tightly packed. */
    if (stride == 0)
       stride = 5 * sizeof(GLuint);      /* sizeof(DrawElementsIndirectCommand) */
 
    if (!_mesa_validate_MultiDrawElementsIndirectCount(ctx, mode, type,
                                                       indirect, drawcount,
                                                       maxdrawcount, stride))
       return;
 
+   if (skip_validated_draw(ctx))
+      return;
+
    vbo_validated_multidrawelementsindirectcount(ctx, mode, type, indirect,
                                                 drawcount, maxdrawcount,
                                                 stride);
 }
 
 
 /**
  * Initialize the dispatch table with the VBO functions for drawing.
  */
 void
-- 
2.9.3



More information about the mesa-dev mailing list