mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-05-08 09:08:10 +02:00
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>
This commit is contained in:
parent
95426b28ac
commit
1c29068074
4 changed files with 203 additions and 3 deletions
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -2808,6 +2808,8 @@ struct gl_pipeline_object
|
|||
|
||||
GLboolean EverBound; /**< Has the pipeline object been created */
|
||||
|
||||
GLboolean Validated; /**< Pipeline Validation status */
|
||||
|
||||
GLchar *InfoLog;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
@ -608,12 +606,199 @@ _mesa_GetProgramPipelineiv(GLuint pipeline, GLenum pname, GLint *params)
|
|||
_mesa_lookup_enum_by_nr(pname));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue