[Mesa-dev] [PATCH 02/12] sso: Add pipeline container/state
Gregory Hainaut
gregory.hainaut at gmail.com
Fri May 3 10:44:06 PDT 2013
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
More information about the mesa-dev
mailing list