#include "main/dispatch.h"
#include "main/enums.h"
#include "main/hash.h"
+#include "main/hash_table.h"
#include "main/mtypes.h"
#include "main/shaderapi.h"
#include "main/shaderobj.h"
link_program(struct gl_context *ctx, GLuint program)
{
struct gl_shader_program *shProg;
- struct gl_transform_feedback_object *obj =
- ctx->TransformFeedback.CurrentObject;
shProg = _mesa_lookup_shader_program_err(ctx, program, "glLinkProgram");
if (!shProg)
return;
- if (obj->Active
- && (shProg == ctx->Shader.CurrentVertexProgram
- || shProg == ctx->Shader.CurrentGeometryProgram
- || shProg == ctx->Shader.CurrentFragmentProgram)) {
+ /* From the ARB_transform_feedback2 specification:
+ * "The error INVALID_OPERATION is generated by LinkProgram if <program> is
+ * the name of a program being used by one or more transform feedback
+ * objects, even if the objects are not currently bound or are paused."
+ */
+ if (_mesa_transform_feedback_is_using_program(ctx, shProg)) {
_mesa_error(ctx, GL_INVALID_OPERATION,
- "glLinkProgram(transform feedback active)");
+ "glLinkProgram(transform feedback is using the program)");
return;
}
#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.
!ctx->TransformFeedback.CurrentObject->Paused;
}
+extern bool
+_mesa_transform_feedback_is_using_program(struct gl_context *ctx,
+ struct gl_shader_program *shProg);
+
#endif /* TRANSFORM_FEEDBACK_H */