diff options
| -rw-r--r-- | src/mesa/SConscript | 1 | ||||
| -rw-r--r-- | src/mesa/drivers/common/driverfuncs.c | 7 | ||||
| -rw-r--r-- | src/mesa/main/dd.h | 16 | ||||
| -rw-r--r-- | src/mesa/main/extensions.c | 1 | ||||
| -rw-r--r-- | src/mesa/main/get.c | 18 | ||||
| -rw-r--r-- | src/mesa/main/get_gen.py | 6 | ||||
| -rw-r--r-- | src/mesa/main/mtypes.h | 35 | ||||
| -rw-r--r-- | src/mesa/main/transformfeedback.c | 474 | ||||
| -rw-r--r-- | src/mesa/main/transformfeedback.h | 31 | ||||
| -rw-r--r-- | src/mesa/shader/shader_api.c | 8 | ||||
| -rw-r--r-- | src/mesa/sources.mak | 1 | ||||
| -rw-r--r-- | src/mesa/state_tracker/st_cb_xformfb.c | 129 | ||||
| -rw-r--r-- | src/mesa/state_tracker/st_cb_xformfb.h | 36 | ||||
| -rw-r--r-- | src/mesa/state_tracker/st_context.c | 7 | 
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;  }  | 
