[Mesa-dev] [PATCH 08/12] sso: Implement _mesa_UseProgramStages

Gregory Hainaut gregory.hainaut at gmail.com
Fri May 3 10:44:12 PDT 2013


Implement _mesa_UseProgramStages => arb_separate_shader_object-GetProgramPipelineiv is now pass :)

Extend use_shader_program to support a different target. Allow to reuse the function to update
the pipeline state. Note I bypass the flush when target isn't current. Maybe it would be better to
create a new UseProgramStages driver function

V2: formatting & rename
---
 src/mesa/main/pipelineobj.c |  111 +++++++++++++++++++++++++++++++++++++++++++
 src/mesa/main/shaderapi.c   |   32 +++++++------
 src/mesa/main/shaderapi.h   |    3 +-
 3 files changed, 131 insertions(+), 15 deletions(-)

diff --git a/src/mesa/main/pipelineobj.c b/src/mesa/main/pipelineobj.c
index 5add307..3cdca63 100644
--- a/src/mesa/main/pipelineobj.c
+++ b/src/mesa/main/pipelineobj.c
@@ -33,6 +33,8 @@
  * XXX things to do:
  * 1/ Do we need to create 2 new drivers functions: CreatePipelineObject
  * DeletePipelineObject
+ * 2/ We probably need a UseProgramStages driver function. It would avoir to
+ * dirty all stages
  */
 
 #include "main/glheader.h"
@@ -231,6 +233,115 @@ _mesa_reference_pipeline_object_(struct gl_context *ctx,
 void GLAPIENTRY
 _mesa_UseProgramStages(GLuint pipeline, GLbitfield stages, GLuint program)
 {
+   GET_CURRENT_CONTEXT(ctx);
+
+   struct gl_pipeline_object *pipe = lookup_pipeline_object(ctx, pipeline);
+   struct gl_shader_program *shProg = NULL;
+
+   if (!pipe) {
+      _mesa_error(ctx, GL_INVALID_OPERATION, "glUseProgramStages(pipeline)");
+      return;
+   }
+
+   /* Object is created by any Pipeline call but glGenProgramPipelines,
+    * glIsProgramPipeline and GetProgramPipelineInfoLog
+    */
+   pipe->EverBound = GL_TRUE;
+
+   /* NOT YET SUPPORTED:
+    * GL_TESS_CONTROL_SHADER_BIT
+    * GL_TESS_EVALUATION_SHADER_BIT
+    * GL_COMPUTE_SHADER_BIT
+    */
+   GLbitfield any_valid_stages = GL_VERTEX_SHADER_BIT | GL_FRAGMENT_SHADER_BIT;
+   if (_mesa_is_desktop_gl(ctx) && ctx->Extensions.ARB_geometry_shader4)
+      any_valid_stages |= GL_GEOMETRY_SHADER_BIT;
+
+   if (stages != GL_ALL_SHADER_BITS && (stages  & ~any_valid_stages) != 0) {
+      _mesa_error(ctx, GL_INVALID_VALUE, "glUseProgramStages(Stages)");
+      return;
+   }
+
+   /*
+    *  An INVALID_OPERATION error is generated :
+    *  by UseProgramStages if the program pipeline object it refers to is current
+    *  and the current transform feedback object is active and not paused;
+    */
+   /*
+    * 6a. Should the fragment shader program object be allowed to changed
+    * within transform feedback mode?
+    * RESOLVED:  No, this should generate an GL_INVALID_OPERATION error.
+    */
+   if (ctx->_Shader == pipe) {
+      if (_mesa_is_xfb_active_and_unpaused(ctx)) {
+         _mesa_error(ctx, GL_INVALID_OPERATION,
+               "glUseProgramStages(transform feedback active)");
+         return;
+      }
+   }
+
+   if (program) {
+      /* An INVALID_OPERATION error is generated if program is the name of a
+       * shader object
+       */
+      struct gl_shader *sh = _mesa_lookup_shader(ctx, program);
+      if (sh != NULL) {
+         _mesa_error(ctx, GL_INVALID_OPERATION,
+               "glUseProgramStages(progam is a shader object)");
+         return;
+      }
+
+      /* An INVALID_VALUE error is generated if program is not the name of ei-
+       * ther a program or shader object
+       */
+      shProg = _mesa_lookup_shader_program(ctx, program);
+      if (shProg == NULL) {
+         _mesa_error(ctx, GL_INVALID_VALUE,
+               "glUseProgramStages(progam is not a program object)");
+         return;
+      }
+
+      /* An INVALID_OPERATION error is generated if the program object named
+       * by program was linked without the PROGRAM_SEPARABLE parameter set, has
+       * not been linked, or was last linked unsuccessfully. The corresponding shader
+       * stages in pipeline are not modified.
+       */
+      if (!shProg->LinkStatus) {
+         _mesa_error(ctx, GL_INVALID_OPERATION,
+               "glUseProgramStages(program not linked)");
+         return;
+      }
+      if (!shProg->SeparateShader) {
+         _mesa_error(ctx, GL_INVALID_OPERATION,
+               "glUseProgramStages(program wasn't linked with the PROGRAM_SEPARABLE flag)");
+         return;
+      }
+   }
+
+   /*
+    *  7.  What happens if you have a program object current for a shader stage,
+    *    but the program object doesn't contain an executable for that stage?
+
+    *    RESOLVED:  This is not an error; instead it is as though there were no
+    *    program bound to that stage.  We have two different notions for
+    *    programs bound to shader stages.  A program is "current" for a stage
+    *    if it bound to that stage in the active program pipeline object.  A
+    *    program is "active" for a stage if it is current and it has an
+    *    executable for this stage.  In this case, the program would be current
+    *    but not active.
+
+    *    When no program is active for a stage, the stage will be replaced with
+    *    fixed functionality logic (compatibility profile vertex and fragment),
+    *    disabled (tessellation control and evaluation, geometry), or have
+    *    undefined results (core profile vertex and fragment).
+    */
+
+   if (stages & GL_VERTEX_SHADER_BIT)
+      _mesa_use_shader_program(ctx, GL_VERTEX_SHADER, shProg, pipe);
+   if (stages & GL_FRAGMENT_SHADER_BIT)
+      _mesa_use_shader_program(ctx, GL_FRAGMENT_SHADER, shProg, pipe);
+   if (stages & GL_GEOMETRY_SHADER_BIT)
+      _mesa_use_shader_program(ctx, GL_GEOMETRY_SHADER_ARB, shProg, pipe);
 }
 
 /**
diff --git a/src/mesa/main/shaderapi.c b/src/mesa/main/shaderapi.c
index c82eba8..facb83a 100644
--- a/src/mesa/main/shaderapi.c
+++ b/src/mesa/main/shaderapi.c
@@ -882,40 +882,44 @@ _mesa_active_program(struct gl_context *ctx, struct gl_shader_program *shProg,
 
 /**
  */
-static bool
+static void
 use_shader_program(struct gl_context *ctx, GLenum type,
-		   struct gl_shader_program *shProg)
+                   struct gl_shader_program *shProg,
+                   struct gl_pipeline_object *shTarget)
 {
    struct gl_shader_program **target;
 
    switch (type) {
    case GL_VERTEX_SHADER:
-      target = &ctx->_Shader->CurrentVertexProgram;
+      target = &shTarget->CurrentVertexProgram;
       if ((shProg == NULL)
 	  || (shProg->_LinkedShaders[MESA_SHADER_VERTEX] == NULL)) {
 	 shProg = NULL;
       }
       break;
    case GL_GEOMETRY_SHADER_ARB:
-      target = &ctx->_Shader->CurrentGeometryProgram;
+      target = &shTarget->CurrentGeometryProgram;
       if ((shProg == NULL)
 	  || (shProg->_LinkedShaders[MESA_SHADER_GEOMETRY] == NULL)) {
 	 shProg = NULL;
       }
       break;
    case GL_FRAGMENT_SHADER:
-      target = &ctx->_Shader->CurrentFragmentProgram;
+      target = &shTarget->CurrentFragmentProgram;
       if ((shProg == NULL)
 	  || (shProg->_LinkedShaders[MESA_SHADER_FRAGMENT] == NULL)) {
 	 shProg = NULL;
       }
       break;
    default:
-      return false;
+      return;
    }
 
    if (*target != shProg) {
-      FLUSH_VERTICES(ctx, _NEW_PROGRAM | _NEW_PROGRAM_CONSTANTS);
+      /* Program is current, flush it */
+      if (shTarget == ctx->_Shader) {
+         FLUSH_VERTICES(ctx, _NEW_PROGRAM | _NEW_PROGRAM_CONSTANTS);
+      }
 
       /* If the shader is also bound as the current rendering shader, unbind
        * it from that binding point as well.  This ensures that the correct
@@ -938,10 +942,10 @@ use_shader_program(struct gl_context *ctx, GLenum type,
       }
 
       _mesa_reference_shader_program(ctx, target, shProg);
-      return true;
+      return;
    }
 
-   return false;
+   return;
 }
 
 /**
@@ -950,9 +954,9 @@ use_shader_program(struct gl_context *ctx, GLenum type,
 void
 _mesa_use_program(struct gl_context *ctx, struct gl_shader_program *shProg)
 {
-   use_shader_program(ctx, GL_VERTEX_SHADER, shProg);
-   use_shader_program(ctx, GL_GEOMETRY_SHADER_ARB, shProg);
-   use_shader_program(ctx, GL_FRAGMENT_SHADER, shProg);
+   use_shader_program(ctx, GL_VERTEX_SHADER, shProg, &ctx->Shader);
+   use_shader_program(ctx, GL_GEOMETRY_SHADER_ARB, shProg, &ctx->Shader);
+   use_shader_program(ctx, GL_FRAGMENT_SHADER, shProg, &ctx->Shader);
    _mesa_active_program(ctx, shProg, "glUseProgram");
 
    if (ctx->Driver.UseProgram)
@@ -1761,9 +1765,9 @@ _mesa_ProgramParameteri(GLuint program, GLenum pname, GLint value)
 
 void
 _mesa_use_shader_program(struct gl_context *ctx, GLenum type,
-			 struct gl_shader_program *shProg)
+			 struct gl_shader_program *shProg, struct gl_pipeline_object *shTarget)
 {
-   use_shader_program(ctx, type, shProg);
+   use_shader_program(ctx, type, shProg, shTarget);
 
    if (ctx->Driver.UseProgram)
       ctx->Driver.UseProgram(ctx, shProg);
diff --git a/src/mesa/main/shaderapi.h b/src/mesa/main/shaderapi.h
index d9b3809..94bef14 100644
--- a/src/mesa/main/shaderapi.h
+++ b/src/mesa/main/shaderapi.h
@@ -201,7 +201,8 @@ _mesa_ProgramParameteri(GLuint program, GLenum pname, GLint value);
 
 void
 _mesa_use_shader_program(struct gl_context *ctx, GLenum type,
-			 struct gl_shader_program *shProg);
+			 struct gl_shader_program *shProg,
+                         struct gl_pipeline_object *shTarget);
 
 extern void GLAPIENTRY
 _mesa_UseShaderProgramEXT(GLenum type, GLuint program);
-- 
1.7.10.4



More information about the mesa-dev mailing list