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

Ian Romanick idr at freedesktop.org
Fri Dec 14 17:31:02 PST 2012


On 12/14/2012 01:01 PM, Paul Berry wrote:
> 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".
> ---
>   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;

I'm kind of going back and forth about Gles in this name.  meh.

> +
>      /** 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 415b0aa..7d500bc 100644
> --- a/src/mesa/main/transformfeedback.c
> +++ b/src/mesa/main/transformfeedback.c
> @@ -283,6 +283,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;
> @@ -303,9 +304,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)");
> @@ -331,6 +336,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);
>   }
>



More information about the mesa-dev mailing list