glsl: calculate TOP_LEVEL_ARRAY_SIZE and STRIDE when adding resources

Patch moves existing calculation code from shader_query.cpp to happen
during program resource list creation.

No Piglit or CTS regressions were observed during testing.

Signed-off-by: Tapani Pälli <tapani.palli@intel.com>
Reviewed-by: Samuel Iglesias Gonsálvez <siglesias@igalia.com>
This commit is contained in:
Tapani Pälli
2015-10-14 11:01:29 +03:00
parent b76159b096
commit ac257f1070
2 changed files with 243 additions and 242 deletions

View File

@@ -839,244 +839,6 @@ program_resource_location(struct gl_shader_program *shProg,
}
}
static char*
get_top_level_name(const char *name)
{
const char *first_dot = strchr(name, '.');
const char *first_square_bracket = strchr(name, '[');
int name_size = 0;
/* From ARB_program_interface_query spec:
*
* "For the property TOP_LEVEL_ARRAY_SIZE, a single integer identifying the
* number of active array elements of the top-level shader storage block
* member containing to the active variable is written to <params>. If the
* top-level block member is not declared as an array, the value one is
* written to <params>. If the top-level block member is an array with no
* declared size, the value zero is written to <params>.
*/
/* The buffer variable is on top level.*/
if (!first_square_bracket && !first_dot)
name_size = strlen(name);
else if ((!first_square_bracket ||
(first_dot && first_dot < first_square_bracket)))
name_size = first_dot - name;
else
name_size = first_square_bracket - name;
return strndup(name, name_size);
}
static char*
get_var_name(const char *name)
{
const char *first_dot = strchr(name, '.');
if (!first_dot)
return strdup(name);
return strndup(first_dot+1, strlen(first_dot) - 1);
}
static bool
is_top_level_shader_storage_block_member(const char* name,
const char* interface_name,
const char* field_name)
{
bool result = false;
/* If the given variable is already a top-level shader storage
* block member, then return array_size = 1.
* We could have two possibilities: if we have an instanced
* shader storage block or not instanced.
*
* For the first, we check create a name as it was in top level and
* compare it with the real name. If they are the same, then
* the variable is already at top-level.
*
* Full instanced name is: interface name + '.' + var name +
* NULL character
*/
int name_length = strlen(interface_name) + 1 + strlen(field_name) + 1;
char *full_instanced_name = (char *) calloc(name_length, sizeof(char));
if (!full_instanced_name) {
fprintf(stderr, "%s: Cannot allocate space for name\n", __func__);
return false;
}
snprintf(full_instanced_name, name_length, "%s.%s",
interface_name, field_name);
/* Check if its top-level shader storage block member of an
* instanced interface block, or of a unnamed interface block.
*/
if (strcmp(name, full_instanced_name) == 0 ||
strcmp(name, field_name) == 0)
result = true;
free(full_instanced_name);
return result;
}
static GLint
program_resource_top_level_array_size(struct gl_shader_program *shProg,
struct gl_program_resource *res,
const char *name)
{
int block_index = RESOURCE_UNI(res)->block_index;
int array_size = -1;
char *var_name = get_top_level_name(name);
char *interface_name =
get_top_level_name(shProg->BufferInterfaceBlocks[block_index].Name);
if (strcmp(var_name, interface_name) == 0) {
/* Deal with instanced array of SSBOs */
char *temp_name = get_var_name(name);
free(var_name);
var_name = get_top_level_name(temp_name);
free(temp_name);
}
for (unsigned i = 0; i < shProg->NumShaders; i++) {
if (shProg->Shaders[i] == NULL)
continue;
const gl_shader *stage = shProg->Shaders[i];
foreach_in_list(ir_instruction, node, stage->ir) {
ir_variable *var = node->as_variable();
if (!var || !var->get_interface_type() ||
var->data.mode != ir_var_shader_storage)
continue;
const glsl_type *interface = var->get_interface_type();
if (strcmp(interface_name, interface->name) != 0)
continue;
for (unsigned i = 0; i < interface->length; i++) {
const glsl_struct_field *field = &interface->fields.structure[i];
if (strcmp(field->name, var_name) != 0)
continue;
/* From GL_ARB_program_interface_query spec:
*
* "For the property TOP_LEVEL_ARRAY_SIZE, a single integer
* identifying the number of active array elements of the top-level
* shader storage block member containing to the active variable is
* written to <params>. If the top-level block member is not
* declared as an array, the value one is written to <params>. If
* the top-level block member is an array with no declared size,
* the value zero is written to <params>.
*/
if (is_top_level_shader_storage_block_member(name,
interface_name,
var_name))
array_size = 1;
else if (field->type->is_unsized_array())
array_size = 0;
else if (field->type->is_array())
array_size = field->type->length;
else
array_size = 1;
goto found_top_level_array_size;
}
}
}
found_top_level_array_size:
free(interface_name);
free(var_name);
return array_size;
}
static GLint
program_resource_top_level_array_stride(struct gl_shader_program *shProg,
struct gl_program_resource *res,
const char *name)
{
int block_index = RESOURCE_UNI(res)->block_index;
int array_stride = -1;
char *var_name = get_top_level_name(name);
char *interface_name =
get_top_level_name(shProg->BufferInterfaceBlocks[block_index].Name);
if (strcmp(var_name, interface_name) == 0) {
/* Deal with instanced array of SSBOs */
char *temp_name = get_var_name(name);
free(var_name);
var_name = get_top_level_name(temp_name);
free(temp_name);
}
for (unsigned i = 0; i < shProg->NumShaders; i++) {
if (shProg->Shaders[i] == NULL)
continue;
const gl_shader *stage = shProg->Shaders[i];
foreach_in_list(ir_instruction, node, stage->ir) {
ir_variable *var = node->as_variable();
if (!var || !var->get_interface_type() ||
var->data.mode != ir_var_shader_storage)
continue;
const glsl_type *interface = var->get_interface_type();
if (strcmp(interface_name, interface->name) != 0) {
continue;
}
for (unsigned i = 0; i < interface->length; i++) {
const glsl_struct_field *field = &interface->fields.structure[i];
if (strcmp(field->name, var_name) != 0)
continue;
/* From GL_ARB_program_interface_query:
*
* "For the property TOP_LEVEL_ARRAY_STRIDE, a single integer
* identifying the stride between array elements of the top-level
* shader storage block member containing the active variable is
* written to <params>. For top-level block members declared as
* arrays, the value written is the difference, in basic machine
* units, between the offsets of the active variable for
* consecutive elements in the top-level array. For top-level
* block members not declared as an array, zero is written to
* <params>."
*/
if (field->type->is_array()) {
const enum glsl_matrix_layout matrix_layout =
glsl_matrix_layout(field->matrix_layout);
bool row_major = matrix_layout == GLSL_MATRIX_LAYOUT_ROW_MAJOR;
const glsl_type *array_type = field->type->fields.array;
if (is_top_level_shader_storage_block_member(name,
interface_name,
var_name)) {
array_stride = 0;
goto found_top_level_array_stride;
}
if (interface->interface_packing != GLSL_INTERFACE_PACKING_STD430) {
if (array_type->is_record() || array_type->is_array()) {
array_stride = array_type->std140_size(row_major);
array_stride = glsl_align(array_stride, 16);
} else {
unsigned element_base_align = 0;
element_base_align = array_type->std140_base_alignment(row_major);
array_stride = MAX2(element_base_align, 16);
}
} else {
array_stride = array_type->std430_array_stride(row_major);
}
} else {
array_stride = 0;
}
goto found_top_level_array_stride;
}
}
}
found_top_level_array_stride:
free(interface_name);
free(var_name);
return array_stride;
}
/**
* Function implements following location queries:
* glGetUniformLocation
@@ -1444,14 +1206,12 @@ _mesa_program_resource_prop(struct gl_shader_program *shProg,
case GL_TOP_LEVEL_ARRAY_SIZE:
VALIDATE_TYPE(GL_BUFFER_VARIABLE);
*val = program_resource_top_level_array_size(shProg, res,
_mesa_program_resource_name(res));
*val = RESOURCE_UNI(res)->top_level_array_size;
return 1;
case GL_TOP_LEVEL_ARRAY_STRIDE:
VALIDATE_TYPE(GL_BUFFER_VARIABLE);
*val = program_resource_top_level_array_stride(shProg, res,
_mesa_program_resource_name(res));
*val = RESOURCE_UNI(res)->top_level_array_stride;
return 1;
/* GL_ARB_tessellation_shader */