summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrian Paul <brianp@vmware.com>2010-05-10 21:11:21 -0600
committerBrian Paul <brianp@vmware.com>2010-05-10 21:11:25 -0600
commitfef6e36e0736a68e24d7844bae65a01de8359214 (patch)
treee5d9abc8125f9166c55efe22dc11309099e1394c
parent12bc39f30c2cc27fe9bc4d33c7c79919d895537d (diff)
mesa: more transform feedback infrastructure
Includes GL_ARB_transform_feedback2 which encapsulates transform feedback state in objects.
-rw-r--r--src/mesa/SConscript1
-rw-r--r--src/mesa/drivers/common/driverfuncs.c7
-rw-r--r--src/mesa/main/dd.h16
-rw-r--r--src/mesa/main/extensions.c1
-rw-r--r--src/mesa/main/get.c18
-rw-r--r--src/mesa/main/get_gen.py6
-rw-r--r--src/mesa/main/mtypes.h35
-rw-r--r--src/mesa/main/transformfeedback.c474
-rw-r--r--src/mesa/main/transformfeedback.h31
-rw-r--r--src/mesa/shader/shader_api.c8
-rw-r--r--src/mesa/sources.mak1
-rw-r--r--src/mesa/state_tracker/st_cb_xformfb.c129
-rw-r--r--src/mesa/state_tracker/st_cb_xformfb.h36
-rw-r--r--src/mesa/state_tracker/st_context.c7
14 files changed, 736 insertions, 34 deletions
diff --git a/src/mesa/SConscript b/src/mesa/SConscript
index bf4ad6d261..9408e2d2f6 100644
--- a/src/mesa/SConscript
+++ b/src/mesa/SConscript
@@ -176,6 +176,7 @@ if env['platform'] != 'winddk':
'state_tracker/st_cb_readpixels.c',
'state_tracker/st_cb_strings.c',
'state_tracker/st_cb_texture.c',
+ 'state_tracker/st_cb_xformfb.c',
'state_tracker/st_context.c',
'state_tracker/st_debug.c',
'state_tracker/st_draw.c',
diff --git a/src/mesa/drivers/common/driverfuncs.c b/src/mesa/drivers/common/driverfuncs.c
index e518c000dd..ca5eb5c755 100644
--- a/src/mesa/drivers/common/driverfuncs.c
+++ b/src/mesa/drivers/common/driverfuncs.c
@@ -47,6 +47,9 @@
#if FEATURE_ARB_sync
#include "main/syncobj.h"
#endif
+#if FEATURE_EXT_transform_feedback
+#include "main/transformfeedback.h"
+#endif
#include "shader/program.h"
#include "shader/shader_api.h"
@@ -205,6 +208,10 @@ _mesa_init_driver_functions(struct dd_function_table *driver)
driver->DeleteArrayObject = _mesa_delete_array_object;
driver->BindArrayObject = NULL;
+#if FEATURE_EXT_transform_feedback
+ _mesa_init_transform_feedback_functions(driver);
+#endif
+
/* T&L stuff */
driver->NeedValidate = GL_FALSE;
driver->ValidateTnlModule = NULL;
diff --git a/src/mesa/main/dd.h b/src/mesa/main/dd.h
index cab8f34404..53e44533cb 100644
--- a/src/mesa/main/dd.h
+++ b/src/mesa/main/dd.h
@@ -1038,6 +1038,22 @@ struct dd_function_table {
void *image_handle);
#endif
+#if FEATURE_EXT_transform_feedback
+ struct gl_transform_feedback_object *
+ (*NewTransformFeedback)(GLcontext *ctx, GLuint name);
+ void (*DeleteTransformFeedback)(GLcontext *ctx,
+ struct gl_transform_feedback_object *obj);
+ void (*BeginTransformFeedback)(GLcontext *ctx, GLenum mode,
+ struct gl_transform_feedback_object *obj);
+ void (*EndTransformFeedback)(GLcontext *ctx,
+ struct gl_transform_feedback_object *obj);
+ void (*PauseTransformFeedback)(GLcontext *ctx,
+ struct gl_transform_feedback_object *obj);
+ void (*ResumeTransformFeedback)(GLcontext *ctx,
+ struct gl_transform_feedback_object *obj);
+ void (*DrawTransformFeedback)(GLcontext *ctx, GLenum mode,
+ struct gl_transform_feedback_object *obj);
+#endif
};
diff --git a/src/mesa/main/extensions.c b/src/mesa/main/extensions.c
index 4c8d4ccfa2..1748ce2733 100644
--- a/src/mesa/main/extensions.c
+++ b/src/mesa/main/extensions.c
@@ -86,6 +86,7 @@ static const struct {
{ OFF, "GL_ARB_texture_non_power_of_two", F(ARB_texture_non_power_of_two)},
{ OFF, "GL_ARB_texture_rectangle", F(NV_texture_rectangle) },
{ ON, "GL_ARB_transpose_matrix", F(ARB_transpose_matrix) },
+ { OFF, "GL_ARB_transform_feedback2", F(ARB_transform_feedback2) },
{ OFF, "GL_ARB_vertex_array_bgra", F(EXT_vertex_array_bgra) },
{ OFF, "GL_ARB_vertex_array_object", F(ARB_vertex_array_object) },
{ ON, "GL_ARB_vertex_buffer_object", F(ARB_vertex_buffer_object) },
diff --git a/src/mesa/main/get.c b/src/mesa/main/get.c
index 2e8b0a4e8c..8230723f26 100644
--- a/src/mesa/main/get.c
+++ b/src/mesa/main/get.c
@@ -7786,7 +7786,7 @@ _mesa_GetBooleanIndexedv( GLenum pname, GLuint index, GLboolean *params )
_mesa_error(ctx, GL_INVALID_VALUE, "glGetBooleanIndexedv(index=%u), index", pname);
return;
}
- params[0] = INT64_TO_BOOLEAN(ctx->TransformFeedback.Offset[index]);
+ params[0] = INT64_TO_BOOLEAN(ctx->TransformFeedback.CurrentObject->Offset[index]);
break;
case GL_TRANSFORM_FEEDBACK_BUFFER_SIZE:
CHECK_EXT1(EXT_transform_feedback);
@@ -7794,7 +7794,7 @@ _mesa_GetBooleanIndexedv( GLenum pname, GLuint index, GLboolean *params )
_mesa_error(ctx, GL_INVALID_VALUE, "glGetBooleanIndexedv(index=%u), index", pname);
return;
}
- params[0] = INT64_TO_BOOLEAN(ctx->TransformFeedback.Size[index]);
+ params[0] = INT64_TO_BOOLEAN(ctx->TransformFeedback.CurrentObject->Size[index]);
break;
case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING:
CHECK_EXT1(EXT_transform_feedback);
@@ -7802,7 +7802,7 @@ _mesa_GetBooleanIndexedv( GLenum pname, GLuint index, GLboolean *params )
_mesa_error(ctx, GL_INVALID_VALUE, "glGetBooleanIndexedv(index=%u), index", pname);
return;
}
- params[0] = INT_TO_BOOLEAN(ctx->TransformFeedback.Buffers[index]->Name);
+ params[0] = INT_TO_BOOLEAN(ctx->TransformFeedback.CurrentObject->Buffers[index]->Name);
break;
default:
goto invalid_enum_error;
@@ -7850,7 +7850,7 @@ _mesa_GetIntegerIndexedv( GLenum pname, GLuint index, GLint *params )
_mesa_error(ctx, GL_INVALID_VALUE, "glGetIntegerIndexedv(index=%u), index", pname);
return;
}
- params[0] = INT64_TO_INT(ctx->TransformFeedback.Offset[index]);
+ params[0] = INT64_TO_INT(ctx->TransformFeedback.CurrentObject->Offset[index]);
break;
case GL_TRANSFORM_FEEDBACK_BUFFER_SIZE:
CHECK_EXT1(EXT_transform_feedback);
@@ -7858,7 +7858,7 @@ _mesa_GetIntegerIndexedv( GLenum pname, GLuint index, GLint *params )
_mesa_error(ctx, GL_INVALID_VALUE, "glGetIntegerIndexedv(index=%u), index", pname);
return;
}
- params[0] = INT64_TO_INT(ctx->TransformFeedback.Size[index]);
+ params[0] = INT64_TO_INT(ctx->TransformFeedback.CurrentObject->Size[index]);
break;
case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING:
CHECK_EXT1(EXT_transform_feedback);
@@ -7866,7 +7866,7 @@ _mesa_GetIntegerIndexedv( GLenum pname, GLuint index, GLint *params )
_mesa_error(ctx, GL_INVALID_VALUE, "glGetIntegerIndexedv(index=%u), index", pname);
return;
}
- params[0] = ctx->TransformFeedback.Buffers[index]->Name;
+ params[0] = ctx->TransformFeedback.CurrentObject->Buffers[index]->Name;
break;
default:
goto invalid_enum_error;
@@ -7915,7 +7915,7 @@ _mesa_GetInteger64Indexedv( GLenum pname, GLuint index, GLint64 *params )
_mesa_error(ctx, GL_INVALID_VALUE, "glGetInteger64Indexedv(index=%u), index", pname);
return;
}
- params[0] = ctx->TransformFeedback.Offset[index];
+ params[0] = ctx->TransformFeedback.CurrentObject->Offset[index];
break;
case GL_TRANSFORM_FEEDBACK_BUFFER_SIZE:
CHECK_EXT1(EXT_transform_feedback);
@@ -7923,7 +7923,7 @@ _mesa_GetInteger64Indexedv( GLenum pname, GLuint index, GLint64 *params )
_mesa_error(ctx, GL_INVALID_VALUE, "glGetInteger64Indexedv(index=%u), index", pname);
return;
}
- params[0] = ctx->TransformFeedback.Size[index];
+ params[0] = ctx->TransformFeedback.CurrentObject->Size[index];
break;
case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING:
CHECK_EXT1(EXT_transform_feedback);
@@ -7931,7 +7931,7 @@ _mesa_GetInteger64Indexedv( GLenum pname, GLuint index, GLint64 *params )
_mesa_error(ctx, GL_INVALID_VALUE, "glGetInteger64Indexedv(index=%u), index", pname);
return;
}
- params[0] = (GLint64)(ctx->TransformFeedback.Buffers[index]->Name);
+ params[0] = (GLint64)(ctx->TransformFeedback.CurrentObject->Buffers[index]->Name);
break;
default:
goto invalid_enum_error;
diff --git a/src/mesa/main/get_gen.py b/src/mesa/main/get_gen.py
index d7c543f368..0e9c9a8666 100644
--- a/src/mesa/main/get_gen.py
+++ b/src/mesa/main/get_gen.py
@@ -1178,15 +1178,15 @@ IndexedStateVars = [
# GL_EXT_transform_feedback
( "GL_TRANSFORM_FEEDBACK_BUFFER_START", GLint64,
- ["ctx->TransformFeedback.Offset[index]"],
+ ["ctx->TransformFeedback.CurrentObject->Offset[index]"],
"ctx->Const.MaxTransformFeedbackSeparateAttribs",
NoState, ["EXT_transform_feedback"] ),
( "GL_TRANSFORM_FEEDBACK_BUFFER_SIZE", GLint64,
- ["ctx->TransformFeedback.Size[index]"],
+ ["ctx->TransformFeedback.CurrentObject->Size[index]"],
"ctx->Const.MaxTransformFeedbackSeparateAttribs",
NoState, ["EXT_transform_feedback"] ),
( "GL_TRANSFORM_FEEDBACK_BUFFER_BINDING", GLint,
- ["ctx->TransformFeedback.Buffers[index]->Name"],
+ ["ctx->TransformFeedback.CurrentObject->Buffers[index]->Name"],
"ctx->Const.MaxTransformFeedbackSeparateAttribs",
NoState, ["EXT_transform_feedback"] ),
diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h
index 81ab17c698..c34d9bac4a 100644
--- a/src/mesa/main/mtypes.h
+++ b/src/mesa/main/mtypes.h
@@ -2034,24 +2034,46 @@ struct gl_shader_state
/**
- * Context state for transform feedback.
+ * Transform feedback object state
*/
-struct gl_transform_feedback
+struct gl_transform_feedback_object
{
+ GLuint Name; /**< AKA the object ID */
+ GLint RefCount;
GLboolean Active; /**< Is transform feedback enabled? */
- GLenum Mode; /**< GL_POINTS, GL_LINES or GL_TRIANGLES */
+ GLboolean Paused; /**< Is transform feedback paused? */
+
+ /** The feedback buffers */
+ GLuint BufferNames[MAX_FEEDBACK_ATTRIBS];
+ struct gl_buffer_object *Buffers[MAX_FEEDBACK_ATTRIBS];
+
/** Start of feedback data in dest buffer */
GLintptr Offset[MAX_FEEDBACK_ATTRIBS];
/** Max data to put into dest buffer (in bytes) */
GLsizeiptr Size[MAX_FEEDBACK_ATTRIBS];
+};
+
+
+/**
+ * Context state for transform feedback.
+ */
+struct gl_transform_feedback
+{
+ GLenum Mode; /**< GL_POINTS, GL_LINES or GL_TRIANGLES */
+
GLboolean RasterDiscard; /**< GL_RASTERIZER_DISCARD */
/** The general binding point (GL_TRANSFORM_FEEDBACK_BUFFER) */
struct gl_buffer_object *CurrentBuffer;
- /** The feedback buffers */
- GLuint BufferNames[MAX_FEEDBACK_ATTRIBS];
- struct gl_buffer_object *Buffers[MAX_FEEDBACK_ATTRIBS];
+ /** The table of all transform feedback objects */
+ struct _mesa_HashTable *Objects;
+
+ /** The current xform-fb object (GL_TRANSFORM_FEEDBACK_BINDING) */
+ struct gl_transform_feedback_object *CurrentObject;
+
+ /** The default xform-fb object (Name==0) */
+ struct gl_transform_feedback_object *DefaultObject;
};
@@ -2480,6 +2502,7 @@ struct gl_extensions
GLboolean ARB_texture_float;
GLboolean ARB_texture_mirrored_repeat;
GLboolean ARB_texture_non_power_of_two;
+ GLboolean ARB_transform_feedback2;
GLboolean ARB_transpose_matrix;
GLboolean ARB_vertex_array_object;
GLboolean ARB_vertex_buffer_object;
diff --git a/src/mesa/main/transformfeedback.c b/src/mesa/main/transformfeedback.c
index 74519ba38a..528e7d954b 100644
--- a/src/mesa/main/transformfeedback.c
+++ b/src/mesa/main/transformfeedback.c
@@ -33,6 +33,7 @@
#include "buffers.h"
#include "bufferobj.h"
#include "context.h"
+#include "hash.h"
#include "transformfeedback.h"
#include "shader/prog_parameter.h"
@@ -40,6 +41,47 @@
/**
+ * Do reference counting of transform feedback buffers.
+ */
+static void
+reference_transform_feedback_object(struct gl_transform_feedback_object **ptr,
+ struct gl_transform_feedback_object *obj)
+{
+ if (*ptr == obj)
+ return;
+
+ if (*ptr) {
+ /* Unreference the old object */
+ struct gl_transform_feedback_object *oldObj = *ptr;
+
+ ASSERT(oldObj->RefCount > 0);
+ oldObj->RefCount--;
+
+ if (oldObj->RefCount == 0) {
+ GET_CURRENT_CONTEXT(ctx);
+ if (ctx)
+ ctx->Driver.DeleteTransformFeedback(ctx, oldObj);
+ }
+
+ *ptr = NULL;
+ }
+ ASSERT(!*ptr);
+
+ if (obj) {
+ /* reference new object */
+ if (obj->RefCount == 0) {
+ _mesa_problem(NULL, "referencing deleted transform feedback object");
+ *ptr = NULL;
+ }
+ else {
+ obj->RefCount++;
+ *ptr = obj;
+ }
+ }
+}
+
+
+/**
* Check if the given primitive mode (as in glBegin(mode)) is compatible
* with the current transform feedback mode (if it's enabled).
* This is to be called from glBegin(), glDrawArrays(), glDrawElements(), etc.
@@ -49,7 +91,7 @@
GLboolean
_mesa_validate_primitive_mode(GLcontext *ctx, GLenum mode)
{
- if (ctx->TransformFeedback.Active) {
+ if (ctx->TransformFeedback.CurrentObject->Active) {
switch (mode) {
case GL_POINTS:
return ctx->TransformFeedback.Mode == GL_POINTS;
@@ -74,7 +116,7 @@ _mesa_validate_primitive_mode(GLcontext *ctx, GLenum mode)
GLboolean
_mesa_validate_transform_feedback_buffers(GLcontext *ctx)
{
-
+ /* XXX to do */
return GL_TRUE;
}
@@ -86,29 +128,173 @@ _mesa_validate_transform_feedback_buffers(GLcontext *ctx)
void
_mesa_init_transform_feedback(GLcontext *ctx)
{
+ if (!ctx->Driver.NewTransformFeedback) {
+ /* this feature/extension may not be supported by the driver */
+ return;
+ }
+
+ ctx->TransformFeedback.DefaultObject =
+ ctx->Driver.NewTransformFeedback(ctx, 0);
+
+ assert(ctx->TransformFeedback.DefaultObject->RefCount == 1);
+
+ reference_transform_feedback_object(&ctx->TransformFeedback.CurrentObject,
+ ctx->TransformFeedback.DefaultObject);
+
+ assert(ctx->TransformFeedback.DefaultObject->RefCount == 2);
+
+ ctx->TransformFeedback.Objects = _mesa_NewHashTable();
+
_mesa_reference_buffer_object(ctx,
&ctx->TransformFeedback.CurrentBuffer,
ctx->Shared->NullBufferObj);
}
+
+/**
+ * Callback for _mesa_HashDeleteAll().
+ */
+static void
+delete_cb(GLuint key, void *data, void *userData)
+{
+ GLcontext *ctx = (GLcontext *) userData;
+ struct gl_transform_feedback_object *obj =
+ (struct gl_transform_feedback_object *) data;
+
+ ctx->Driver.DeleteTransformFeedback(ctx, obj);
+}
+
+
/**
* Per-context free/clean-up for transform feedback.
*/
void
_mesa_free_transform_feedback(GLcontext *ctx)
{
+ if (!ctx->Driver.NewTransformFeedback) {
+ /* this feature/extension may not be supported by the driver */
+ return;
+ }
+
_mesa_reference_buffer_object(ctx,
&ctx->TransformFeedback.CurrentBuffer,
NULL);
+
+ /* Delete all feedback objects */
+ _mesa_HashDeleteAll(ctx->TransformFeedback.Objects, delete_cb, ctx);
+
+ /* Delete the default feedback object */
+ assert(ctx->Driver.DeleteTransformFeedback);
+ ctx->Driver.DeleteTransformFeedback(ctx, ctx->TransformFeedback.DefaultObject);
+
+ ctx->TransformFeedback.CurrentObject = NULL;
}
+/** Default fallback for ctx->Driver.NewTransformFeedback() */
+static struct gl_transform_feedback_object *
+new_transform_feedback(GLcontext *ctx, GLuint name)
+{
+ struct gl_transform_feedback_object *obj;
+ obj = CALLOC_STRUCT(gl_transform_feedback_object);
+ if (obj) {
+ obj->Name = name;
+ obj->RefCount = 1;
+ }
+ return obj;
+}
+
+/** Default fallback for ctx->Driver.DeleteTransformFeedback() */
+static void
+delete_transform_feedback(GLcontext *ctx,
+ struct gl_transform_feedback_object *obj)
+{
+ GLuint i;
+
+ for (i = 0; i < Elements(obj->Buffers); i++) {
+ _mesa_reference_buffer_object(ctx, &obj->Buffers[i], NULL);
+ }
+
+ free(obj);
+}
+
+/** Default fallback for ctx->Driver.BeginTransformFeedback() */
+static void
+begin_transform_feedback(GLcontext *ctx, GLenum mode,
+ struct gl_transform_feedback_object *obj)
+{
+ /* nop */
+}
+
+/** Default fallback for ctx->Driver.EndTransformFeedback() */
+static void
+end_transform_feedback(GLcontext *ctx,
+ struct gl_transform_feedback_object *obj)
+{
+ /* nop */
+}
+
+/** Default fallback for ctx->Driver.PauseTransformFeedback() */
+static void
+pause_transform_feedback(GLcontext *ctx,
+ struct gl_transform_feedback_object *obj)
+{
+ /* nop */
+}
+
+/** Default fallback for ctx->Driver.ResumeTransformFeedback() */
+static void
+resume_transform_feedback(GLcontext *ctx,
+ struct gl_transform_feedback_object *obj)
+{
+ /* nop */
+}
+
+/** Default fallback for ctx->Driver.DrawTransformFeedback() */
+static void
+draw_transform_feedback(GLcontext *ctx, GLenum mode,
+ struct gl_transform_feedback_object *obj)
+{
+ /* XXX to do */
+ /*
+ * Get number of vertices in obj's feedback buffer.
+ * Call ctx->Exec.DrawArrays(mode, 0, count);
+ */
+}
+
+
+/**
+ * Plug in default device driver functions for transform feedback.
+ * Most drivers will override some/all of these.
+ */
+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->DrawTransformFeedback = draw_transform_feedback;
+}
+
+
+
+/**
+ ** Begin API functions
+ **/
+
+
void GLAPIENTRY
_mesa_BeginTransformFeedback(GLenum mode)
{
+ struct gl_transform_feedback_object *obj;
GET_CURRENT_CONTEXT(ctx);
+ obj = ctx->TransformFeedback.CurrentObject;
+
switch (mode) {
case GL_POINTS:
case GL_LINES:
@@ -120,29 +306,38 @@ _mesa_BeginTransformFeedback(GLenum mode)
return;
}
- if (ctx->TransformFeedback.Active) {
+ if (obj->Active) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"glBeginTransformFeedback(already active)");
return;
}
- ctx->TransformFeedback.Active = GL_TRUE;
+ obj->Active = GL_TRUE;
ctx->TransformFeedback.Mode = mode;
+
+ assert(ctx->Driver.BeginTransformFeedback);
+ ctx->Driver.BeginTransformFeedback(ctx, mode, obj);
}
void GLAPIENTRY
_mesa_EndTransformFeedback(void)
{
+ struct gl_transform_feedback_object *obj;
GET_CURRENT_CONTEXT(ctx);
- if (!ctx->TransformFeedback.Active) {
+ obj = ctx->TransformFeedback.CurrentObject;
+
+ if (!obj->Active) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"glEndTransformFeedback(not active)");
return;
}
- ctx->TransformFeedback.Active = GL_FALSE;
+ ctx->TransformFeedback.CurrentObject->Active = GL_FALSE;
+
+ assert(ctx->Driver.EndTransformFeedback);
+ ctx->Driver.EndTransformFeedback(ctx, obj);
}
@@ -154,6 +349,9 @@ bind_buffer_range(GLcontext *ctx, GLuint index,
struct gl_buffer_object *bufObj,
GLintptr offset, GLsizeiptr size)
{
+ struct gl_transform_feedback_object *obj =
+ ctx->TransformFeedback.CurrentObject;
+
/* The general binding point */
_mesa_reference_buffer_object(ctx,
&ctx->TransformFeedback.CurrentBuffer,
@@ -161,13 +359,13 @@ bind_buffer_range(GLcontext *ctx, GLuint index,
/* The per-attribute binding point */
_mesa_reference_buffer_object(ctx,
- &ctx->TransformFeedback.Buffers[index],
+ &obj->Buffers[index],
bufObj);
- ctx->TransformFeedback.BufferNames[index] = bufObj->Name;
+ obj->BufferNames[index] = bufObj->Name;
- ctx->TransformFeedback.Offset[index] = offset;
- ctx->TransformFeedback.Size[index] = size;
+ obj->Offset[index] = offset;
+ obj->Size[index] = size;
}
@@ -179,6 +377,7 @@ void GLAPIENTRY
_mesa_BindBufferRange(GLenum target, GLuint index,
GLuint buffer, GLintptr offset, GLsizeiptr size)
{
+ struct gl_transform_feedback_object *obj;
struct gl_buffer_object *bufObj;
GET_CURRENT_CONTEXT(ctx);
@@ -187,7 +386,9 @@ _mesa_BindBufferRange(GLenum target, GLuint index,
return;
}
- if (ctx->TransformFeedback.Active) {
+ obj = ctx->TransformFeedback.CurrentObject;
+
+ if (obj->Active) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"glBindBufferRange(transform feedback active)");
return;
@@ -235,16 +436,19 @@ _mesa_BindBufferRange(GLenum target, GLuint index,
void GLAPIENTRY
_mesa_BindBufferBase(GLenum target, GLuint index, GLuint buffer)
{
+ struct gl_transform_feedback_object *obj;
struct gl_buffer_object *bufObj;
- GET_CURRENT_CONTEXT(ctx);
GLsizeiptr size;
+ GET_CURRENT_CONTEXT(ctx);
if (target != GL_TRANSFORM_FEEDBACK_BUFFER) {
_mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferBase(target)");
return;
}
- if (ctx->TransformFeedback.Active) {
+ obj = ctx->TransformFeedback.CurrentObject;
+
+ if (obj->Active) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"glBindBufferRange(transform feedback active)");
return;
@@ -280,6 +484,7 @@ 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);
GLsizeiptr size;
@@ -289,7 +494,9 @@ _mesa_BindBufferOffsetEXT(GLenum target, GLuint index, GLuint buffer,
return;
}
- if (ctx->TransformFeedback.Active) {
+ obj = ctx->TransformFeedback.CurrentObject;
+
+ if (obj->Active) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"glBindBufferRange(transform feedback active)");
return;
@@ -433,3 +640,242 @@ _mesa_GetTransformFeedbackVarying(GLuint program, GLuint index,
}
}
+
+
+static struct gl_transform_feedback_object *
+lookup_transform_feedback_object(GLcontext *ctx, GLuint name)
+{
+ if (name == 0) {
+ return ctx->TransformFeedback.DefaultObject;
+ }
+ else
+ return (struct gl_transform_feedback_object *)
+ _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)
+{
+ GLuint first;
+ GET_CURRENT_CONTEXT(ctx);
+
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ if (n < 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glGenTransformFeedbacks(n < 0)");
+ return;
+ }
+
+ if (!names)
+ return;
+
+ /* we don't need contiguous IDs, but this might be faster */
+ first = _mesa_HashFindFreeKeyBlock(ctx->TransformFeedback.Objects, n);
+ if (first) {
+ GLsizei i;
+ for (i = 0; i < n; i++) {
+ struct gl_transform_feedback_object *obj
+ = ctx->Driver.NewTransformFeedback(ctx, first + i);
+ if (!obj) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenTransformFeedbacks");
+ return;
+ }
+ names[i] = first + i;
+ _mesa_HashInsert(ctx->TransformFeedback.Objects, first + i, obj);
+ }
+ }
+ else {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenTransformFeedbacks");
+ }
+}
+
+
+/**
+ * Is the given ID a transform feedback object?
+ * Part of GL_ARB_transform_feedback2.
+ */
+GLboolean GLAPIENTRY
+_mesa_IsTransformFeedback(GLuint name)
+{
+ GET_CURRENT_CONTEXT(ctx);
+
+ ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
+
+ if (name && lookup_transform_feedback_object(ctx, name))
+ return GL_TRUE;
+ else
+ return GL_FALSE;
+}
+
+
+/**
+ * Bind the given transform feedback object.
+ * Part of GL_ARB_transform_feedback2.
+ */
+void GLAPIENTRY
+_mesa_BindTransformFeedback(GLenum target, uint name)
+{
+ struct gl_transform_feedback_object *obj;
+ GET_CURRENT_CONTEXT(ctx);
+
+ if (target != GL_TRANSFORM_FEEDBACK) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glBindTransformFeedback(target)");
+ return;
+ }
+
+ if (ctx->TransformFeedback.CurrentObject->Active &&
+ !ctx->TransformFeedback.CurrentObject->Paused) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glBindTransformFeedback(transform is active, or not paused)");
+ return;
+ }
+
+ obj = 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);
+}
+
+
+/**
+ * Delete the given transform feedback objects.
+ * Part of GL_ARB_transform_feedback2.
+ */
+void GLAPIENTRY
+_mesa_DeleteTransformFeedbacks(GLsizei n, const GLuint *names)
+{
+ GLint i;
+ GET_CURRENT_CONTEXT(ctx);
+
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ if (n < 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteTransformFeedbacks(n < 0)");
+ return;
+ }
+
+ if (!names)
+ return;
+
+ for (i = 0; i < n; i++) {
+ if (names[i] > 0) {
+ struct gl_transform_feedback_object *obj
+ = lookup_transform_feedback_object(ctx, names[i]);
+ if (obj) {
+ if (obj->Active) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glDeleteTransformFeedbacks(object %u is active)",
+ names[i]);
+ return;
+ }
+ _mesa_HashRemove(ctx->TransformFeedback.Objects, names[i]);
+ /* unref, but object may not be deleted until later */
+ reference_transform_feedback_object(&obj, NULL);
+ }
+ }
+ }
+}
+
+
+/**
+ * Pause transform feedback.
+ * Part of GL_ARB_transform_feedback2.
+ */
+void GLAPIENTRY
+_mesa_PauseTransformFeedback(void)
+{
+ struct gl_transform_feedback_object *obj;
+ GET_CURRENT_CONTEXT(ctx);
+
+ obj = ctx->TransformFeedback.CurrentObject;
+
+ if (!obj->Active || obj->Paused) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glPauseTransformFeedback(feedback not active or already paused)");
+ return;
+ }
+
+ obj->Paused = GL_TRUE;
+
+ assert(ctx->Driver.PauseTransformFeedback);
+ ctx->Driver.PauseTransformFeedback(ctx, obj);
+}
+
+
+/**
+ * Resume transform feedback.
+ * Part of GL_ARB_transform_feedback2.
+ */
+void GLAPIENTRY
+_mesa_ResumeTransformFeedback(void)
+{
+ struct gl_transform_feedback_object *obj;
+ GET_CURRENT_CONTEXT(ctx);
+
+ obj = ctx->TransformFeedback.CurrentObject;
+
+ if (!obj->Active || !obj->Paused) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glPauseTransformFeedback(feedback not active or not paused)");
+ return;
+ }
+
+ obj->Paused = GL_FALSE;
+
+ assert(ctx->Driver.ResumeTransformFeedback);
+ ctx->Driver.ResumeTransformFeedback(ctx, obj);
+}
+
+
+/**
+ * Draw the vertex data in a transform feedback object.
+ * \param mode GL_POINTS, GL_LINES, GL_TRIANGLE_STRIP, etc.
+ * \param name the transform feedback object
+ * The number of vertices comes from the transform feedback object.
+ * User still has to setup of the vertex attribute info with
+ * glVertexPointer, glColorPointer, etc.
+ * Part of GL_ARB_transform_feedback2.
+ */
+void GLAPIENTRY
+_mesa_DrawTransformFeedback(GLenum mode, GLuint name)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct gl_transform_feedback_object *obj =
+ lookup_transform_feedback_object(ctx, name);
+
+ if (!obj) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glDrawTransformFeedback(name = %u)", name);
+ return;
+ }
+
+ /* XXX check if EndTransformFeedback has never been called while
+ * the object was bound
+ */
+
+ assert(ctx->Driver.DrawTransformFeedback);
+ ctx->Driver.DrawTransformFeedback(ctx, mode, obj);
+}
+
+
+/*
+XXX misc to do:
+
+glGet*() for
+
+GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED
+GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE
+GL_TRANSFORM_FEEDBACK_BINDING
+*/
diff --git a/src/mesa/main/transformfeedback.h b/src/mesa/main/transformfeedback.h
index e89cc41473..53cc456591 100644
--- a/src/mesa/main/transformfeedback.h
+++ b/src/mesa/main/transformfeedback.h
@@ -41,6 +41,12 @@ extern void
_mesa_free_transform_feedback(GLcontext *ctx);
+extern void
+_mesa_init_transform_feedback_functions(struct dd_function_table *driver);
+
+
+/*** GL_EXT_transform_feedback ***/
+
extern void GLAPIENTRY
_mesa_BeginTransformFeedback(GLenum mode);
@@ -68,4 +74,29 @@ _mesa_GetTransformFeedbackVarying(GLuint program, GLuint index,
GLsizei *size, GLenum *type, GLchar *name);
+
+/*** GL_ARB_transform_feedback2 ***/
+
+extern void GLAPIENTRY
+_mesa_GenTransformFeedbacks(GLsizei n, GLuint *names);
+
+extern GLboolean GLAPIENTRY
+_mesa_IsTransformFeedback(GLuint name);
+
+extern void GLAPIENTRY
+_mesa_BindTransformFeedback(GLenum target, uint name);
+
+extern void GLAPIENTRY
+_mesa_DeleteTransformFeedbacks(GLsizei n, const GLuint *names);
+
+extern void GLAPIENTRY
+_mesa_PauseTransformFeedback(void);
+
+extern void GLAPIENTRY
+_mesa_ResumeTransformFeedback(void);
+
+extern void GLAPIENTRY
+_mesa_DrawTransformFeedback(GLenum mode, GLuint name);
+
+
#endif /* TRANSFORM_FEEDBACK_H */
diff --git a/src/mesa/shader/shader_api.c b/src/mesa/shader/shader_api.c
index 4ff032d4ec..505c7bb46f 100644
--- a/src/mesa/shader/shader_api.c
+++ b/src/mesa/shader/shader_api.c
@@ -1517,12 +1517,14 @@ static void
_mesa_link_program(GLcontext *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 (ctx->TransformFeedback.Active && shProg == ctx->Shader.CurrentProgram) {
+ if (obj->Active && shProg == ctx->Shader.CurrentProgram) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"glLinkProgram(transform feedback active");
return;
@@ -1591,8 +1593,10 @@ void
_mesa_use_program(GLcontext *ctx, GLuint program)
{
struct gl_shader_program *shProg;
+ struct gl_transform_feedback_object *obj =
+ ctx->TransformFeedback.CurrentObject;
- if (ctx->TransformFeedback.Active) {
+ if (obj->Active) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"glUseProgram(transform feedback active)");
return;
diff --git a/src/mesa/sources.mak b/src/mesa/sources.mak
index 55523fad1d..5c2aa92132 100644
--- a/src/mesa/sources.mak
+++ b/src/mesa/sources.mak
@@ -210,6 +210,7 @@ STATETRACKER_SOURCES = \
state_tracker/st_cb_readpixels.c \
state_tracker/st_cb_strings.c \
state_tracker/st_cb_texture.c \
+ state_tracker/st_cb_xformfb.c \
state_tracker/st_context.c \
state_tracker/st_debug.c \
state_tracker/st_draw.c \
diff --git a/src/mesa/state_tracker/st_cb_xformfb.c b/src/mesa/state_tracker/st_cb_xformfb.c
new file mode 100644
index 0000000000..fb48b57eb5
--- /dev/null
+++ b/src/mesa/state_tracker/st_cb_xformfb.c
@@ -0,0 +1,129 @@
+/**************************************************************************
+ *
+ * Copyright 2010 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+
+/**
+ * Transform feedback functions.
+ *
+ * \author Brian Paul
+ */
+
+
+#include "main/imports.h"
+#include "main/context.h"
+#include "main/transformfeedback.h"
+
+#include "st_cb_xformfb.h"
+
+
+#if 0
+static struct gl_transform_feedback_object *
+st_new_transform_feedback(GLcontext *ctx, GLuint name)
+{
+ struct gl_transform_feedback_object *obj;
+ obj = CALLOC_STRUCT(gl_transform_feedback_object);
+ if (obj) {
+ obj->Name = name;
+ obj->RefCount = 1;
+ }
+ return obj;
+}
+#endif
+
+#if 0
+static void
+st_delete_transform_feedback(GLcontext *ctx,
+ struct gl_transform_feedback_object *obj)
+{
+ GLuint i;
+
+ for (i = 0; i < Elements(obj->Buffers); i++) {
+ _mesa_reference_buffer_object(ctx, &obj->Buffers[i], NULL);
+ }
+
+ free(obj);
+}
+#endif
+
+
+static void
+st_begin_transform_feedback(GLcontext *ctx, GLenum mode,
+ struct gl_transform_feedback_object *obj)
+{
+ /* to-do */
+}
+
+
+static void
+st_end_transform_feedback(GLcontext *ctx,
+ struct gl_transform_feedback_object *obj)
+{
+ /* to-do */
+}
+
+
+static void
+st_pause_transform_feedback(GLcontext *ctx,
+ struct gl_transform_feedback_object *obj)
+{
+ /* to-do */
+}
+
+
+static void
+st_resume_transform_feedback(GLcontext *ctx,
+ struct gl_transform_feedback_object *obj)
+{
+ /* to-do */
+}
+
+
+static void
+st_draw_transform_feedback(GLcontext *ctx, GLenum mode,
+ struct gl_transform_feedback_object *obj)
+{
+ /* XXX to do */
+ /*
+ * Get number of vertices in obj's feedback buffer.
+ * Call ctx->Exec.DrawArrays(mode, 0, count);
+ */
+}
+
+
+void
+st_init_xformfb_functions(struct dd_function_table *functions)
+{
+ /* let core Mesa plug in its functions */
+ _mesa_init_transform_feedback_functions(functions);
+
+ /* then override a few: */
+ functions->BeginTransformFeedback = st_begin_transform_feedback;
+ functions->EndTransformFeedback = st_end_transform_feedback;
+ functions->PauseTransformFeedback = st_pause_transform_feedback;
+ functions->ResumeTransformFeedback = st_resume_transform_feedback;
+ functions->DrawTransformFeedback = st_draw_transform_feedback;
+}
diff --git a/src/mesa/state_tracker/st_cb_xformfb.h b/src/mesa/state_tracker/st_cb_xformfb.h
new file mode 100644
index 0000000000..d6c354e5a5
--- /dev/null
+++ b/src/mesa/state_tracker/st_cb_xformfb.h
@@ -0,0 +1,36 @@
+/**************************************************************************
+ *
+ * Copyright 2010 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#ifndef ST_CB_XFORMFB_H
+#define ST_CB_XFORMFB_H
+
+
+extern void
+st_init_xformfb_functions(struct dd_function_table *functions);
+
+
+#endif /* ST_CB_XFORMFB_H */
diff --git a/src/mesa/state_tracker/st_context.c b/src/mesa/state_tracker/st_context.c
index e8a3926e6d..93406141f6 100644
--- a/src/mesa/state_tracker/st_context.c
+++ b/src/mesa/state_tracker/st_context.c
@@ -54,6 +54,9 @@
#include "st_cb_queryobj.h"
#include "st_cb_readpixels.h"
#include "st_cb_texture.h"
+#if FEATURE_EXT_transform_feedback
+#include "st_cb_xformfb.h"
+#endif
#include "st_cb_flush.h"
#include "st_cb_strings.h"
#include "st_atom.h"
@@ -335,5 +338,9 @@ void st_init_driver_functions(struct dd_function_table *functions)
st_init_flush_functions(functions);
st_init_string_functions(functions);
+#if FEATURE_EXT_transform_feedback
+ st_init_xformfb_functions(functions);
+#endif
+
functions->UpdateState = st_invalidate_state;
}