summaryrefslogtreecommitdiffstats
path: root/src/mesa
diff options
context:
space:
mode:
authorGregory Hainaut <gregory.hainaut@gmail.com>2013-06-28 19:30:44 -0700
committerIan Romanick <ian.d.romanick@intel.com>2014-03-25 10:25:26 -0700
commit1c290680742ce5cb9a0a1019d0f971689335aabc (patch)
tree90f8a3574b4a87827373082ab741e11ecc977a83 /src/mesa
parent95426b28ac716dafff4c797f66949244896a94fd (diff)
mesa/sso: Implement ValidateProgramPipeline
Implementation note: I don't use context for ralloc (don't know how). The check on PROGRAM_SEPARABLE flags is also done when the pipeline isn't bound. It doesn't make any sense in a DSA style API. Maybe we could replace _mesa_validate_program by _mesa_validate_program_pipeline. For example we could recreate a dummy pipeline object. However the new function checks also the TEXTURE_IMAGE_UNIT number not sure of the impact. V2: Fix memory leak with ralloc_strdup Formatting improvement V3 (idr): * Actually fix the leak of the InfoLog. :) * Directly generate logs in to gl_pipeline_object::InfoLog via ralloc_asprintf isntead of using a temporary buffer. * Split out from previous uber patch. * Change spec references to include section numbers, etc. * Fix a bug in checking that a different program isn't active in a stage between two stages that have the same program. Specifically, if (pipe->CurrentVertexProgram->Name == pipe->CurrentGeometryProgram->Name && pipe->CurrentGeometryProgram->Name != pipe->CurrentVertexProgram->Name) should have been if (pipe->CurrentVertexProgram->Name == pipe->CurrentFragmentProgram->Name && pipe->CurrentGeometryProgram->Name != pipe->CurrentVertexProgram->Name) v4 (idr): Rework to use CurrentProgram array in loops. Reviewed-by: Ian Romanick <ian.d.romanick@intel.com> Reviewed-by: Eric Anholt <eric@anholt.net>
Diffstat (limited to 'src/mesa')
-rw-r--r--src/mesa/main/context.c10
-rw-r--r--src/mesa/main/mtypes.h2
-rw-r--r--src/mesa/main/pipelineobj.c191
-rw-r--r--src/mesa/main/pipelineobj.h3
4 files changed, 203 insertions, 3 deletions
diff --git a/src/mesa/main/context.c b/src/mesa/main/context.c
index 5d580fab786..860ae860531 100644
--- a/src/mesa/main/context.c
+++ b/src/mesa/main/context.c
@@ -1841,6 +1841,7 @@ shader_linked_or_absent(struct gl_context *ctx,
* Prior to drawing anything with glBegin, glDrawArrays, etc. this function
* is called to see if it's valid to render. This involves checking that
* the current shader is valid and the framebuffer is complete.
+ * It also check the current pipeline object is valid if any.
* If an error is detected it'll be recorded here.
* \return GL_TRUE if OK to render, GL_FALSE if not
*/
@@ -1892,6 +1893,15 @@ _mesa_valid_to_render(struct gl_context *ctx, const char *where)
}
}
+ /* A pipeline object is bound */
+ if (ctx->_Shader->Name && !ctx->_Shader->Validated) {
+ /* Error message will be printed inside _mesa_validate_program_pipeline.
+ */
+ if (!_mesa_validate_program_pipeline(ctx, ctx->_Shader, GL_TRUE)) {
+ return GL_FALSE;
+ }
+ }
+
if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
_mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
"%s(incomplete framebuffer)", where);
diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h
index c18ff1edab7..33cb8888136 100644
--- a/src/mesa/main/mtypes.h
+++ b/src/mesa/main/mtypes.h
@@ -2808,6 +2808,8 @@ struct gl_pipeline_object
GLboolean EverBound; /**< Has the pipeline object been created */
+ GLboolean Validated; /**< Pipeline Validation status */
+
GLchar *InfoLog;
};
diff --git a/src/mesa/main/pipelineobj.c b/src/mesa/main/pipelineobj.c
index 2d079cc7545..49fb64151a5 100644
--- a/src/mesa/main/pipelineobj.c
+++ b/src/mesa/main/pipelineobj.c
@@ -576,9 +576,7 @@ _mesa_GetProgramPipelineiv(GLuint pipeline, GLenum pname, GLint *params)
*params = pipe->InfoLog ? strlen(pipe->InfoLog) + 1 : 0;
return;
case GL_VALIDATE_STATUS:
- /* FINISHME: Implement validation status.
- */
- *params = 0;
+ *params = pipe->Validated;
return;
case GL_VERTEX_SHADER:
*params = pipe->CurrentProgram[MESA_SHADER_VERTEX]
@@ -609,11 +607,198 @@ _mesa_GetProgramPipelineiv(GLuint pipeline, GLenum pname, GLint *params)
}
/**
+ * Determines whether every stage in a linked program is active in the
+ * specified pipeline.
+ */
+static bool
+program_stages_all_active(struct gl_pipeline_object *pipe,
+ const struct gl_shader_program *prog)
+{
+ unsigned i;
+ bool status = true;
+
+ if (!prog)
+ return true;
+
+ for (i = 0; i < MESA_SHADER_STAGES; i++) {
+ if (prog->_LinkedShaders[i]) {
+ if (pipe->CurrentProgram[i]) {
+ if (prog->Name != pipe->CurrentProgram[i]->Name) {
+ status = false;
+ }
+ } else {
+ status = false;
+ }
+ }
+ }
+
+ if (!status) {
+ pipe->InfoLog = ralloc_asprintf(pipe,
+ "Program %d is not active for all "
+ "shaders that was linked",
+ prog->Name);
+ }
+
+ return status;
+}
+
+extern GLboolean
+_mesa_validate_program_pipeline(struct gl_context* ctx,
+ struct gl_pipeline_object *pipe,
+ GLboolean IsBound)
+{
+ unsigned i;
+
+ pipe->Validated = GL_FALSE;
+
+ /* Release and reset the info log.
+ */
+ if (pipe->InfoLog != NULL)
+ ralloc_free(pipe->InfoLog);
+
+ pipe->InfoLog = NULL;
+
+ /* Section 2.11.11 (Shader Execution), subheading "Validation," of the
+ * OpenGL 4.1 spec says:
+ *
+ * "[INVALID_OPERATION] is generated by any command that transfers
+ * vertices to the GL if:
+ *
+ * - A program object is active for at least one, but not all of
+ * the shader stages that were present when the program was
+ * linked."
+ *
+ * For each possible program stage, verify that the program bound to that
+ * stage has all of its stages active. In other words, if the program
+ * bound to the vertex stage also has a fragment shader, the fragment
+ * shader must also be bound to the fragment stage.
+ */
+ for (i = 0; i < MESA_SHADER_STAGES; i++) {
+ if (!program_stages_all_active(pipe, pipe->CurrentProgram[i])) {
+ goto err;
+ }
+ }
+
+ /* Section 2.11.11 (Shader Execution), subheading "Validation," of the
+ * OpenGL 4.1 spec says:
+ *
+ * "[INVALID_OPERATION] is generated by any command that transfers
+ * vertices to the GL if:
+ *
+ * ...
+ *
+ * - One program object is active for at least two shader stages
+ * and a second program is active for a shader stage between two
+ * stages for which the first program was active."
+ *
+ * Without Tesselation, the only case where this can occur is the geometry
+ * shader between the fragment shader and vertex shader.
+ */
+ if (pipe->CurrentProgram[MESA_SHADER_GEOMETRY]
+ && pipe->CurrentProgram[MESA_SHADER_FRAGMENT]
+ && pipe->CurrentProgram[MESA_SHADER_VERTEX]) {
+ if (pipe->CurrentProgram[MESA_SHADER_VERTEX]->Name == pipe->CurrentProgram[MESA_SHADER_FRAGMENT]->Name &&
+ pipe->CurrentProgram[MESA_SHADER_GEOMETRY]->Name != pipe->CurrentProgram[MESA_SHADER_VERTEX]->Name) {
+ pipe->InfoLog =
+ ralloc_asprintf(pipe,
+ "Program %d is active for geometry stage between "
+ "two stages for which another program %d is "
+ "active",
+ pipe->CurrentProgram[MESA_SHADER_GEOMETRY]->Name,
+ pipe->CurrentProgram[MESA_SHADER_VERTEX]->Name);
+ goto err;
+ }
+ }
+
+ /* Section 2.11.11 (Shader Execution), subheading "Validation," of the
+ * OpenGL 4.1 spec says:
+ *
+ * "[INVALID_OPERATION] is generated by any command that transfers
+ * vertices to the GL if:
+ *
+ * ...
+ *
+ * - There is an active program for tessellation control,
+ * tessellation evaluation, or geometry stages with corresponding
+ * executable shader, but there is no active program with
+ * executable vertex shader."
+ */
+ if (!pipe->CurrentProgram[MESA_SHADER_VERTEX]
+ && pipe->CurrentProgram[MESA_SHADER_GEOMETRY]) {
+ pipe->InfoLog = ralloc_strdup(pipe, "Program lacks a vertex shader");
+ goto err;
+ }
+
+ /* Section 2.11.11 (Shader Execution), subheading "Validation," of the
+ * OpenGL 4.1 spec says:
+ *
+ * "[INVALID_OPERATION] is generated by any command that transfers
+ * vertices to the GL if:
+ *
+ * ...
+ *
+ * - There is no current program object specified by UseProgram,
+ * there is a current program pipeline object, and the current
+ * program for any shader stage has been relinked since being
+ * applied to the pipeline object via UseProgramStages with the
+ * PROGRAM_SEPARABLE parameter set to FALSE.
+ */
+ for (i = 0; i < MESA_SHADER_STAGES; i++) {
+ if (pipe->CurrentProgram[i] && !pipe->CurrentProgram[i]->SeparateShader) {
+ pipe->InfoLog = ralloc_asprintf(pipe,
+ "Program %d was relinked without "
+ "PROGRAM_SEPARABLE state",
+ pipe->CurrentProgram[i]->Name);
+ goto err;
+ }
+ }
+
+ /* Section 2.11.11 (Shader Execution), subheading "Validation," of the
+ * OpenGL 4.1 spec says:
+ *
+ * "[INVALID_OPERATION] is generated by any command that transfers
+ * vertices to the GL if:
+ *
+ * ...
+ *
+ * - Any two active samplers in the current program object are of
+ * different types, but refer to the same texture image unit.
+ *
+ * - The number of active samplers in the program exceeds the
+ * maximum number of texture image units allowed."
+ */
+ if (!_mesa_sampler_uniforms_pipeline_are_valid(pipe))
+ goto err;
+
+ pipe->Validated = GL_TRUE;
+ return GL_TRUE;
+
+err:
+ if (IsBound)
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glValidateProgramPipeline failed to validate the pipeline");
+
+ return GL_FALSE;
+}
+
+/**
* Check compatibility of pipeline's program
*/
void GLAPIENTRY
_mesa_ValidateProgramPipeline(GLuint pipeline)
{
+ GET_CURRENT_CONTEXT(ctx);
+
+ struct gl_pipeline_object *pipe = lookup_pipeline_object(ctx, pipeline);
+
+ if (!pipe) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glValidateProgramPipeline(pipeline)");
+ return;
+ }
+
+ _mesa_validate_program_pipeline(ctx, pipe,
+ (ctx->_Shader->Name == pipe->Name));
}
void GLAPIENTRY
diff --git a/src/mesa/main/pipelineobj.h b/src/mesa/main/pipelineobj.h
index 46d5fab4230..ceaf4f14ce9 100644
--- a/src/mesa/main/pipelineobj.h
+++ b/src/mesa/main/pipelineobj.h
@@ -59,6 +59,9 @@ _mesa_reference_pipeline_object(struct gl_context *ctx,
_mesa_reference_pipeline_object_(ctx, ptr, obj);
}
+extern GLboolean
+_mesa_validate_program_pipeline(struct gl_context * ctx, struct gl_pipeline_object *pipe, GLboolean IsBound);
+
extern void GLAPIENTRY
_mesa_UseProgramStages(GLuint pipeline, GLbitfield stages, GLuint program);