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 * @@ -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 + 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); -- 1.7.10.4 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev