[Mesa-dev] [PATCH 02/12] sso: Add pipeline container/state

gregory hainaut gregory.hainaut at gmail.com
Tue May 28 14:05:33 PDT 2013


On Tue, 28 May 2013 12:30:56 -0700
Ian Romanick <idr at freedesktop.org> wrote:

> On 05/03/2013 10:44 AM, Gregory Hainaut wrote:
> > V1:
> > * Extend gl_shader_state as pipeline object state
> > * Add a new container gl_pipeline_shader_state that contains
> >    binding point of the previous object
> > * Update mesa init/free shader state due to the extension of
> >    the attibute
> > * Add an init/free pipeline function for the context
> > * Implement GenProgramPipeline/DeleteProgramPipeline/IsProgramPipeline.
> >   I based my work on the VAO code.
> >
> > V2:
> > * Rename gl_shader_state to gl_pipeline_object
> > * Rename Pipeline.PipelineObj to Pipeline.Current
> > * Rename ValidationStatus to Validated
> > * Formatting improvement
> > ---
> >   src/mesa/main/context.c     |    3 +
> >   src/mesa/main/mtypes.h      |   30 +++++-
> >   src/mesa/main/pipelineobj.c |  234 ++++++++++++++++++++++++++++++++++++++++++-
> >   src/mesa/main/pipelineobj.h |   25 +++++
> >   src/mesa/main/shaderapi.c   |   14 ++-
> >   src/mesa/main/shaderapi.h   |    3 +
> >   6 files changed, 303 insertions(+), 6 deletions(-)
> >
> > diff --git a/src/mesa/main/context.c b/src/mesa/main/context.c
> > index 0539934..d089827 100644
> > --- a/src/mesa/main/context.c
> > +++ b/src/mesa/main/context.c
> > @@ -106,6 +106,7 @@
> >   #include "macros.h"
> >   #include "matrix.h"
> >   #include "multisample.h"
> > +#include "pipelineobj.h"
> >   #include "pixel.h"
> >   #include "pixelstore.h"
> >   #include "points.h"
> > @@ -762,6 +763,7 @@ init_attrib_groups(struct gl_context *ctx)
> >      _mesa_init_lighting( ctx );
> >      _mesa_init_matrix( ctx );
> >      _mesa_init_multisample( ctx );
> > +   _mesa_init_pipeline( ctx );
> >      _mesa_init_pixel( ctx );
> >      _mesa_init_pixelstore( ctx );
> >      _mesa_init_point( ctx );
> > @@ -1167,6 +1169,7 @@ _mesa_free_context_data( struct gl_context *ctx )
> >      _mesa_free_texture_data( ctx );
> >      _mesa_free_matrix_data( ctx );
> >      _mesa_free_viewport_data( ctx );
> > +   _mesa_free_pipeline_data(ctx);
> >      _mesa_free_program_data(ctx);
> >      _mesa_free_shader_state(ctx);
> >      _mesa_free_queryobj_data(ctx);
> > diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h
> > index 05d8518..4487068 100644
> > --- a/src/mesa/main/mtypes.h
> > +++ b/src/mesa/main/mtypes.h
> > @@ -2381,9 +2381,19 @@ struct gl_shader_program
> >
> >   /**
> >    * Context state for GLSL vertex/fragment shaders.
> > + * Extended to support pipeline object
> >    */
> > -struct gl_shader_state
> > +struct gl_pipeline_object
> >   {
> > +   /** Name of the pipeline object as received from glGenProgramPipelines.
> > +    * It would be 0 for shaders without separate shader objects.
> > +    */
> > +   GLuint Name;
> > +
> > +   GLint RefCount;
> > +
> > +   _glthread_Mutex Mutex;
> > +
> >      /**
> >       * Programs used for rendering
> >       *
> 
> I think this comment needs to be updated.  The rest of it says
> 
>      *
>      * There is a separate program set for each shader stage.  If
>      * GL_EXT_separate_shader_objects is not supported, each of these 
> must point
>      * to \c NULL or to the same program.
>      */
> 
> However, I think the shader stages can only point to different programs 
> for the default pipeline object (gl_pipeline_object::Name == 0).  Right?
Hum no it is more complicated.

When gl_pipeline_object::Name != 0, you can put any program on shader stage.

When gl_pipeline_object::Name == 0, there is the 2 possibilities
0/ GL_EXT_separate_shader_objects is not supported. All program must be the same.
1/ GL_EXT_separate_shader_objects is supported. You can set different program.
 
> > @@ -2405,8 +2415,23 @@ struct gl_shader_state
> >      struct gl_shader_program *ActiveProgram;
> >
> >      GLbitfield Flags;                    /**< Mask of GLSL_x flags */
> > +
> > +   GLboolean Validated;                 /**< Pipeline Validation status */
> > +
> > +   GLboolean EverBound;                 /**< Has the pipeline object been created */
> >   };
> >
> > +/**
> > + * Context state for GLSL pipeline shaders.
> > + */
> > +struct gl_pipeline_shader_state
> > +{
> > +   /** Currently bound pipeline object. See _mesa_BindProgramPipeline() */
> > +   struct gl_pipeline_object *Current;
> > +
> > +   /** Pipeline objects */
> > +   struct _mesa_HashTable *Objects;
> > +};
> >
> >   /**
> >    * Compiler options for a single GLSL shaders type
> > @@ -3514,7 +3539,8 @@ struct gl_context
> >      struct gl_geometry_program_state GeometryProgram;
> >      struct gl_ati_fragment_shader_state ATIFragmentShader;
> >
> > -   struct gl_shader_state Shader; /**< GLSL shader object state */
> > +   struct gl_pipeline_shader_state Pipeline; /**< GLSL pipeline shader object state */
> > +   struct gl_pipeline_object Shader; /**< GLSL shader object state */
> >      struct gl_shader_compiler_options ShaderCompilerOptions[MESA_SHADER_TYPES];
> >
> >      struct gl_query_state Query;  /**< occlusion, timer queries */
> > diff --git a/src/mesa/main/pipelineobj.c b/src/mesa/main/pipelineobj.c
> > index e7e628b..d81bd0e 100644
> > --- a/src/mesa/main/pipelineobj.c
> > +++ b/src/mesa/main/pipelineobj.c
> > @@ -30,6 +30,9 @@
> >    * Implementation of pipeline object related API functions. Based on
> >    * GL_ARB_separate_shader_objects extension.
> >    *
> > + * XXX things to do:
> > + * 1/ Do we need to create 2 new drivers functions: CreatePipelineObject
> > + * DeletePipelineObject
> >    */
> >
> >   #include "main/glheader.h"
> > @@ -51,6 +54,168 @@
> >   #include "../glsl/glsl_parser_extras.h"
> >   #include "../glsl/ir_uniform.h"
> >
> > +/**
> > + * Delete a pipeline object.
> > + */
> > +void
> > +_mesa_delete_pipeline_object(struct gl_context *ctx, struct gl_pipeline_object *obj)
> > +{
> > +   _mesa_reference_shader_program(ctx, &obj->_CurrentFragmentProgram, NULL);
> > +   _mesa_reference_shader_program(ctx, &obj->CurrentFragmentProgram, NULL);
> > +   _mesa_reference_shader_program(ctx, &obj->CurrentVertexProgram, NULL);
> > +   _mesa_reference_shader_program(ctx, &obj->CurrentGeometryProgram, NULL);
> > +   _mesa_reference_shader_program(ctx, &obj->ActiveProgram, NULL);
> > +   _glthread_DESTROY_MUTEX(obj->Mutex);
> > +   ralloc_free(obj);
> > +}
> > +
> > +/**
> > + * Allocate and initialize a new pipeline object.
> > + */
> > +static struct gl_pipeline_object *
> > +_mesa_new_pipeline_object(struct gl_context *ctx, GLuint name)
> > +{
> > +   struct gl_pipeline_object *obj = rzalloc(NULL, struct gl_pipeline_object);
> > +   if (obj) {
> > +      obj->Name = name;
> > +      _glthread_INIT_MUTEX(obj->Mutex);
> > +      obj->RefCount = 1;
> > +      obj->Flags = _mesa_get_shader_flags();
> > +   }
> > +
> > +   return obj;
> > +}
> > +
> > +/**
> > + * Initialize pipeline object state for given context.
> > + */
> > +void
> > +_mesa_init_pipeline(struct gl_context *ctx)
> > +{
> > +   ctx->Pipeline.Objects = _mesa_NewHashTable();
> > +
> > +   ctx->Pipeline.Current = NULL;
> > +}
> > +
> > +
> > +/**
> > + * Callback for deleting a pipeline object.  Called by _mesa_HashDeleteAll().
> > + */
> > +static void
> > +delete_pipelineobj_cb(GLuint id, void *data, void *userData)
> > +{
> > +   struct gl_pipeline_object *obj = (struct gl_pipeline_object *) data;
> > +   struct gl_context *ctx = (struct gl_context *) userData;
> > +   _mesa_delete_pipeline_object(ctx, obj);
> > +}
> > +
> > +
> > +/**
> > + * Free pipeline state for given context.
> > + */
> > +void
> > +_mesa_free_pipeline_data(struct gl_context *ctx)
> > +{
> > +   _mesa_HashDeleteAll(ctx->Pipeline.Objects, delete_pipelineobj_cb, ctx);
> > +   _mesa_DeleteHashTable(ctx->Pipeline.Objects);
> > +}
> > +
> > +/**
> > + * Look up the pipeline object for the given ID.
> > + *
> > + * \returns
> > + * Either a pointer to the pipeline object with the specified ID or \c NULL for
> > + * a non-existent ID.  The spec defines ID 0 as being technically
> > + * non-existent.
> > + */
> > +static inline struct gl_pipeline_object *
> > +lookup_pipeline_object(struct gl_context *ctx, GLuint id)
> > +{
> > +   if (id == 0)
> > +      return NULL;
> > +   else
> > +      return (struct gl_pipeline_object *)
> > +         _mesa_HashLookup(ctx->Pipeline.Objects, id);
> > +}
> > +
> > +/**
> > + * Add the given pipeline object to the pipeline object pool.
> > + */
> > +static void
> > +save_pipeline_object(struct gl_context *ctx, struct gl_pipeline_object *obj)
> > +{
> > +   if (obj->Name > 0) {
> > +      _mesa_HashInsert(ctx->Pipeline.Objects, obj->Name, obj);
> > +   }
> > +}
> > +
> > +/**
> > + * Remove the given pipeline object from the pipeline object pool.
> > + * Do not deallocate the pipeline object though.
> > + */
> > +static void
> > +remove_pipeline_object(struct gl_context *ctx, struct gl_pipeline_object *obj)
> > +{
> > +   if (obj->Name > 0) {
> > +      _mesa_HashRemove(ctx->Pipeline.Objects, obj->Name);
> > +   }
> > +}
> > +
> > +/**
> > + * Set ptr to obj w/ reference counting.
> > + * Note: this should only be called from the _mesa_reference_pipeline_object()
> > + * inline function.
> > + */
> > +void
> > +_mesa_reference_pipeline_object_(struct gl_context *ctx,
> > +                                 struct gl_pipeline_object **ptr,
> > +                                 struct gl_pipeline_object *obj)
> > +{
> > +   assert(*ptr != obj);
> > +
> > +   if (*ptr) {
> > +      /* Unreference the old pipeline object */
> > +      GLboolean deleteFlag = GL_FALSE;
> > +      struct gl_pipeline_object *oldObj = *ptr;
> > +
> > +      _glthread_LOCK_MUTEX(oldObj->Mutex);
> > +      ASSERT(oldObj->RefCount > 0);
> > +      oldObj->RefCount--;
> > +#if 0
> > +      printf("obj %p %d DECR to %d\n",
> > +            (void *) oldObj, oldObj->Name, oldObj->RefCount);
> > +#endif
> 
> Should either delete these left over debug messages or protect them with 
> an existing Mesa debug flag.
> 
> > +      deleteFlag = (oldObj->RefCount == 0);
> > +      _glthread_UNLOCK_MUTEX(oldObj->Mutex);
> > +
> > +      if (deleteFlag) {
> > +         _mesa_delete_pipeline_object(ctx, oldObj);
> > +      }
> > +
> > +      *ptr = NULL;
> > +   }
> > +   ASSERT(!*ptr);
> > +
> > +   if (obj) {
> > +      /* reference new pipeline object */
> > +      _glthread_LOCK_MUTEX(obj->Mutex);
> > +      if (obj->RefCount == 0) {
> > +         /* this pipeline's being deleted (look just above) */
> > +         /* Not sure this can every really happen.  Warn if it does. */
> > +         _mesa_problem(NULL, "referencing deleted pipeline object");
> > +         *ptr = NULL;
> > +      }
> > +      else {
> > +         obj->RefCount++;
> > +#if 0
> > +         printf("obj %p %d INCR to %d\n",
> > +               (void *) obj, obj->Name, obj->RefCount);
> > +#endif
> > +         *ptr = obj;
> > +      }
> > +      _glthread_UNLOCK_MUTEX(obj->Mutex);
> > +   }
> > +}
> >
> >   /**
> >    * Bound program to severals stages of the pipeline
> > @@ -85,6 +250,37 @@ _mesa_BindProgramPipeline(GLuint pipeline)
> >   void GLAPIENTRY
> >   _mesa_DeleteProgramPipelines(GLsizei n, const GLuint *pipelines)
> >   {
> > +   GET_CURRENT_CONTEXT(ctx);
> > +   GLsizei i;
> > +
> > +   if (n < 0) {
> > +      _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteProgramPipelines(n<0)");
> > +      return;
> > +   }
> > +
> > +   for (i = 0; i < n; i++) {
> > +      struct gl_pipeline_object *obj = lookup_pipeline_object(ctx, pipelines[i]);
> > +
> > +      if (obj) {
> > +         ASSERT(obj->Name == pipelines[i]);
> > +
> > +         /* If the pipeline object is currently bound, the spec says "If an object that is
> > +          * currently bound is deleted, the binding for that object
> > +          * reverts to zero and no program pipeline object becomes current."
> > +          */
> > +         if (obj == ctx->Pipeline.Current) {
> > +            _mesa_BindProgramPipeline(0);
> > +         }
> > +
> > +         /* The ID is immediately freed for re-use */
> > +         remove_pipeline_object(ctx, obj);
> > +
> > +         /* Unreference the pipeline object.
> > +          * If refcount hits zero, the object will be deleted.
> > +          */
> > +         _mesa_reference_pipeline_object(ctx, &obj, NULL);
> > +      }
> > +   }
> >   }
> >
> >   /**
> > @@ -95,6 +291,36 @@ _mesa_DeleteProgramPipelines(GLsizei n, const GLuint *pipelines)
> >   void GLAPIENTRY
> >   _mesa_GenProgramPipelines(GLsizei n, GLuint *pipelines)
> >   {
> > +   GET_CURRENT_CONTEXT(ctx);
> > +
> > +   GLuint first;
> > +   GLint i;
> > +
> > +   if (n < 0) {
> > +      _mesa_error(ctx, GL_INVALID_VALUE, "glGenProgramPipelines(n<0)");
> > +      return;
> > +   }
> > +
> > +   if (!pipelines) {
> > +      return;
> > +   }
> > +
> > +   first = _mesa_HashFindFreeKeyBlock(ctx->Pipeline.Objects, n);
> > +
> > +   for (i = 0; i < n; i++) {
> > +      struct gl_pipeline_object *obj;
> > +      GLuint name = first + i;
> > +
> > +      obj = _mesa_new_pipeline_object(ctx, name);
> > +      if (!obj) {
> > +         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenProgramPipelines");
> > +         return;
> > +      }
> > +
> > +      save_pipeline_object(ctx, obj);
> > +      pipelines[i] = first + i;
> > +   }
> > +
> >   }
> >
> >   /**
> > @@ -107,7 +333,13 @@ _mesa_GenProgramPipelines(GLsizei n, GLuint *pipelines)
> >   GLboolean GLAPIENTRY
> >   _mesa_IsProgramPipeline(GLuint pipeline)
> >   {
> > -   return GL_FALSE;
> > +   GET_CURRENT_CONTEXT(ctx);
> > +
> > +   struct gl_pipeline_object *obj = lookup_pipeline_object(ctx, pipeline);
> > +   if (obj == NULL)
> > +      return GL_FALSE;
> > +
> > +   return obj->EverBound;
> >   }
> >
> >   /**
> > diff --git a/src/mesa/main/pipelineobj.h b/src/mesa/main/pipelineobj.h
> > index d0301fe..8a38aab 100644
> > --- a/src/mesa/main/pipelineobj.h
> > +++ b/src/mesa/main/pipelineobj.h
> > @@ -37,6 +37,31 @@ extern "C" {
> >
> >   struct _glapi_table;
> >   struct gl_context;
> > +struct gl_pipeline_object;
> > +
> > +extern void
> > +_mesa_delete_pipeline_object(struct gl_context *ctx, struct gl_pipeline_object *obj);
> > +
> > +extern void
> > +_mesa_init_pipeline(struct gl_context *ctx);
> > +
> > +extern void
> > +_mesa_free_pipeline_data(struct gl_context *ctx);
> > +
> > +extern void
> > +_mesa_reference_pipeline_object_(struct gl_context *ctx,
> > +                                 struct gl_pipeline_object **ptr,
> > +                                 struct gl_pipeline_object *obj);
> > +
> > +static inline void
> > +_mesa_reference_pipeline_object(struct gl_context *ctx,
> > +                                struct gl_pipeline_object **ptr,
> > +                                struct gl_pipeline_object *obj)
> > +{
> > +   if (*ptr != obj)
> > +      _mesa_reference_pipeline_object_(ctx, ptr, obj);
> > +}
> > +
> >
> >   extern void GLAPIENTRY
> >   _mesa_UseProgramStages(GLuint pipeline, GLbitfield stages, GLuint program);
> > diff --git a/src/mesa/main/shaderapi.c b/src/mesa/main/shaderapi.c
> > index f4c2482..774163d 100644
> > --- a/src/mesa/main/shaderapi.c
> > +++ b/src/mesa/main/shaderapi.c
> > @@ -61,8 +61,8 @@
> >   /**
> >    * Return mask of GLSL_x flags by examining the MESA_GLSL env var.
> >    */
> > -static GLbitfield
> > -get_shader_flags(void)
> > +GLbitfield
> > +_mesa_get_shader_flags(void)
> >   {
> >      GLbitfield flags = 0x0;
> >      const char *env = _mesa_getenv("MESA_GLSL");
> > @@ -114,7 +114,11 @@ _mesa_init_shader_state(struct gl_context *ctx)
> >      for (sh = 0; sh < MESA_SHADER_TYPES; ++sh)
> >         memcpy(&ctx->ShaderCompilerOptions[sh], &options, sizeof(options));
> >
> > -   ctx->Shader.Flags = get_shader_flags();
> > +   ctx->Shader.Flags = _mesa_get_shader_flags();
> > +
> > +   /* Extended for ARB_separate_shader_objects */
> > +   ctx->Shader.RefCount = 1;
> > +   _glthread_INIT_MUTEX(ctx->Shader.Mutex);
> >   }
> >
> >
> > @@ -132,6 +136,10 @@ _mesa_free_shader_state(struct gl_context *ctx)
> >      _mesa_reference_shader_program(ctx, &ctx->Shader._CurrentFragmentProgram,
> >   				  NULL);
> >      _mesa_reference_shader_program(ctx, &ctx->Shader.ActiveProgram, NULL);
> > +
> > +   /* Extended for ARB_separate_shader_objects */
> > +   assert(ctx->Shader.RefCount == 1);
> > +   _glthread_DESTROY_MUTEX(ctx->Shader.Mutex);
> >   }
> >
> >
> > diff --git a/src/mesa/main/shaderapi.h b/src/mesa/main/shaderapi.h
> > index e0bd77d..4381703 100644
> > --- a/src/mesa/main/shaderapi.h
> > +++ b/src/mesa/main/shaderapi.h
> > @@ -39,6 +39,9 @@ struct _glapi_table;
> >   struct gl_context;
> >   struct gl_shader_program;
> >
> > +extern GLbitfield
> > +_mesa_get_shader_flags(void);
> > +
> >   extern void
> >   _mesa_copy_string(GLchar *dst, GLsizei maxLength,
> >                     GLsizei *length, const GLchar *src);
> >
> 


More information about the mesa-dev mailing list