summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Romanick <ian.d.romanick@intel.com>2010-06-21 16:10:42 -0700
committerIan Romanick <ian.d.romanick@intel.com>2010-06-23 11:24:21 -0700
commit019a59b2642f403203d8bc8ea980efeeffcd6462 (patch)
tree999de628bf37da55531e4d9f1b7b8fa127e5167d
parent5edf6f98d8b7b945294c55284cefc8035d23ea8a (diff)
linker: Initial implementation of uniform slot allocation
-rw-r--r--linker.cpp100
1 files changed, 99 insertions, 1 deletions
diff --git a/linker.cpp b/linker.cpp
index dadc0d9..0c07b6d 100644
--- a/linker.cpp
+++ b/linker.cpp
@@ -69,7 +69,9 @@
#include "glsl_symbol_table.h"
#include "glsl_parser_extras.h"
#include "ir.h"
+#include "ir_optimization.h"
#include "program.h"
+#include "hash_table.h"
/**
* Visitor that determines whether or not a variable is ever written.
@@ -318,6 +320,101 @@ cross_validate_outputs_to_inputs(glsl_shader *producer, glsl_shader *consumer)
}
+struct uniform_node {
+ exec_node link;
+ struct gl_uniform *u;
+ unsigned slots;
+};
+
+struct gl_uniform_list *
+assign_uniform_locations(struct glsl_shader **shaders, unsigned num_shaders)
+{
+ /* */
+ exec_list uniforms;
+ unsigned total_uniforms = 0;
+ hash_table *ht = hash_table_ctor(32, hash_table_string_hash,
+ hash_table_string_compare);
+
+ for (unsigned i = 0; i < num_shaders; i++) {
+ unsigned next_position = 0;
+
+ foreach_list(node, &shaders[i]->ir) {
+ ir_variable *const var = ((ir_instruction *) node)->as_variable();
+
+ if ((var == NULL) || (var->mode != ir_var_uniform))
+ continue;
+
+ const unsigned vec4_slots = (var->component_slots() + 3) / 4;
+ assert(vec4_slots != 0);
+
+ uniform_node *n = (uniform_node *) hash_table_find(ht, var->name);
+ if (n == NULL) {
+ n = (uniform_node *) calloc(1, sizeof(struct uniform_node));
+ n->u = (gl_uniform *) calloc(vec4_slots, sizeof(struct gl_uniform));
+ n->slots = vec4_slots;
+
+ n->u[0].Name = strdup(var->name);
+ for (unsigned j = 1; j < vec4_slots; j++)
+ n->u[j].Name = n->u[0].Name;
+
+ hash_table_insert(ht, n, n->u[0].Name);
+ uniforms.push_tail(& n->link);
+ total_uniforms += vec4_slots;
+ }
+
+ if (var->constant_value != NULL)
+ for (unsigned j = 0; j < vec4_slots; j++)
+ n->u[j].Initialized = true;
+
+ var->location = next_position;
+
+ for (unsigned j = 0; j < vec4_slots; j++) {
+ switch (shaders[i]->Type) {
+ case GL_VERTEX_SHADER:
+ n->u[j].VertPos = next_position;
+ break;
+ case GL_FRAGMENT_SHADER:
+ n->u[j].FragPos = next_position;
+ break;
+ case GL_GEOMETRY_SHADER:
+ /* FINISHME: Support geometry shaders. */
+ assert(shaders[i]->Type != GL_GEOMETRY_SHADER);
+ break;
+ }
+
+ next_position++;
+ }
+ }
+ }
+
+ gl_uniform_list *ul = (gl_uniform_list *)
+ calloc(1, sizeof(gl_uniform_list));
+
+ ul->Size = total_uniforms;
+ ul->NumUniforms = total_uniforms;
+ ul->Uniforms = (gl_uniform *) calloc(total_uniforms, sizeof(gl_uniform));
+
+ unsigned idx = 0;
+ uniform_node *next;
+ for (uniform_node *node = (uniform_node *) uniforms.head
+ ; node->link.next != NULL
+ ; node = next) {
+ next = (uniform_node *) node->link.next;
+
+ node->link.remove();
+ memcpy(&ul->Uniforms[idx], node->u, sizeof(gl_uniform) * node->slots);
+ idx += node->slots;
+
+ free(node->u);
+ free(node);
+ }
+
+ hash_table_dtor(ht);
+
+ return ul;
+}
+
+
void
link_shaders(struct glsl_program *prog)
{
@@ -394,7 +491,8 @@ link_shaders(struct glsl_program *prog)
/* FINISHME: Perform whole-program optimization here. */
- /* FINISHME: Assign uniform locations. */
+ prog->Uniforms = assign_uniform_locations(shader_executables,
+ num_shader_executables);
/* FINISHME: Assign vertex shader input locations. */