#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
{
- struct gl_shader_program *shProg;
+ struct gl_program *prog;
bool found;
};
{
struct using_program_tuple *callback_data = user_data;
struct gl_transform_feedback_object *obj = data;
- if (obj->Active && obj->shader_program == callback_data->shProg)
+ if (obj->Active && obj->program == callback_data->prog)
callback_data->found = true;
}
_mesa_transform_feedback_is_using_program(struct gl_context *ctx,
struct gl_shader_program *shProg)
{
+ if (!shProg->last_vert_prog)
+ return false;
+
struct using_program_tuple callback_data;
- callback_data.shProg = shProg;
callback_data.found = false;
+ callback_data.prog = shProg->last_vert_prog;
- _mesa_HashWalk(ctx->TransformFeedback.Objects,
- active_xfb_object_references_program, &callback_data);
+ _mesa_HashWalkLocked(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,
assert(!*ptr);
if (obj) {
+ assert(obj->RefCount > 0);
+
/* reference new object */
- if (obj->RefCount == 0) {
- _mesa_problem(NULL, "referencing deleted transform feedback object");
- *ptr = NULL;
- }
- else {
- obj->RefCount++;
- obj->EverBound = GL_TRUE;
- *ptr = obj;
- }
+ obj->RefCount++;
+ obj->EverBound = GL_TRUE;
+ *ptr = obj;
}
}
-/**
- * Check that all the buffer objects currently bound for transform
- * feedback actually exist. Raise a GL_INVALID_OPERATION error if
- * any buffers are missing.
- * \return GL_TRUE for success, GL_FALSE if error
- */
-GLboolean
-_mesa_validate_transform_feedback_buffers(struct gl_context *ctx)
-{
- /* XXX to do */
- return GL_TRUE;
-}
-
-
-
/**
* Per-context init for transform feedback.
*/
ctx->TransformFeedback.Objects = _mesa_NewHashTable();
_mesa_reference_buffer_object(ctx,
- &ctx->TransformFeedback.CurrentBuffer,
- ctx->Shared->NullBufferObj);
+ &ctx->TransformFeedback.CurrentBuffer, NULL);
}
_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;
}
+/**
+ * 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 *
-new_transform_feedback(struct gl_context *ctx, GLuint name)
+new_transform_feedback_fallback(struct gl_context *ctx, GLuint name)
{
struct gl_transform_feedback_object *obj;
+
obj = CALLOC_STRUCT(gl_transform_feedback_object);
+ if (!obj)
+ return NULL;
+
_mesa_init_transform_feedback_object(obj, name);
return obj;
}
-/** Default fallback for ctx->Driver.DeleteTransformFeedback() */
-static void
-delete_transform_feedback(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(struct gl_context *ctx, GLenum mode,
- struct gl_transform_feedback_object *obj)
+begin_transform_feedback_fallback(struct gl_context *ctx, GLenum mode,
+ struct gl_transform_feedback_object *obj)
{
/* nop */
}
/** Default fallback for ctx->Driver.EndTransformFeedback() */
static void
-end_transform_feedback(struct gl_context *ctx,
- struct gl_transform_feedback_object *obj)
+end_transform_feedback_fallback(struct gl_context *ctx,
+ struct gl_transform_feedback_object *obj)
{
/* nop */
}
/** Default fallback for ctx->Driver.PauseTransformFeedback() */
static void
-pause_transform_feedback(struct gl_context *ctx,
- struct gl_transform_feedback_object *obj)
+pause_transform_feedback_fallback(struct gl_context *ctx,
+ struct gl_transform_feedback_object *obj)
{
/* nop */
}
/** Default fallback for ctx->Driver.ResumeTransformFeedback() */
static void
-resume_transform_feedback(struct gl_context *ctx,
- struct gl_transform_feedback_object *obj)
+resume_transform_feedback_fallback(struct gl_context *ctx,
+ struct gl_transform_feedback_object *obj)
{
/* nop */
}
void
_mesa_init_transform_feedback_functions(struct dd_function_table *driver)
{
- driver->NewTransformFeedback = new_transform_feedback;
- driver->DeleteTransformFeedback = delete_transform_feedback;
- driver->BeginTransformFeedback = begin_transform_feedback;
- driver->EndTransformFeedback = end_transform_feedback;
- driver->PauseTransformFeedback = pause_transform_feedback;
- driver->ResumeTransformFeedback = resume_transform_feedback;
+ driver->NewTransformFeedback = new_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;
+ driver->ResumeTransformFeedback = resume_transform_feedback_fallback;
}
* enabled transform feedback buffers without overflowing any of them.
*/
unsigned
-_mesa_compute_max_transform_feedback_vertices(
+_mesa_compute_max_transform_feedback_vertices(struct gl_context *ctx,
const struct gl_transform_feedback_object *obj,
const struct gl_transform_feedback_info *info)
{
unsigned max_index = 0xffffffff;
unsigned i;
- for (i = 0; i < info->NumBuffers; ++i) {
- unsigned stride = info->BufferStride[i];
- unsigned max_for_this_buffer;
+ for (i = 0; i < ctx->Const.MaxTransformFeedbackBuffers; i++) {
+ if ((info->ActiveBuffers >> i) & 1) {
+ unsigned stride = info->Buffers[i].Stride;
+ unsigned max_for_this_buffer;
- /* Skip any inactive buffers, which have a stride of 0. */
- if (stride == 0)
- continue;
+ /* Skip any inactive buffers, which have a stride of 0. */
+ if (stride == 0)
+ continue;
- max_for_this_buffer = obj->Size[i] / (4 * stride);
- max_index = MIN2(max_index, max_for_this_buffer);
+ max_for_this_buffer = obj->Size[i] / (4 * stride);
+ max_index = MIN2(max_index, max_for_this_buffer);
+ }
}
return max_index;
/**
* 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.
+ * data given the current context state, and return its gl_program.
*
* If no active program can generate transform feedback data (i.e. no vertex
* shader is active), returns NULL.
*/
-static struct gl_shader_program *
+static struct gl_program *
get_xfb_source(struct gl_context *ctx)
{
int i;
}
-void GLAPIENTRY
-_mesa_BeginTransformFeedback(GLenum mode)
+static ALWAYS_INLINE void
+begin_transform_feedback(struct gl_context *ctx, GLenum mode, bool no_error)
{
struct gl_transform_feedback_object *obj;
struct gl_transform_feedback_info *info = NULL;
- struct gl_shader_program *source;
+ struct gl_program *source;
GLuint i;
unsigned vertices_per_prim;
- GET_CURRENT_CONTEXT(ctx);
obj = ctx->TransformFeedback.CurrentObject;
* feedback.
*/
source = get_xfb_source(ctx);
- if (source == NULL) {
+ if (!no_error && source == NULL) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"glBeginTransformFeedback(no program active)");
return;
}
- info = &source->LinkedTransformFeedback;
+ info = source->sh.LinkedTransformFeedback;
- if (info->NumOutputs == 0) {
+ if (!no_error && info->NumOutputs == 0) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"glBeginTransformFeedback(no varyings to record)");
return;
vertices_per_prim = 3;
break;
default:
- _mesa_error(ctx, GL_INVALID_ENUM, "glBeginTransformFeedback(mode)");
- return;
- }
-
- if (obj->Active) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glBeginTransformFeedback(already active)");
- return;
+ if (!no_error) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glBeginTransformFeedback(mode)");
+ return;
+ } else {
+ /* Stop compiler warnings */
+ unreachable("Error in API use when using KHR_no_error");
+ }
}
- for (i = 0; i < info->NumBuffers; ++i) {
- if (obj->BufferNames[i] == 0) {
+ if (!no_error) {
+ if (obj->Active) {
_mesa_error(ctx, GL_INVALID_OPERATION,
- "glBeginTransformFeedback(binding point %d does not have "
- "a buffer object bound)", i);
+ "glBeginTransformFeedback(already active)");
return;
}
+
+ for (i = 0; i < ctx->Const.MaxTransformFeedbackBuffers; i++) {
+ if ((info->ActiveBuffers >> i) & 1) {
+ if (obj->BufferNames[i] == 0) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glBeginTransformFeedback(binding point %d does not "
+ "have a buffer object bound)", i);
+ return;
+ }
+ }
+ }
}
FLUSH_VERTICES(ctx, 0);
* feedback.
*/
unsigned max_vertices
- = _mesa_compute_max_transform_feedback_vertices(obj, info);
+ = _mesa_compute_max_transform_feedback_vertices(ctx, obj, info);
obj->GlesRemainingPrims = max_vertices / vertices_per_prim;
}
- if (obj->shader_program != source) {
+ if (obj->program != source) {
ctx->NewDriverState |= ctx->DriverFlags.NewTransformFeedbackProg;
- obj->shader_program = source;
+ _mesa_reference_program_(ctx, &obj->program, source);
+ obj->program = source;
}
assert(ctx->Driver.BeginTransformFeedback);
}
+void GLAPIENTRY
+_mesa_BeginTransformFeedback_no_error(GLenum mode)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ begin_transform_feedback(ctx, mode, true);
+}
+
+
+void GLAPIENTRY
+_mesa_BeginTransformFeedback(GLenum mode)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ begin_transform_feedback(ctx, mode, false);
+}
+
+
+static void
+end_transform_feedback(struct gl_context *ctx,
+ struct gl_transform_feedback_object *obj)
+{
+ FLUSH_VERTICES(ctx, 0);
+ ctx->NewDriverState |= ctx->DriverFlags.NewTransformFeedback;
+
+ 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;
+}
+
+
+void GLAPIENTRY
+_mesa_EndTransformFeedback_no_error(void)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ end_transform_feedback(ctx, ctx->TransformFeedback.CurrentObject);
+}
+
+
void GLAPIENTRY
_mesa_EndTransformFeedback(void)
{
return;
}
- FLUSH_VERTICES(ctx, 0);
- ctx->NewDriverState |= ctx->DriverFlags.NewTransformFeedback;
-
- ctx->TransformFeedback.CurrentObject->Active = GL_FALSE;
- ctx->TransformFeedback.CurrentObject->Paused = GL_FALSE;
- ctx->TransformFeedback.CurrentObject->EndedAnytime = GL_TRUE;
-
- assert(ctx->Driver.EndTransformFeedback);
- ctx->Driver.EndTransformFeedback(ctx, obj);
+ end_transform_feedback(ctx, obj);
}
/**
- * 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.
+ * Validate the buffer object to receive transform feedback results. Plus,
+ * validate the starting offset to place the results, and max size.
+ * Called from the glBindBufferRange() and glTransformFeedbackBufferRange
+ * functions.
*/
-void
-_mesa_bind_buffer_range_transform_feedback(struct gl_context *ctx,
- struct gl_transform_feedback_object *obj,
- GLuint index,
- struct gl_buffer_object *bufObj,
- GLintptr offset,
- GLsizeiptr size)
+bool
+_mesa_validate_buffer_range_xfb(struct gl_context *ctx,
+ struct gl_transform_feedback_object *obj,
+ GLuint index, struct gl_buffer_object *bufObj,
+ GLintptr offset, GLsizeiptr size, bool dsa)
{
+ const char *gl_methd_name;
+ if (dsa)
+ gl_methd_name = "glTransformFeedbackBufferRange";
+ else
+ gl_methd_name = "glBindBufferRange";
+
+
if (obj->Active) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glBindBufferRange(transform feedback active)");
- return;
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s(transform feedback active)",
+ gl_methd_name);
+ return false;
}
if (index >= ctx->Const.MaxTransformFeedbackBuffers) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glBindBufferRange(index=%d "
- "out of bounds)", index);
- return;
+ /* 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 false;
}
if (size & 0x3) {
- /* must a multiple of four */
- _mesa_error(ctx, GL_INVALID_VALUE, "glBindBufferRange(size=%d)",
- (int) size);
- return;
- }
+ /* 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 false;
+ }
if (offset & 0x3) {
- /* must be multiple of four */
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glBindBufferRange(offset=%d)", (int) offset);
- return;
- }
+ /* 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 false;
+ }
+
+ 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 false;
+ }
+
+ if (size <= 0 && (dsa || bufObj)) {
+ /* 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 false;
+ }
- bind_buffer_range(ctx, obj, index, bufObj, offset, size, false);
+ return true;
}
*/
static struct gl_buffer_object *
lookup_transform_feedback_bufferobj_err(struct gl_context *ctx,
- GLuint buffer, const char* func)
+ GLuint buffer, const char* func,
+ bool *error)
{
- struct gl_buffer_object *bufObj;
+ struct gl_buffer_object *bufObj = NULL;
+
+ *error = false;
/* 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 {
+ if (buffer) {
bufObj = _mesa_lookup_bufferobj(ctx, buffer);
if (!bufObj) {
_mesa_error(ctx, GL_INVALID_VALUE, "%s(invalid buffer=%u)", func,
buffer);
+ *error = true;
}
}
obj = lookup_transform_feedback_object_err(ctx, xfb,
"glTransformFeedbackBufferBase");
- if(!obj) {
+ if (!obj) {
return;
}
+ bool error;
bufObj = lookup_transform_feedback_bufferobj_err(ctx, buffer,
- "glTransformFeedbackBufferBase");
- if(!bufObj) {
+ "glTransformFeedbackBufferBase",
+ &error);
+ if (error) {
return;
}
_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;
+ }
+
+ bool error;
+ bufObj = lookup_transform_feedback_bufferobj_err(ctx, buffer,
+ "glTransformFeedbackBufferRange",
+ &error);
+ if (error) {
+ return;
+ }
+
+ if (!_mesa_validate_buffer_range_xfb(ctx, obj, index, bufObj, offset,
+ size, true))
+ return;
+
+ /* The per-attribute binding point */
+ _mesa_set_transform_feedback_binding(ctx, obj, index, bufObj, offset,
+ size);
+}
+
/**
* 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.
*/
+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 = NULL;
+ } 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);
+ 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);
- if (!bufObj) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glBindBufferOffsetEXT(invalid buffer=%u)", buffer);
+ /* 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;
}
- bind_buffer_range(ctx, obj, index, bufObj, offset, 0, false);
+ /* 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.
+ */
}
-/**
- * This function specifies the transform feedback outputs to be written
- * to the feedback buffer(s), and in what order.
- */
+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,
return;
}
- shProg = _mesa_lookup_shader_program(ctx, program);
- if (!shProg) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glTransformFeedbackVaryings(program=%u)", program);
+ shProg = _mesa_lookup_shader_program_err(ctx, program,
+ "glTransformFeedbackVaryings");
+ if (!shProg)
return;
- }
if (ctx->Extensions.ARB_transform_feedback3) {
if (bufferMode == GL_INTERLEAVED_ATTRIBS) {
if (buffers > ctx->Const.MaxTransformFeedbackBuffers) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"glTransformFeedbackVaryings(too many gl_NextBuffer "
- "occurences)");
+ "occurrences)");
return;
}
} else {
}
}
- /* 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);
}
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);
- if (!shProg) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glGetTransformFeedbackVarying(program=%u)", program);
+ shProg = _mesa_lookup_shader_program_err(ctx, program,
+ "glGetTransformFeedbackVarying");
+ if (!shProg)
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");
}
}
else
return (struct gl_transform_feedback_object *)
- _mesa_HashLookup(ctx->TransformFeedback.Objects, name);
+ _mesa_HashLookupLocked(ctx->TransformFeedback.Objects, name);
}
static void
return;
}
ids[i] = first + i;
- _mesa_HashInsert(ctx->TransformFeedback.Objects, first + i, obj);
+ _mesa_HashInsertLocked(ctx->TransformFeedback.Objects, first + i,
+ obj);
if (dsa) {
/* this is normally done at bind time in the non-dsa case */
obj->EverBound = GL_TRUE;
* Bind the given transform feedback object.
* Part of GL_ARB_transform_feedback2.
*/
+static ALWAYS_INLINE void
+bind_transform_feedback(struct gl_context *ctx, GLuint name, bool no_error)
+{
+ struct gl_transform_feedback_object *obj;
+
+ obj = _mesa_lookup_transform_feedback_object(ctx, name);
+ if (!no_error && !obj) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glBindTransformFeedback(name=%u)", name);
+ return;
+ }
+
+ reference_transform_feedback_object(&ctx->TransformFeedback.CurrentObject,
+ obj);
+}
+
+
+void GLAPIENTRY
+_mesa_BindTransformFeedback_no_error(GLenum target, GLuint name)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ bind_transform_feedback(ctx, name, true);
+}
+
+
void GLAPIENTRY
_mesa_BindTransformFeedback(GLenum target, GLuint name)
{
- struct gl_transform_feedback_object *obj;
GET_CURRENT_CONTEXT(ctx);
if (target != GL_TRANSFORM_FEEDBACK) {
return;
}
- obj = _mesa_lookup_transform_feedback_object(ctx, name);
- if (!obj) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glBindTransformFeedback(name=%u)", name);
- return;
- }
-
- reference_transform_feedback_object(&ctx->TransformFeedback.CurrentObject,
- obj);
+ bind_transform_feedback(ctx, name, false);
}
names[i]);
return;
}
- _mesa_HashRemove(ctx->TransformFeedback.Objects, names[i]);
+ _mesa_HashRemoveLocked(ctx->TransformFeedback.Objects, names[i]);
/* unref, but object may not be deleted until later */
+ if (obj == ctx->TransformFeedback.CurrentObject) {
+ reference_transform_feedback_object(
+ &ctx->TransformFeedback.CurrentObject,
+ ctx->TransformFeedback.DefaultObject);
+ }
reference_transform_feedback_object(&obj, NULL);
}
}
* Pause transform feedback.
* Part of GL_ARB_transform_feedback2.
*/
+static void
+pause_transform_feedback(struct gl_context *ctx,
+ struct gl_transform_feedback_object *obj)
+{
+ FLUSH_VERTICES(ctx, 0);
+ ctx->NewDriverState |= ctx->DriverFlags.NewTransformFeedback;
+
+ assert(ctx->Driver.PauseTransformFeedback);
+ ctx->Driver.PauseTransformFeedback(ctx, obj);
+
+ obj->Paused = GL_TRUE;
+}
+
+
+void GLAPIENTRY
+_mesa_PauseTransformFeedback_no_error(void)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ pause_transform_feedback(ctx, ctx->TransformFeedback.CurrentObject);
+}
+
+
void GLAPIENTRY
_mesa_PauseTransformFeedback(void)
{
return;
}
- FLUSH_VERTICES(ctx, 0);
- ctx->NewDriverState |= ctx->DriverFlags.NewTransformFeedback;
-
- obj->Paused = GL_TRUE;
-
- assert(ctx->Driver.PauseTransformFeedback);
- ctx->Driver.PauseTransformFeedback(ctx, obj);
+ pause_transform_feedback(ctx, obj);
}
* Resume transform feedback.
* Part of GL_ARB_transform_feedback2.
*/
+static void
+resume_transform_feedback(struct gl_context *ctx,
+ struct gl_transform_feedback_object *obj)
+{
+ FLUSH_VERTICES(ctx, 0);
+ ctx->NewDriverState |= ctx->DriverFlags.NewTransformFeedback;
+
+ obj->Paused = GL_FALSE;
+
+ assert(ctx->Driver.ResumeTransformFeedback);
+ ctx->Driver.ResumeTransformFeedback(ctx, obj);
+}
+
+
+void GLAPIENTRY
+_mesa_ResumeTransformFeedback_no_error(void)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ resume_transform_feedback(ctx, ctx->TransformFeedback.CurrentObject);
+}
+
+
void GLAPIENTRY
_mesa_ResumeTransformFeedback(void)
{
* the program object being used by the current transform feedback object
* is not active."
*/
- if (obj->shader_program != get_xfb_source(ctx)) {
+ if (obj->program != get_xfb_source(ctx)) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"glResumeTransformFeedback(wrong program bound)");
return;
}
- FLUSH_VERTICES(ctx, 0);
- ctx->NewDriverState |= ctx->DriverFlags.NewTransformFeedback;
+ resume_transform_feedback(ctx, obj);
+}
- obj->Paused = GL_FALSE;
+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);
+ }
+}
- assert(ctx->Driver.ResumeTransformFeedback);
- ctx->Driver.ResumeTransformFeedback(ctx, obj);
+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;
+ }
+
+ /**
+ * 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:
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glGetTransformFeedbacki64_v(pname=%i)", pname);
+ }
}