#include "transformfeedback.h"
#include "shaderapi.h"
#include "shaderobj.h"
-#include "main/dispatch.h"
+#include "program/program.h"
#include "program/prog_parameter.h"
struct using_program_tuple
obj->EverBound = GL_FALSE;
}
+/**
+ * Delete a transform feedback object. Called via
+ * ctx->Driver->DeleteTransformFeedback, if not overwritten by driver. In
+ * the latter case, called from the driver after all driver-specific clean-up
+ * has been done.
+ *
+ * \param ctx GL context to wich transform feedback object belongs.
+ * \param obj Transform feedback object due to be deleted.
+ */
+void
+_mesa_delete_transform_feedback_object(struct gl_context *ctx,
+ struct gl_transform_feedback_object
+ *obj)
+{
+ for (unsigned i = 0; i < ARRAY_SIZE(obj->Buffers); i++) {
+ _mesa_reference_buffer_object(ctx, &obj->Buffers[i], NULL);
+ }
+
+ free(obj->Label);
+ free(obj);
+}
/** Default fallback for ctx->Driver.NewTransformFeedback() */
static struct gl_transform_feedback_object *
return obj;
}
-/** Default fallback for ctx->Driver.DeleteTransformFeedback() */
-static void
-delete_transform_feedback_fallback(struct gl_context *ctx,
- struct gl_transform_feedback_object *obj)
-{
- GLuint i;
-
- for (i = 0; i < ARRAY_SIZE(obj->Buffers); i++) {
- _mesa_reference_buffer_object(ctx, &obj->Buffers[i], NULL);
- }
-
- free(obj->Label);
- free(obj);
-}
-
-
/** Default fallback for ctx->Driver.BeginTransformFeedback() */
static void
begin_transform_feedback_fallback(struct gl_context *ctx, GLenum mode,
_mesa_init_transform_feedback_functions(struct dd_function_table *driver)
{
driver->NewTransformFeedback = new_transform_feedback_fallback;
- driver->DeleteTransformFeedback = delete_transform_feedback_fallback;
+ driver->DeleteTransformFeedback = _mesa_delete_transform_feedback_object;
driver->BeginTransformFeedback = begin_transform_feedback_fallback;
driver->EndTransformFeedback = end_transform_feedback_fallback;
driver->PauseTransformFeedback = pause_transform_feedback_fallback;
/* Skip any inactive buffers, which have a stride of 0. */
if (stride == 0)
- continue;
+ continue;
max_for_this_buffer = obj->Size[i] / (4 * stride);
max_index = MIN2(max_index, max_for_this_buffer);
if (obj->program != source) {
ctx->NewDriverState |= ctx->DriverFlags.NewTransformFeedbackProg;
+ _mesa_reference_program_(ctx, &obj->program, source);
obj->program = source;
}
assert(ctx->Driver.EndTransformFeedback);
ctx->Driver.EndTransformFeedback(ctx, obj);
+ _mesa_reference_program_(ctx, &obj->program, NULL);
ctx->TransformFeedback.CurrentObject->Active = GL_FALSE;
ctx->TransformFeedback.CurrentObject->Paused = GL_FALSE;
ctx->TransformFeedback.CurrentObject->EndedAnytime = GL_TRUE;
_mesa_error(ctx, GL_INVALID_VALUE, "%s(size=%d must be a multiple of "
"four)", gl_methd_name, (int) size);
return false;
- }
+ }
if (offset & 0x3) {
/* OpenGL 4.5 core profile, 6.7, pdf page 103: multiple of 4 */
obj = lookup_transform_feedback_object_err(ctx, xfb,
"glTransformFeedbackBufferBase");
- if(!obj) {
+ if (!obj) {
return;
}
bufObj = lookup_transform_feedback_bufferobj_err(ctx, buffer,
"glTransformFeedbackBufferBase");
- if(!bufObj) {
+ if (!bufObj) {
return;
}
obj = lookup_transform_feedback_object_err(ctx, xfb,
"glTransformFeedbackBufferRange");
- if(!obj) {
+ if (!obj) {
return;
}
bufObj = lookup_transform_feedback_bufferobj_err(ctx, buffer,
"glTransformFeedbackBufferRange");
- if(!bufObj) {
+ if (!bufObj) {
return;
}
* offset in the buffer to start placing results.
* This function is part of GL_EXT_transform_feedback, but not GL3.
*/
+static ALWAYS_INLINE void
+bind_buffer_offset(struct gl_context *ctx,
+ struct gl_transform_feedback_object *obj, GLuint index,
+ GLuint buffer, GLintptr offset, bool no_error)
+{
+ struct gl_buffer_object *bufObj;
+
+ if (buffer == 0) {
+ bufObj = ctx->Shared->NullBufferObj;
+ } else {
+ bufObj = _mesa_lookup_bufferobj(ctx, buffer);
+ if (!no_error && !bufObj) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glBindBufferOffsetEXT(invalid buffer=%u)", buffer);
+ return;
+ }
+ }
+
+ _mesa_bind_buffer_range_xfb(ctx, obj, index, bufObj, offset, 0);
+}
+
+
+void GLAPIENTRY
+_mesa_BindBufferOffsetEXT_no_error(GLenum target, GLuint index, GLuint buffer,
+ GLintptr offset)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ bind_buffer_offset(ctx, ctx->TransformFeedback.CurrentObject, index, buffer,
+ offset, true);
+}
+
+
void GLAPIENTRY
_mesa_BindBufferOffsetEXT(GLenum target, GLuint index, GLuint buffer,
GLintptr offset)
{
struct gl_transform_feedback_object *obj;
- struct gl_buffer_object *bufObj;
GET_CURRENT_CONTEXT(ctx);
if (target != GL_TRANSFORM_FEEDBACK_BUFFER) {
return;
}
- if (buffer == 0) {
- bufObj = ctx->Shared->NullBufferObj;
- } else {
- bufObj = _mesa_lookup_bufferobj(ctx, buffer);
- if (!bufObj) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glBindBufferOffsetEXT(invalid buffer=%u)", buffer);
- return;
- }
- }
-
- _mesa_bind_buffer_range_xfb(ctx, obj, index, bufObj, offset, 0);
+ bind_buffer_offset(ctx, obj, index, buffer, offset, false);
}
* This function specifies the transform feedback outputs to be written
* to the feedback buffer(s), and in what order.
*/
+static ALWAYS_INLINE void
+transform_feedback_varyings(struct gl_context *ctx,
+ struct gl_shader_program *shProg, GLsizei count,
+ const GLchar *const *varyings, GLenum bufferMode)
+{
+ GLint i;
+
+ /* free existing varyings, if any */
+ for (i = 0; i < (GLint) shProg->TransformFeedback.NumVarying; i++) {
+ free(shProg->TransformFeedback.VaryingNames[i]);
+ }
+ free(shProg->TransformFeedback.VaryingNames);
+
+ /* allocate new memory for varying names */
+ shProg->TransformFeedback.VaryingNames =
+ malloc(count * sizeof(GLchar *));
+
+ if (!shProg->TransformFeedback.VaryingNames) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTransformFeedbackVaryings()");
+ return;
+ }
+
+ /* Save the new names and the count */
+ for (i = 0; i < count; i++) {
+ shProg->TransformFeedback.VaryingNames[i] = strdup(varyings[i]);
+ }
+ shProg->TransformFeedback.NumVarying = count;
+
+ shProg->TransformFeedback.BufferMode = bufferMode;
+
+ /* No need to invoke FLUSH_VERTICES or flag NewTransformFeedback since
+ * the varyings won't be used until shader link time.
+ */
+}
+
+
+void GLAPIENTRY
+_mesa_TransformFeedbackVaryings_no_error(GLuint program, GLsizei count,
+ const GLchar *const *varyings,
+ GLenum bufferMode)
+{
+ GET_CURRENT_CONTEXT(ctx);
+
+ struct gl_shader_program *shProg = _mesa_lookup_shader_program(ctx, program);
+ transform_feedback_varyings(ctx, shProg, count, varyings, bufferMode);
+}
+
void GLAPIENTRY
_mesa_TransformFeedbackVaryings(GLuint program, GLsizei count,
const GLchar * const *varyings,
}
}
- /* free existing varyings, if any */
- for (i = 0; i < (GLint) shProg->TransformFeedback.NumVarying; i++) {
- free(shProg->TransformFeedback.VaryingNames[i]);
- }
- free(shProg->TransformFeedback.VaryingNames);
-
- /* allocate new memory for varying names */
- shProg->TransformFeedback.VaryingNames =
- malloc(count * sizeof(GLchar *));
-
- if (!shProg->TransformFeedback.VaryingNames) {
- _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTransformFeedbackVaryings()");
- return;
- }
-
- /* Save the new names and the count */
- for (i = 0; i < count; i++) {
- shProg->TransformFeedback.VaryingNames[i] = strdup(varyings[i]);
- }
- shProg->TransformFeedback.NumVarying = count;
-
- shProg->TransformFeedback.BufferMode = bufferMode;
-
- /* No need to invoke FLUSH_VERTICES or flag NewTransformFeedback since
- * the varyings won't be used until shader link time.
- */
+ transform_feedback_varyings(ctx, shProg, count, varyings, bufferMode);
}
obj = lookup_transform_feedback_object_err(ctx, xfb,
"glGetTransformFeedbackiv");
- if(!obj) {
+ if (!obj) {
return;
}
obj = lookup_transform_feedback_object_err(ctx, xfb,
"glGetTransformFeedbacki_v");
- if(!obj) {
+ if (!obj) {
return;
}
obj = lookup_transform_feedback_object_err(ctx, xfb,
"glGetTransformFeedbacki64_v");
- if(!obj) {
+ if (!obj) {
return;
}
return;
}
+ /**
+ * This follows the same general rules used for BindBufferBase:
+ *
+ * "To query the starting offset or size of the range of a buffer
+ * object binding in an indexed array, call GetInteger64i_v with
+ * target set to respectively the starting offset or binding size
+ * name from table 6.5 for that array. Index must be in the range
+ * zero to the number of bind points supported minus one. If the
+ * starting offset or size was not specified when the buffer object
+ * was bound (e.g. if it was bound with BindBufferBase), or if no
+ * buffer object is bound to the target array at index, zero is
+ * returned."
+ */
+ if (obj->RequestedSize[index] == 0 &&
+ (pname == GL_TRANSFORM_FEEDBACK_BUFFER_START ||
+ pname == GL_TRANSFORM_FEEDBACK_BUFFER_SIZE)) {
+ *param = 0;
+ return;
+ }
+
compute_transform_feedback_buffer_sizes(obj);
switch(pname) {
case GL_TRANSFORM_FEEDBACK_BUFFER_START:
+ assert(obj->RequestedSize[index] > 0);
*param = obj->Offset[index];
break;
case GL_TRANSFORM_FEEDBACK_BUFFER_SIZE:
+ assert(obj->RequestedSize[index] > 0);
*param = obj->Size[index];
break;
default: