/*
- * Vertex transform feedback support.
+ * Transform feedback support.
*
* Authors:
* Brian Paul
#include "buffers.h"
-#include "bufferobj.h"
#include "context.h"
#include "hash.h"
#include "macros.h"
#include "program/prog_parameter.h"
+struct using_program_tuple
+{
+ struct gl_shader_program *shProg;
+ bool found;
+};
+
+static void
+active_xfb_object_references_program(GLuint key, void *data, void *user_data)
+{
+ struct using_program_tuple *callback_data = user_data;
+ struct gl_transform_feedback_object *obj = data;
+ if (obj->Active && obj->shader_program == callback_data->shProg)
+ callback_data->found = true;
+}
+
+/**
+ * Return true if any active transform feedback object is using a program.
+ */
+bool
+_mesa_transform_feedback_is_using_program(struct gl_context *ctx,
+ struct gl_shader_program *shProg)
+{
+ struct using_program_tuple callback_data;
+ callback_data.shProg = shProg;
+ callback_data.found = false;
+
+ _mesa_HashWalk(ctx->TransformFeedback.Objects,
+ active_xfb_object_references_program, &callback_data);
+
+ /* Also check DefaultObject, as it's not in the Objects hash table. */
+ active_xfb_object_references_program(0, ctx->TransformFeedback.DefaultObject,
+ &callback_data);
+
+ return callback_data.found;
+}
/**
* Do reference counting of transform feedback buffers.
}
+/** Initialize the fields of a gl_transform_feedback_object. */
+void
+_mesa_init_transform_feedback_object(struct gl_transform_feedback_object *obj,
+ GLuint name)
+{
+ if (!obj)
+ return;
+
+ obj->Name = name;
+ obj->RefCount = 1;
+ obj->EverBound = GL_FALSE;
+}
+
+
/** Default fallback for ctx->Driver.NewTransformFeedback() */
static struct gl_transform_feedback_object *
new_transform_feedback(struct gl_context *ctx, GLuint name)
{
struct gl_transform_feedback_object *obj;
obj = CALLOC_STRUCT(gl_transform_feedback_object);
- if (obj) {
- obj->Name = name;
- obj->RefCount = 1;
- obj->EverBound = GL_FALSE;
- }
+ _mesa_init_transform_feedback_object(obj, name);
return obj;
}
**/
+/**
+ * Figure out which stage of the pipeline is the source of transform feedback
+ * data given the current context state, and return its gl_shader_program.
+ *
+ * If no active program can generate transform feedback data (i.e. no vertex
+ * shader is active), returns NULL.
+ */
+static struct gl_shader_program *
+get_xfb_source(struct gl_context *ctx)
+{
+ int i;
+ for (i = MESA_SHADER_GEOMETRY; i >= MESA_SHADER_VERTEX; i--) {
+ if (ctx->_Shader->CurrentProgram[i] != NULL)
+ return ctx->_Shader->CurrentProgram[i];
+ }
+ return NULL;
+}
+
+
void GLAPIENTRY
_mesa_BeginTransformFeedback(GLenum mode)
{
struct gl_transform_feedback_object *obj;
- struct gl_transform_feedback_info *info;
+ struct gl_transform_feedback_info *info = NULL;
+ struct gl_shader_program *source;
GLuint i;
unsigned vertices_per_prim;
GET_CURRENT_CONTEXT(ctx);
obj = ctx->TransformFeedback.CurrentObject;
- if (ctx->Shader.CurrentVertexProgram == NULL) {
+ /* Figure out what pipeline stage is the source of data for transform
+ * feedback.
+ */
+ source = get_xfb_source(ctx);
+ if (source == NULL) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"glBeginTransformFeedback(no program active)");
return;
}
- info = &ctx->Shader.CurrentVertexProgram->LinkedTransformFeedback;
+ info = &source->LinkedTransformFeedback;
if (info->NumOutputs == 0) {
_mesa_error(ctx, GL_INVALID_OPERATION,
obj->GlesRemainingPrims = max_vertices / vertices_per_prim;
}
- obj->shader_program = ctx->Shader.CurrentVertexProgram;
+ if (obj->shader_program != source) {
+ ctx->NewDriverState |= ctx->DriverFlags.NewTransformFeedbackProg;
+ obj->shader_program = source;
+ }
assert(ctx->Driver.BeginTransformFeedback);
ctx->Driver.BeginTransformFeedback(ctx, mode, obj);
bufObj);
/* The per-attribute binding point */
- _mesa_reference_buffer_object(ctx,
- &obj->Buffers[index],
- bufObj);
-
- obj->BufferNames[index] = bufObj->Name;
-
- obj->Offset[index] = offset;
- obj->RequestedSize[index] = size;
+ _mesa_set_transform_feedback_binding(ctx, obj, index, bufObj, offset, size);
}
/**
- * Specify a buffer object to receive vertex shader results. Plus,
+ * 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.
*/
/**
- * Specify a buffer object to receive vertex shader results.
+ * Specify a buffer object to receive transform feedback results.
* As above, but start at offset = 0.
* Called from the glBindBufferBase() function.
*/
/**
- * Specify a buffer object to receive vertex shader results, plus the
+ * Specify a buffer object to receive transform feedback results, plus the
* offset in the buffer to start placing results.
* This function is part of GL_EXT_transform_feedback, but not GL3.
*/
/**
- * This function specifies the vertex shader outputs to be written
+ * This function specifies the transform feedback outputs to be written
* to the feedback buffer(s), and in what order.
*/
void GLAPIENTRY
/**
- * Get info about the vertex shader's outputs which are to be written
+ * Get info about the transform feedback outputs which are to be written
* to the feedback buffer(s).
*/
void GLAPIENTRY
* the program object being used by the current transform feedback object
* is not active."
*/
- if (obj->shader_program != ctx->Shader.CurrentVertexProgram) {
+ if (obj->shader_program != get_xfb_source(ctx)) {
_mesa_error(ctx, GL_INVALID_OPERATION,
- "glResumeTransformFeedback(wrong vertex program bound)");
+ "glResumeTransformFeedback(wrong program bound)");
return;
}