diff options
Diffstat (limited to 'src/mesa/main/program_resource.c')
-rw-r--r-- | src/mesa/main/program_resource.c | 141 |
1 files changed, 118 insertions, 23 deletions
diff --git a/src/mesa/main/program_resource.c b/src/mesa/main/program_resource.c index f2a9f006dd8..6ddbdad997f 100644 --- a/src/mesa/main/program_resource.c +++ b/src/mesa/main/program_resource.c @@ -66,6 +66,79 @@ supported_interface_enum(struct gl_context *ctx, GLenum iface) } } +static struct gl_shader_program * +lookup_linked_program(GLuint program, + const char *caller, + bool raise_link_error) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_shader_program *prog = + _mesa_lookup_shader_program_err(ctx, program, caller); + + if (!prog) + return NULL; + + if (prog->LinkStatus == GL_FALSE) { + if (raise_link_error) + _mesa_error(ctx, GL_INVALID_OPERATION, "%s(program not linked)", + caller); + return NULL; + } + return prog; +} + +static GLenum +stage_from_program_interface(GLenum programInterface) +{ + switch(programInterface) { + case GL_VERTEX_SUBROUTINE_UNIFORM: + return MESA_SHADER_VERTEX; + case GL_TESS_CONTROL_SUBROUTINE_UNIFORM: + return MESA_SHADER_TESS_CTRL; + case GL_TESS_EVALUATION_SUBROUTINE_UNIFORM: + return MESA_SHADER_TESS_EVAL; + case GL_GEOMETRY_SUBROUTINE_UNIFORM: + return MESA_SHADER_GEOMETRY; + case GL_FRAGMENT_SUBROUTINE_UNIFORM: + return MESA_SHADER_FRAGMENT; + case GL_COMPUTE_SUBROUTINE_UNIFORM: + return MESA_SHADER_COMPUTE; + default: + assert(!"unexpected programInterface value"); + } +} + +static struct gl_linked_shader * +lookup_linked_shader(GLuint program, + GLenum programInterface, + const char *caller) +{ + struct gl_shader_program *shLinkedProg = + lookup_linked_program(program, caller, false); + gl_shader_stage stage = stage_from_program_interface(programInterface); + + if (!shLinkedProg) + return NULL; + + return shLinkedProg->_LinkedShaders[stage]; +} + +static bool +is_subroutine_uniform_program_interface(GLenum programInterface) +{ + switch(programInterface) { + case GL_VERTEX_SUBROUTINE_UNIFORM: + case GL_TESS_CONTROL_SUBROUTINE_UNIFORM: + case GL_TESS_EVALUATION_SUBROUTINE_UNIFORM: + case GL_GEOMETRY_SUBROUTINE_UNIFORM: + case GL_FRAGMENT_SUBROUTINE_UNIFORM: + case GL_COMPUTE_SUBROUTINE_UNIFORM: + return true; + default: + return false; + } +} + void GLAPIENTRY _mesa_GetProgramInterfaceiv(GLuint program, GLenum programInterface, GLenum pname, GLint *params) @@ -101,9 +174,49 @@ _mesa_GetProgramInterfaceiv(GLuint program, GLenum programInterface, /* Validate pname against interface. */ switch(pname) { case GL_ACTIVE_RESOURCES: - for (i = 0, *params = 0; i < shProg->NumProgramResourceList; i++) - if (shProg->ProgramResourceList[i].Type == programInterface) - (*params)++; + if (is_subroutine_uniform_program_interface(programInterface)) { + /* ARB_program_interface_query doesn't explicitly says that those + * uniforms would need a linked shader, or that should fail if it is + * not the case, but Section 7.6 (Uniform Variables) of the OpenGL + * 4.4 Core Profile says: + * + * "A uniform is considered an active uniform if the compiler and + * linker determine that the uniform will actually be accessed + * when the executable code is executed. In cases where the + * compiler and linker cannot make a conclusive determination, + * the uniform will be considered active." + * + * So in order to know the real number of active subroutine uniforms + * we would need a linked shader . + * + * At the same time, Section 7.3 (Program Objects) of the OpenGL 4.4 + * Core Profile says: + * + * "The GL provides various commands allowing applications to + * enumerate and query properties of active variables and in- + * terface blocks for a specified program. If one of these + * commands is called with a program for which LinkProgram + * succeeded, the information recorded when the program was + * linked is returned. If one of these commands is called with a + * program for which LinkProgram failed, no error is generated + * unless otherwise noted." + * <skip> + * "If one of these commands is called with a program for which + * LinkProgram had never been called, no error is generated + * unless otherwise noted, and the program object is considered + * to have no active variables or interface blocks." + * + * So if the program is not linked we will return 0. + */ + struct gl_linked_shader *sh = + lookup_linked_shader(program, programInterface, "glGetProgramInterfaceiv"); + + *params = sh ? sh->NumSubroutineUniforms : 0; + } else { + for (i = 0, *params = 0; i < shProg->NumProgramResourceList; i++) + if (shProg->ProgramResourceList[i].Type == programInterface) + (*params)++; + } break; case GL_MAX_NAME_LENGTH: if (programInterface == GL_ATOMIC_COUNTER_BUFFER || @@ -375,24 +488,6 @@ _mesa_GetProgramResourceiv(GLuint program, GLenum programInterface, propCount, props, bufSize, length, params); } -static struct gl_shader_program * -lookup_linked_program(GLuint program, const char *caller) -{ - GET_CURRENT_CONTEXT(ctx); - struct gl_shader_program *prog = - _mesa_lookup_shader_program_err(ctx, program, caller); - - if (!prog) - return NULL; - - if (prog->LinkStatus == GL_FALSE) { - _mesa_error(ctx, GL_INVALID_OPERATION, "%s(program not linked)", - caller); - return NULL; - } - return prog; -} - GLint GLAPIENTRY _mesa_GetProgramResourceLocation(GLuint program, GLenum programInterface, const GLchar *name) @@ -405,7 +500,7 @@ _mesa_GetProgramResourceLocation(GLuint program, GLenum programInterface, } struct gl_shader_program *shProg = - lookup_linked_program(program, "glGetProgramResourceLocation"); + lookup_linked_program(program, "glGetProgramResourceLocation", true); if (!shProg || !name) return -1; @@ -461,7 +556,7 @@ _mesa_GetProgramResourceLocationIndex(GLuint program, GLenum programInterface, } struct gl_shader_program *shProg = - lookup_linked_program(program, "glGetProgramResourceLocationIndex"); + lookup_linked_program(program, "glGetProgramResourceLocationIndex", true); if (!shProg || !name) return -1; |