[Mesa-dev] [PATCH v2 4/6] mesa/gles3: Generate error on draw call if transform feedback would overflow.

Paul Berry stereotype441 at gmail.com
Sat Dec 15 22:09:23 PST 2012


In desktop GL, if a draw call would cause transform feedback buffers
to overflow, the draw call should succeed, and the extra primitives
should simply not be recorded in the transform feedback buffers.

In GLES3, however, if a draw call would cause transform feedback
buffers to overflow, the draw call is supposed to produce an
INVALID_OPERATION error and no drawing should occur.

This patch implements the GLES3-required behaviour.

Fixes GLES3 conformance test "transform_feedback_overflow.test".

Reviewed-by: Ian Romanick <ian.d.romanick at intel.com>
---
 src/mesa/main/api_validate.c      | 51 +++++++++++++++++++++++++++++++++++++++
 src/mesa/main/mtypes.h            | 11 +++++++++
 src/mesa/main/transformfeedback.c | 19 ++++++++++++++-
 3 files changed, 80 insertions(+), 1 deletion(-)

diff --git a/src/mesa/main/api_validate.c b/src/mesa/main/api_validate.c
index 355a93c..1606282 100644
--- a/src/mesa/main/api_validate.c
+++ b/src/mesa/main/api_validate.c
@@ -516,6 +516,8 @@ GLboolean
 _mesa_validate_DrawArrays(struct gl_context *ctx,
 			  GLenum mode, GLint start, GLsizei count)
 {
+   struct gl_transform_feedback_object *xfb_obj
+      = ctx->TransformFeedback.CurrentObject;
    ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
    FLUSH_CURRENT(ctx, 0);
 
@@ -537,6 +539,29 @@ _mesa_validate_DrawArrays(struct gl_context *ctx,
          return GL_FALSE;
    }
 
+   /* From the GLES3 specification, section 2.14.2 (Transform Feedback
+    * Primitive Capture):
+    *
+    *   The error INVALID_OPERATION is generated by DrawArrays and
+    *   DrawArraysInstanced if recording the vertices of a primitive to the
+    *   buffer objects being used for transform feedback purposes would result
+    *   in either exceeding the limits of any buffer object’s size, or in
+    *   exceeding the end position offset + size − 1, as set by
+    *   BindBufferRange.
+    *
+    * This is in contrast to the behaviour of desktop GL, where the extra
+    * primitives are silently dropped from the transform feedback buffer.
+    */
+   if (_mesa_is_gles3(ctx) && xfb_obj->Active && !xfb_obj->Paused) {
+      size_t prim_count = vbo_count_tessellated_primitives(mode, count, 1);
+      if (xfb_obj->GlesRemainingPrims < prim_count) {
+         _mesa_error(ctx, GL_INVALID_OPERATION,
+                     "glDrawArrays(exceeds transform feedback size)");
+         return GL_FALSE;
+      }
+      xfb_obj->GlesRemainingPrims -= prim_count;
+   }
+
    return GL_TRUE;
 }
 
@@ -545,6 +570,8 @@ GLboolean
 _mesa_validate_DrawArraysInstanced(struct gl_context *ctx, GLenum mode, GLint first,
                                    GLsizei count, GLsizei numInstances)
 {
+   struct gl_transform_feedback_object *xfb_obj
+      = ctx->TransformFeedback.CurrentObject;
    ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
    FLUSH_CURRENT(ctx, 0);
 
@@ -580,6 +607,30 @@ _mesa_validate_DrawArraysInstanced(struct gl_context *ctx, GLenum mode, GLint fi
          return GL_FALSE;
    }
 
+   /* From the GLES3 specification, section 2.14.2 (Transform Feedback
+    * Primitive Capture):
+    *
+    *   The error INVALID_OPERATION is generated by DrawArrays and
+    *   DrawArraysInstanced if recording the vertices of a primitive to the
+    *   buffer objects being used for transform feedback purposes would result
+    *   in either exceeding the limits of any buffer object’s size, or in
+    *   exceeding the end position offset + size − 1, as set by
+    *   BindBufferRange.
+    *
+    * This is in contrast to the behaviour of desktop GL, where the extra
+    * primitives are silently dropped from the transform feedback buffer.
+    */
+   if (_mesa_is_gles3(ctx) && xfb_obj->Active && !xfb_obj->Paused) {
+      size_t prim_count
+         = vbo_count_tessellated_primitives(mode, count, numInstances);
+      if (xfb_obj->GlesRemainingPrims < prim_count) {
+         _mesa_error(ctx, GL_INVALID_OPERATION,
+                     "glDrawArraysInstanced(exceeds transform feedback size)");
+         return GL_FALSE;
+      }
+      xfb_obj->GlesRemainingPrims -= prim_count;
+   }
+
    return GL_TRUE;
 }
 
diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h
index b59498f..18ab2db 100644
--- a/src/mesa/main/mtypes.h
+++ b/src/mesa/main/mtypes.h
@@ -1808,6 +1808,17 @@ struct gl_transform_feedback_object
    GLboolean EndedAnytime; /**< Has EndTransformFeedback been called
                                 at least once? */
 
+   /**
+    * GLES: if Active is true, remaining number of primitives which can be
+    * rendered without overflow.  This is necessary to track because GLES
+    * requires us to generate INVALID_OPERATION if a call to glDrawArrays or
+    * glDrawArraysInstanced would overflow transform feedback buffers.
+    * Undefined if Active is false.
+    *
+    * Not tracked for desktop GL since it's unnecessary.
+    */
+   unsigned GlesRemainingPrims;
+
    /** The feedback buffers */
    GLuint BufferNames[MAX_FEEDBACK_BUFFERS];
    struct gl_buffer_object *Buffers[MAX_FEEDBACK_BUFFERS];
diff --git a/src/mesa/main/transformfeedback.c b/src/mesa/main/transformfeedback.c
index bf161bb..4782a6f 100644
--- a/src/mesa/main/transformfeedback.c
+++ b/src/mesa/main/transformfeedback.c
@@ -284,6 +284,7 @@ _mesa_BeginTransformFeedback(GLenum mode)
    struct gl_transform_feedback_object *obj;
    struct gl_transform_feedback_info *info;
    GLuint i;
+   unsigned vertices_per_prim;
    GET_CURRENT_CONTEXT(ctx);
 
    obj = ctx->TransformFeedback.CurrentObject;
@@ -304,9 +305,13 @@ _mesa_BeginTransformFeedback(GLenum mode)
 
    switch (mode) {
    case GL_POINTS:
+      vertices_per_prim = 1;
+      break;
    case GL_LINES:
+      vertices_per_prim = 2;
+      break;
    case GL_TRIANGLES:
-      /* legal */
+      vertices_per_prim = 3;
       break;
    default:
       _mesa_error(ctx, GL_INVALID_ENUM, "glBeginTransformFeedback(mode)");
@@ -332,6 +337,18 @@ _mesa_BeginTransformFeedback(GLenum mode)
    obj->Active = GL_TRUE;
    ctx->TransformFeedback.Mode = mode;
 
+   if (_mesa_is_gles3(ctx)) {
+      /* In GLES3, we are required to track the usage of the transform
+       * feedback buffer and report INVALID_OPERATION if a draw call tries to
+       * exceed it.  So compute the maximum number of vertices that we can
+       * write without overflowing any of the buffers currently being used for
+       * feedback.
+       */
+      unsigned max_vertices
+         = _mesa_compute_max_transform_feedback_vertices(obj, info);
+      obj->GlesRemainingPrims = max_vertices / vertices_per_prim;
+   }
+
    assert(ctx->Driver.BeginTransformFeedback);
    ctx->Driver.BeginTransformFeedback(ctx, mode, obj);
 }
-- 
1.8.0.2



More information about the mesa-dev mailing list