glsl: Trim the size of uniform arrays to the maximum element used.

Fixes glsl-getactiveuniform-array-size.
This commit is contained in:
Eric Anholt 2010-08-23 10:32:01 -07:00
parent 001a7bfdfc
commit a721abfbd1
2 changed files with 57 additions and 0 deletions

View File

@ -1258,6 +1258,11 @@ ast_expression::hir(exec_list *instructions,
}
} else if (array->type->array_size() == 0) {
_mesa_glsl_error(&loc, state, "unsized array index must be constant");
} else {
if (array->type->is_array()) {
ir_variable *v = array->whole_variable_referenced();
v->max_array_access = array->type->array_size();
}
}
if (error_emitted)

View File

@ -809,6 +809,56 @@ struct uniform_node {
unsigned slots;
};
/**
* Update the sizes of linked shader uniform arrays to the maximum
* array index used.
*
* From page 81 (page 95 of the PDF) of the OpenGL 2.1 spec:
*
* If one or more elements of an array are active,
* GetActiveUniform will return the name of the array in name,
* subject to the restrictions listed above. The type of the array
* is returned in type. The size parameter contains the highest
* array element index used, plus one. The compiler or linker
* determines the highest index used. There will be only one
* active uniform reported by the GL per uniform array.
*/
static void
update_uniform_array_sizes(struct gl_shader_program *prog)
{
for (unsigned i = 0; i < prog->_NumLinkedShaders; i++) {
foreach_list(node, prog->_LinkedShaders[i]->ir) {
ir_variable *const var = ((ir_instruction *) node)->as_variable();
if ((var == NULL) || (var->mode != ir_var_uniform) ||
!var->type->is_array())
continue;
unsigned int size = var->max_array_access;
for (unsigned j = 0; j < prog->_NumLinkedShaders; j++) {
foreach_list(node2, prog->_LinkedShaders[j]->ir) {
ir_variable *other_var = ((ir_instruction *) node2)->as_variable();
if (!other_var)
continue;
if (strcmp(var->name, other_var->name) == 0 &&
other_var->max_array_access > size) {
size = other_var->max_array_access;
}
}
}
if (size + 1 != var->type->fields.array->length) {
var->type = glsl_type::get_array_instance(var->type->fields.array,
size + 1);
/* FINISHME: We should update the types of array
* dereferences of this variable now.
*/
}
}
}
}
void
assign_uniform_locations(struct gl_shader_program *prog)
{
@ -818,6 +868,8 @@ assign_uniform_locations(struct gl_shader_program *prog)
hash_table *ht = hash_table_ctor(32, hash_table_string_hash,
hash_table_string_compare);
update_uniform_array_sizes(prog);
for (unsigned i = 0; i < prog->_NumLinkedShaders; i++) {
unsigned next_position = 0;