On Tue, 28 May 2013 12:30:56 -0700 Ian Romanick <i...@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); > > > _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev