summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Anholt <eric@anholt.net>2010-08-23 10:32:01 -0700
committerEric Anholt <eric@anholt.net>2010-08-23 10:34:31 -0700
commita721abfbd1724e83381b46fc670bb38fbde76f69 (patch)
treed6ecf823c668122e3c6179a2db31fea69774d690
parent001a7bfdfc8b3c8930d5ced21982dbdfb8cd35b3 (diff)
glsl: Trim the size of uniform arrays to the maximum element used.
Fixes glsl-getactiveuniform-array-size.
-rw-r--r--src/glsl/ast_to_hir.cpp5
-rw-r--r--src/glsl/linker.cpp52
2 files changed, 57 insertions, 0 deletions
diff --git a/src/glsl/ast_to_hir.cpp b/src/glsl/ast_to_hir.cpp
index b60bb2f0a0a..8e4c3299aa6 100644
--- a/src/glsl/ast_to_hir.cpp
+++ b/src/glsl/ast_to_hir.cpp
@@ -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)
diff --git a/src/glsl/linker.cpp b/src/glsl/linker.cpp
index 2dc569777e7..deb30d7fecf 100644
--- a/src/glsl/linker.cpp
+++ b/src/glsl/linker.cpp
@@ -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;