[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