_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);
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;
}
_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);
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;
}
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];
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;
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)");
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);
}