linker: Initial implementation of uniform slot allocation
authorIan Romanick <ian.d.romanick@intel.com>
Mon, 21 Jun 2010 23:10:42 +0000 (16:10 -0700)
committerIan Romanick <ian.d.romanick@intel.com>
Wed, 23 Jun 2010 18:24:21 +0000 (11:24 -0700)
linker.cpp

index dadc0d9..0c07b6d 100644 (file)
@@ -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. */