aboutsummaryrefslogtreecommitdiff
path: root/mesalib/src/mesa/main/transformfeedback.c
diff options
context:
space:
mode:
Diffstat (limited to 'mesalib/src/mesa/main/transformfeedback.c')
-rw-r--r--mesalib/src/mesa/main/transformfeedback.c386
1 files changed, 327 insertions, 59 deletions
diff --git a/mesalib/src/mesa/main/transformfeedback.c b/mesalib/src/mesa/main/transformfeedback.c
index ce678c864..103011ce5 100644
--- a/mesalib/src/mesa/main/transformfeedback.c
+++ b/mesalib/src/mesa/main/transformfeedback.c
@@ -514,22 +514,24 @@ _mesa_EndTransformFeedback(void)
* Helper used by BindBufferRange() and BindBufferBase().
*/
static void
-bind_buffer_range(struct gl_context *ctx, GLuint index,
+bind_buffer_range(struct gl_context *ctx,
+ struct gl_transform_feedback_object *obj,
+ GLuint index,
struct gl_buffer_object *bufObj,
- GLintptr offset, GLsizeiptr size)
+ GLintptr offset, GLsizeiptr size,
+ bool dsa)
{
- struct gl_transform_feedback_object *obj =
- ctx->TransformFeedback.CurrentObject;
-
/* Note: no need to FLUSH_VERTICES or flag NewTransformFeedback, because
* transform feedback buffers can't be changed while transform feedback is
* active.
*/
- /* The general binding point */
- _mesa_reference_buffer_object(ctx,
- &ctx->TransformFeedback.CurrentBuffer,
- bufObj);
+ if (!dsa) {
+ /* The general binding point */
+ _mesa_reference_buffer_object(ctx,
+ &ctx->TransformFeedback.CurrentBuffer,
+ bufObj);
+ }
/* The per-attribute binding point */
_mesa_set_transform_feedback_binding(ctx, obj, index, bufObj, offset, size);
@@ -539,75 +541,209 @@ bind_buffer_range(struct gl_context *ctx, GLuint index,
/**
* Specify a buffer object to receive transform feedback results. Plus,
* specify the starting offset to place the results, and max size.
- * Called from the glBindBufferRange() function.
+ * Called from the glBindBufferRange() and glTransformFeedbackBufferRange
+ * functions.
*/
void
_mesa_bind_buffer_range_transform_feedback(struct gl_context *ctx,
- GLuint index,
- struct gl_buffer_object *bufObj,
- GLintptr offset,
- GLsizeiptr size)
+ struct gl_transform_feedback_object *obj,
+ GLuint index,
+ struct gl_buffer_object *bufObj,
+ GLintptr offset,
+ GLsizeiptr size,
+ bool dsa)
{
- struct gl_transform_feedback_object *obj;
+ const char *gl_methd_name;
+ if (dsa)
+ gl_methd_name = "glTransformFeedbackBufferRange";
+ else
+ gl_methd_name = "glBindBufferRange";
- obj = ctx->TransformFeedback.CurrentObject;
if (obj->Active) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glBindBufferRange(transform feedback active)");
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s(transform feedback active)",
+ gl_methd_name);
return;
}
if (index >= ctx->Const.MaxTransformFeedbackBuffers) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glBindBufferRange(index=%d)", index);
+ /* OpenGL 4.5 core profile, 6.1, pdf page 82: "An INVALID_VALUE error is
+ * generated if index is greater than or equal to the number of binding
+ * points for transform feedback, as described in section 6.7.1."
+ */
+ _mesa_error(ctx, GL_INVALID_VALUE, "%s(index=%d out of bounds)",
+ gl_methd_name, index);
return;
}
if (size & 0x3) {
- /* must a multiple of four */
- _mesa_error(ctx, GL_INVALID_VALUE, "glBindBufferRange(size=%d)", (int) size);
+ /* OpenGL 4.5 core profile, 6.7, pdf page 103: multiple of 4 */
+ _mesa_error(ctx, GL_INVALID_VALUE, "%s(size=%d must be a multiple of "
+ "four)", gl_methd_name, (int) size);
return;
}
if (offset & 0x3) {
- /* must be multiple of four */
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glBindBufferRange(offset=%d)", (int) offset);
+ /* OpenGL 4.5 core profile, 6.7, pdf page 103: multiple of 4 */
+ _mesa_error(ctx, GL_INVALID_VALUE, "%s(offset=%d must be a multiple "
+ "of four)", gl_methd_name, (int) offset);
return;
- }
+ }
+
+ if (offset < 0) {
+ /* OpenGL 4.5 core profile, 6.1, pdf page 82: "An INVALID_VALUE error is
+ * generated by BindBufferRange if offset is negative."
+ *
+ * OpenGL 4.5 core profile, 13.2, pdf page 445: "An INVALID_VALUE error
+ * is generated by TransformFeedbackBufferRange if offset is negative."
+ */
+ _mesa_error(ctx, GL_INVALID_VALUE, "%s(offset=%d must be >= 0)",
+ gl_methd_name,
+ (int) offset);
+ return;
+ }
- bind_buffer_range(ctx, index, bufObj, offset, size);
+ if (size <= 0 && (dsa || bufObj != ctx->Shared->NullBufferObj)) {
+ /* OpenGL 4.5 core profile, 6.1, pdf page 82: "An INVALID_VALUE error is
+ * generated by BindBufferRange if buffer is non-zero and size is less
+ * than or equal to zero."
+ *
+ * OpenGL 4.5 core profile, 13.2, pdf page 445: "An INVALID_VALUE error
+ * is generated by TransformFeedbackBufferRange if size is less than or
+ * equal to zero."
+ */
+ _mesa_error(ctx, GL_INVALID_VALUE, "%s(size=%d must be > 0)",
+ gl_methd_name, (int) size);
+ return;
+ }
+
+ bind_buffer_range(ctx, obj, index, bufObj, offset, size, dsa);
}
/**
* Specify a buffer object to receive transform feedback results.
* As above, but start at offset = 0.
- * Called from the glBindBufferBase() function.
+ * Called from the glBindBufferBase() and glTransformFeedbackBufferBase()
+ * functions.
*/
void
_mesa_bind_buffer_base_transform_feedback(struct gl_context *ctx,
- GLuint index,
- struct gl_buffer_object *bufObj)
+ struct gl_transform_feedback_object *obj,
+ GLuint index,
+ struct gl_buffer_object *bufObj,
+ bool dsa)
{
- struct gl_transform_feedback_object *obj;
-
- obj = ctx->TransformFeedback.CurrentObject;
-
if (obj->Active) {
_mesa_error(ctx, GL_INVALID_OPERATION,
- "glBindBufferBase(transform feedback active)");
+ "%s(transform feedback active)",
+ dsa ? "glTransformFeedbackBufferBase" : "glBindBufferBase");
return;
}
if (index >= ctx->Const.MaxTransformFeedbackBuffers) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glBindBufferBase(index=%d)", index);
+ _mesa_error(ctx, GL_INVALID_VALUE, "%s(index=%d out of bounds)",
+ dsa ? "glTransformFeedbackBufferBase" : "glBindBufferBase",
+ index);
+ return;
+ }
+
+ bind_buffer_range(ctx, obj, index, bufObj, 0, 0, dsa);
+}
+
+/**
+ * Wrapper around lookup_transform_feedback_object that throws
+ * GL_INVALID_OPERATION if id is not in the hash table. After calling
+ * _mesa_error, it returns NULL.
+ */
+static struct gl_transform_feedback_object *
+lookup_transform_feedback_object_err(struct gl_context *ctx,
+ GLuint xfb, const char* func)
+{
+ struct gl_transform_feedback_object *obj;
+
+ obj = _mesa_lookup_transform_feedback_object(ctx, xfb);
+ if (!obj) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "%s(xfb=%u: non-generated object name)", func, xfb);
+ }
+
+ return obj;
+}
+
+/**
+ * Wrapper around _mesa_lookup_bufferobj that throws GL_INVALID_VALUE if id
+ * is not in the hash table. Specialised version for the
+ * transform-feedback-related functions. After calling _mesa_error, it
+ * returns NULL.
+ */
+static struct gl_buffer_object *
+lookup_transform_feedback_bufferobj_err(struct gl_context *ctx,
+ GLuint buffer, const char* func)
+{
+ struct gl_buffer_object *bufObj;
+
+ /* OpenGL 4.5 core profile, 13.2, pdf page 444: buffer must be zero or the
+ * name of an existing buffer object.
+ */
+ if (buffer == 0) {
+ bufObj = ctx->Shared->NullBufferObj;
+ } else {
+ bufObj = _mesa_lookup_bufferobj(ctx, buffer);
+ if (!bufObj) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "%s(invalid buffer=%u)", func,
+ buffer);
+ }
+ }
+
+ return bufObj;
+}
+
+void GLAPIENTRY
+_mesa_TransformFeedbackBufferBase(GLuint xfb, GLuint index, GLuint buffer)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct gl_transform_feedback_object *obj;
+ struct gl_buffer_object *bufObj;
+
+ obj = lookup_transform_feedback_object_err(ctx, xfb,
+ "glTransformFeedbackBufferBase");
+ if(!obj) {
+ return;
+ }
+
+ bufObj = lookup_transform_feedback_bufferobj_err(ctx, buffer,
+ "glTransformFeedbackBufferBase");
+ if(!bufObj) {
return;
}
- bind_buffer_range(ctx, index, bufObj, 0, 0);
+ _mesa_bind_buffer_base_transform_feedback(ctx, obj, index, bufObj, true);
}
+void GLAPIENTRY
+_mesa_TransformFeedbackBufferRange(GLuint xfb, GLuint index, GLuint buffer,
+ GLintptr offset, GLsizeiptr size)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct gl_transform_feedback_object *obj;
+ struct gl_buffer_object *bufObj;
+
+ obj = lookup_transform_feedback_object_err(ctx, xfb,
+ "glTransformFeedbackBufferRange");
+ if(!obj) {
+ return;
+ }
+
+ bufObj = lookup_transform_feedback_bufferobj_err(ctx, buffer,
+ "glTransformFeedbackBufferRange");
+ if(!bufObj) {
+ return;
+ }
+
+ _mesa_bind_buffer_range_transform_feedback(ctx, obj, index, bufObj, offset,
+ size, true);
+}
/**
* Specify a buffer object to receive transform feedback results, plus the
@@ -660,7 +796,7 @@ _mesa_BindBufferOffsetEXT(GLenum target, GLuint index, GLuint buffer,
return;
}
- bind_buffer_range(ctx, index, bufObj, offset, 0);
+ bind_buffer_range(ctx, obj, index, bufObj, offset, 0, false);
}
@@ -784,7 +920,7 @@ _mesa_GetTransformFeedbackVarying(GLuint program, GLuint index,
GLsizei *size, GLenum *type, GLchar *name)
{
const struct gl_shader_program *shProg;
- const struct gl_transform_feedback_info *linked_xfb_info;
+ struct gl_program_resource *res;
GET_CURRENT_CONTEXT(ctx);
shProg = _mesa_lookup_shader_program(ctx, program);
@@ -794,22 +930,27 @@ _mesa_GetTransformFeedbackVarying(GLuint program, GLuint index,
return;
}
- linked_xfb_info = &shProg->LinkedTransformFeedback;
- if (index >= (GLuint) linked_xfb_info->NumVarying) {
+ res = _mesa_program_resource_find_index((struct gl_shader_program *) shProg,
+ GL_TRANSFORM_FEEDBACK_VARYING,
+ index);
+ if (!res) {
_mesa_error(ctx, GL_INVALID_VALUE,
"glGetTransformFeedbackVarying(index=%u)", index);
return;
}
/* return the varying's name and length */
- _mesa_copy_string(name, bufSize, length,
- linked_xfb_info->Varyings[index].Name);
+ _mesa_copy_string(name, bufSize, length, _mesa_program_resource_name(res));
/* return the datatype and value's size (in datatype units) */
if (type)
- *type = linked_xfb_info->Varyings[index].Type;
+ _mesa_program_resource_prop((struct gl_shader_program *) shProg,
+ res, index, GL_TYPE, (GLint*) type,
+ "glGetTransformFeedbackVarying");
if (size)
- *size = linked_xfb_info->Varyings[index].Size;
+ _mesa_program_resource_prop((struct gl_shader_program *) shProg,
+ res, index, GL_ARRAY_SIZE, (GLint*) size,
+ "glGetTransformFeedbackVarying");
}
@@ -817,6 +958,10 @@ _mesa_GetTransformFeedbackVarying(GLuint program, GLuint index,
struct gl_transform_feedback_object *
_mesa_lookup_transform_feedback_object(struct gl_context *ctx, GLuint name)
{
+ /* OpenGL 4.5 core profile, 13.2 pdf page 444: "xfb must be zero, indicating
+ * the default transform feedback object, or the name of an existing
+ * transform feedback object."
+ */
if (name == 0) {
return ctx->TransformFeedback.DefaultObject;
}
@@ -825,25 +970,24 @@ _mesa_lookup_transform_feedback_object(struct gl_context *ctx, GLuint name)
_mesa_HashLookup(ctx->TransformFeedback.Objects, name);
}
-
-/**
- * Create new transform feedback objects. Transform feedback objects
- * encapsulate the state related to transform feedback to allow quickly
- * switching state (and drawing the results, below).
- * Part of GL_ARB_transform_feedback2.
- */
-void GLAPIENTRY
-_mesa_GenTransformFeedbacks(GLsizei n, GLuint *names)
+static void
+create_transform_feedbacks(struct gl_context *ctx, GLsizei n, GLuint *ids,
+ bool dsa)
{
GLuint first;
- GET_CURRENT_CONTEXT(ctx);
+ const char* func;
+
+ if (dsa)
+ func = "glCreateTransformFeedbacks";
+ else
+ func = "glGenTransformFeedbacks";
if (n < 0) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glGenTransformFeedbacks(n < 0)");
+ _mesa_error(ctx, GL_INVALID_VALUE, "%s(n < 0)", func);
return;
}
- if (!names)
+ if (!ids)
return;
/* we don't need contiguous IDs, but this might be faster */
@@ -854,18 +998,56 @@ _mesa_GenTransformFeedbacks(GLsizei n, GLuint *names)
struct gl_transform_feedback_object *obj
= ctx->Driver.NewTransformFeedback(ctx, first + i);
if (!obj) {
- _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenTransformFeedbacks");
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", func);
return;
}
- names[i] = first + i;
+ ids[i] = first + i;
_mesa_HashInsert(ctx->TransformFeedback.Objects, first + i, obj);
+ if (dsa) {
+ /* this is normally done at bind time in the non-dsa case */
+ obj->EverBound = GL_TRUE;
+ }
}
}
else {
- _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenTransformFeedbacks");
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", func);
}
}
+/**
+ * Create new transform feedback objects. Transform feedback objects
+ * encapsulate the state related to transform feedback to allow quickly
+ * switching state (and drawing the results, below).
+ * Part of GL_ARB_transform_feedback2.
+ */
+void GLAPIENTRY
+_mesa_GenTransformFeedbacks(GLsizei n, GLuint *names)
+{
+ GET_CURRENT_CONTEXT(ctx);
+
+ /* GenTransformFeedbacks should just reserve the object names that a
+ * subsequent call to BindTransformFeedback should actively create. For
+ * the sake of simplicity, we reserve the names and create the objects
+ * straight away.
+ */
+
+ create_transform_feedbacks(ctx, n, names, false);
+}
+
+/**
+ * Create new transform feedback objects. Transform feedback objects
+ * encapsulate the state related to transform feedback to allow quickly
+ * switching state (and drawing the results, below).
+ * Part of GL_ARB_direct_state_access.
+ */
+void GLAPIENTRY
+_mesa_CreateTransformFeedbacks(GLsizei n, GLuint *names)
+{
+ GET_CURRENT_CONTEXT(ctx);
+
+ create_transform_feedbacks(ctx, n, names, true);
+}
+
/**
* Is the given ID a transform feedback object?
@@ -1026,3 +1208,89 @@ _mesa_ResumeTransformFeedback(void)
assert(ctx->Driver.ResumeTransformFeedback);
ctx->Driver.ResumeTransformFeedback(ctx, obj);
}
+
+extern void GLAPIENTRY
+_mesa_GetTransformFeedbackiv(GLuint xfb, GLenum pname, GLint *param)
+{
+ struct gl_transform_feedback_object *obj;
+ GET_CURRENT_CONTEXT(ctx);
+
+ obj = lookup_transform_feedback_object_err(ctx, xfb,
+ "glGetTransformFeedbackiv");
+ if(!obj) {
+ return;
+ }
+
+ switch(pname) {
+ case GL_TRANSFORM_FEEDBACK_PAUSED:
+ *param = obj->Paused;
+ break;
+ case GL_TRANSFORM_FEEDBACK_ACTIVE:
+ *param = obj->Active;
+ break;
+ default:
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glGetTransformFeedbackiv(pname=%i)", pname);
+ }
+}
+
+extern void GLAPIENTRY
+_mesa_GetTransformFeedbacki_v(GLuint xfb, GLenum pname, GLuint index,
+ GLint *param)
+{
+ struct gl_transform_feedback_object *obj;
+ GET_CURRENT_CONTEXT(ctx);
+
+ obj = lookup_transform_feedback_object_err(ctx, xfb,
+ "glGetTransformFeedbacki_v");
+ if(!obj) {
+ return;
+ }
+
+ if (index >= ctx->Const.MaxTransformFeedbackBuffers) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glGetTransformFeedbacki_v(index=%i)", index);
+ return;
+ }
+
+ switch(pname) {
+ case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING:
+ *param = obj->BufferNames[index];
+ break;
+ default:
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glGetTransformFeedbacki_v(pname=%i)", pname);
+ }
+}
+
+extern void GLAPIENTRY
+_mesa_GetTransformFeedbacki64_v(GLuint xfb, GLenum pname, GLuint index,
+ GLint64 *param)
+{
+ struct gl_transform_feedback_object *obj;
+ GET_CURRENT_CONTEXT(ctx);
+
+ obj = lookup_transform_feedback_object_err(ctx, xfb,
+ "glGetTransformFeedbacki64_v");
+ if(!obj) {
+ return;
+ }
+
+ if (index >= ctx->Const.MaxTransformFeedbackBuffers) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glGetTransformFeedbacki64_v(index=%i)", index);
+ return;
+ }
+
+ switch(pname) {
+ case GL_TRANSFORM_FEEDBACK_BUFFER_START:
+ *param = obj->Offset[index];
+ break;
+ case GL_TRANSFORM_FEEDBACK_BUFFER_SIZE:
+ *param = obj->RequestedSize[index];
+ break;
+ default:
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glGetTransformFeedbacki64_v(pname=%i)", pname);
+ }
+}