diff --git a/src/mesa/main/program_resource.c b/src/mesa/main/program_resource.c index fedd1f183ce..c85988d21ff 100644 --- a/src/mesa/main/program_resource.c +++ b/src/mesa/main/program_resource.c @@ -164,10 +164,12 @@ _mesa_GetProgramInterfaceiv(GLuint program, GLenum programInterface, shProg->data->ProgramResourceList[i].Data; GLint block_params = 0; for (unsigned j = 0; j < block->NumUniforms; j++) { - const char *iname = block->Uniforms[j].IndexName; struct gl_program_resource *uni = - _mesa_program_resource_find_name(shProg, GL_BUFFER_VARIABLE, - iname, NULL); + _mesa_program_resource_find_active_variable( + shProg, + GL_BUFFER_VARIABLE, + block, + j); if (!uni) continue; block_params++; diff --git a/src/mesa/main/shader_query.cpp b/src/mesa/main/shader_query.cpp index e9b39b7ff8f..000e2a16ea7 100644 --- a/src/mesa/main/shader_query.cpp +++ b/src/mesa/main/shader_query.cpp @@ -638,6 +638,119 @@ _mesa_program_resource_find_name(struct gl_shader_program *shProg, return NULL; } +/* Find an uniform or buffer variable program resource with an specific offset + * inside a block with an specific binding. + * + * Valid interfaces are GL_BUFFER_VARIABLE and GL_UNIFORM. + */ +static struct gl_program_resource * +program_resource_find_binding_offset(struct gl_shader_program *shProg, + GLenum programInterface, + const GLuint binding, + const GLint offset) +{ + + /* First we need to get the BLOCK_INDEX from the BUFFER_BINDING */ + GLenum blockInterface; + + switch (programInterface) { + case GL_BUFFER_VARIABLE: + blockInterface = GL_SHADER_STORAGE_BLOCK; + break; + case GL_UNIFORM: + blockInterface = GL_UNIFORM_BLOCK; + break; + default: + assert("Invalid program interface"); + return NULL; + } + + int block_index = -1; + int starting_index = -1; + struct gl_program_resource *res = shProg->data->ProgramResourceList; + + /* Blocks are added to the resource list in the same order that they are + * added to UniformBlocks/ShaderStorageBlocks. Furthermore, all the blocks + * of each type (UBO/SSBO) are contiguous, so we can infer block_index from + * the resource list. + */ + for (unsigned i = 0; i < shProg->data->NumProgramResourceList; i++, res++) { + if (res->Type != blockInterface) + continue; + + /* Store the first index where a resource of the specific interface is. */ + if (starting_index == -1) + starting_index = i; + + const struct gl_uniform_block *block = RESOURCE_UBO(res); + + if (block->Binding == binding) { + /* For arrays, or arrays of arrays of blocks, we want the resource + * for the block with base index. Most properties for members of each + * block are inherited from the block with the base index, including + * a uniform being active or not. + */ + block_index = i - starting_index - block->linearized_array_index; + break; + } + } + + if (block_index == -1) + return NULL; + + /* We now look for the resource corresponding to the uniform or buffer + * variable using the BLOCK_INDEX and OFFSET. + */ + res = shProg->data->ProgramResourceList; + for (unsigned i = 0; i < shProg->data->NumProgramResourceList; i++, res++) { + if (res->Type != programInterface) + continue; + + const struct gl_uniform_storage *uniform = RESOURCE_UNI(res); + + if (uniform->block_index == block_index && uniform->offset == offset) { + return res; + } + } + + return NULL; +} + +/* Checks if an uniform or buffer variable is in the active program resource + * list. + * + * It takes into accout that for variables coming from SPIR-V binaries their + * names could not be available (ARB_gl_spirv). In that case, it will use the + * the offset and the block binding to locate the resource. + * + * Valid interfaces are GL_BUFFER_VARIABLE and GL_UNIFORM. + */ +struct gl_program_resource * +_mesa_program_resource_find_active_variable(struct gl_shader_program *shProg, + GLenum programInterface, + const gl_uniform_block *block, + unsigned index) +{ + struct gl_program_resource *res; + struct gl_uniform_buffer_variable uni = block->Uniforms[index]; + + assert(programInterface == GL_UNIFORM || + programInterface == GL_BUFFER_VARIABLE); + + if (uni.IndexName) { + res = _mesa_program_resource_find_name(shProg, programInterface, uni.IndexName, + NULL); + } else { + /* As the resource has no associated name (ARB_gl_spirv), + * we can use the UBO/SSBO binding and offset to find it. + */ + res = program_resource_find_binding_offset(shProg, programInterface, + block->Binding, uni.Offset); + } + + return res; +} + static GLuint calc_resource_index(struct gl_shader_program *shProg, struct gl_program_resource *res) @@ -1039,10 +1152,13 @@ get_buffer_property(struct gl_shader_program *shProg, case GL_NUM_ACTIVE_VARIABLES: *val = 0; for (unsigned i = 0; i < RESOURCE_UBO(res)->NumUniforms; i++) { - const char *iname = RESOURCE_UBO(res)->Uniforms[i].IndexName; struct gl_program_resource *uni = - _mesa_program_resource_find_name(shProg, GL_UNIFORM, iname, - NULL); + _mesa_program_resource_find_active_variable( + shProg, + GL_UNIFORM, + RESOURCE_UBO(res), + i); + if (!uni) continue; (*val)++; @@ -1051,10 +1167,13 @@ get_buffer_property(struct gl_shader_program *shProg, case GL_ACTIVE_VARIABLES: { unsigned num_values = 0; for (unsigned i = 0; i < RESOURCE_UBO(res)->NumUniforms; i++) { - const char *iname = RESOURCE_UBO(res)->Uniforms[i].IndexName; struct gl_program_resource *uni = - _mesa_program_resource_find_name(shProg, GL_UNIFORM, iname, - NULL); + _mesa_program_resource_find_active_variable( + shProg, + GL_UNIFORM, + RESOURCE_UBO(res), + i); + if (!uni) continue; *val++ = @@ -1075,10 +1194,13 @@ get_buffer_property(struct gl_shader_program *shProg, case GL_NUM_ACTIVE_VARIABLES: *val = 0; for (unsigned i = 0; i < RESOURCE_UBO(res)->NumUniforms; i++) { - const char *iname = RESOURCE_UBO(res)->Uniforms[i].IndexName; struct gl_program_resource *uni = - _mesa_program_resource_find_name(shProg, GL_BUFFER_VARIABLE, - iname, NULL); + _mesa_program_resource_find_active_variable( + shProg, + GL_BUFFER_VARIABLE, + RESOURCE_UBO(res), + i); + if (!uni) continue; (*val)++; @@ -1087,10 +1209,13 @@ get_buffer_property(struct gl_shader_program *shProg, case GL_ACTIVE_VARIABLES: { unsigned num_values = 0; for (unsigned i = 0; i < RESOURCE_UBO(res)->NumUniforms; i++) { - const char *iname = RESOURCE_UBO(res)->Uniforms[i].IndexName; struct gl_program_resource *uni = - _mesa_program_resource_find_name(shProg, GL_BUFFER_VARIABLE, - iname, NULL); + _mesa_program_resource_find_active_variable( + shProg, + GL_BUFFER_VARIABLE, + RESOURCE_UBO(res), + i); + if (!uni) continue; *val++ = diff --git a/src/mesa/main/shaderapi.h b/src/mesa/main/shaderapi.h index a8227ecc969..73fa90bbae9 100644 --- a/src/mesa/main/shaderapi.h +++ b/src/mesa/main/shaderapi.h @@ -29,6 +29,7 @@ #include "glheader.h" +#include "main/mtypes.h" #include "compiler/shader_enums.h" #ifdef __cplusplus @@ -296,6 +297,12 @@ extern struct gl_program_resource * _mesa_program_resource_find_index(struct gl_shader_program *shProg, GLenum programInterface, GLuint index); +extern struct gl_program_resource * +_mesa_program_resource_find_active_variable(struct gl_shader_program *shProg, + GLenum programInterface, + const struct gl_uniform_block *block, + unsigned index); + extern bool _mesa_get_program_resource_name(struct gl_shader_program *shProg, GLenum programInterface, GLuint index,