[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