diff options
-rw-r--r-- | src/mesa/main/api_validate.c | 51 | ||||
-rw-r--r-- | src/mesa/main/mtypes.h | 11 | ||||
-rw-r--r-- | src/mesa/main/transformfeedback.c | 19 |
3 files changed, 80 insertions, 1 deletions
diff --git a/src/mesa/main/api_validate.c b/src/mesa/main/api_validate.c index 355a93c4c3d..16062820ef9 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 67eaadd9f0d..0c201d08f46 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 d9c6e514e8f..b2818caa591 100644 --- a/src/mesa/main/transformfeedback.c +++ b/src/mesa/main/transformfeedback.c @@ -285,6 +285,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; @@ -305,9 +306,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)"); @@ -333,6 +338,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); } |