glsl: Make uniform linking generate separate uniforms for struct members.
authorEric Anholt <eric@anholt.net>
Tue, 24 Aug 2010 20:51:35 +0000 (13:51 -0700)
committerEric Anholt <eric@anholt.net>
Wed, 25 Aug 2010 19:38:26 +0000 (12:38 -0700)
This is a step towards making the linker code usable as our uniform
setup, instead of having it wedged into ir_to_mesa.cpp.

src/glsl/linker.cpp

index c5c8c9cdd6382fc2b5d1eb6a2110d5353dd5b362..cb06036ef230a4b304b399b414f1e14d541b1271 100644 (file)
@@ -877,6 +877,83 @@ update_uniform_array_sizes(struct gl_shader_program *prog)
    }
 }
 
+static void
+add_uniform(void *mem_ctx, exec_list *uniforms, struct hash_table *ht,
+           const char *name, const glsl_type *type, GLenum shader_type,
+           unsigned *next_shader_pos, unsigned *total_uniforms)
+{
+   if (type->is_record()) {
+      for (unsigned int i = 0; i < type->length; i++) {
+        const glsl_type *field_type = type->fields.structure[i].type;
+        char *field_name = talloc_asprintf(mem_ctx, "%s.%s", name,
+                                           type->fields.structure[i].name);
+
+        add_uniform(mem_ctx, uniforms, ht, field_name, field_type,
+                    shader_type, next_shader_pos, total_uniforms);
+      }
+   } else {
+      uniform_node *n = (uniform_node *) hash_table_find(ht, name);
+      unsigned int vec4_slots;
+      const glsl_type *array_elem_type = NULL;
+
+      if (type->is_array()) {
+        array_elem_type = type->fields.array;
+        /* Array of structures. */
+        if (array_elem_type->is_record()) {
+           for (unsigned int i = 0; i < type->length; i++) {
+              char *elem_name = talloc_asprintf(mem_ctx, "%s[%d]", name, i);
+              add_uniform(mem_ctx, uniforms, ht, elem_name, array_elem_type,
+                          shader_type, next_shader_pos, total_uniforms);
+           }
+           return;
+        }
+      }
+
+      /* Fix the storage size of samplers at 1 vec4 each. Be sure to pad out
+       * vectors to vec4 slots.
+       */
+      if (type->is_array()) {
+        if (array_elem_type->is_sampler())
+           vec4_slots = type->length;
+        else
+           vec4_slots = type->length * array_elem_type->matrix_columns;
+      } else if (type->is_sampler()) {
+        vec4_slots = 1;
+      } else {
+        vec4_slots = type->matrix_columns;
+      }
+
+      if (n == NULL) {
+        n = (uniform_node *) calloc(1, sizeof(struct uniform_node));
+        n->u = (gl_uniform *) calloc(1, sizeof(struct gl_uniform));
+        n->slots = vec4_slots;
+
+        n->u->Name = strdup(name);
+        n->u->VertPos = -1;
+        n->u->FragPos = -1;
+        n->u->GeomPos = -1;
+        (*total_uniforms)++;
+
+        hash_table_insert(ht, n, name);
+        uniforms->push_tail(& n->link);
+      }
+
+      switch (shader_type) {
+      case GL_VERTEX_SHADER:
+        n->u->VertPos = *next_shader_pos;
+        break;
+      case GL_FRAGMENT_SHADER:
+        n->u->FragPos = *next_shader_pos;
+        break;
+      case GL_GEOMETRY_SHADER:
+        n->u->GeomPos = *next_shader_pos;
+        break;
+      }
+
+      (*next_shader_pos) += vec4_slots;
+   }
+}
+
 void
 assign_uniform_locations(struct gl_shader_program *prog)
 {
@@ -885,6 +962,7 @@ assign_uniform_locations(struct gl_shader_program *prog)
    unsigned total_uniforms = 0;
    hash_table *ht = hash_table_ctor(32, hash_table_string_hash,
                                    hash_table_string_compare);
+   void *mem_ctx = talloc_new(NULL);
 
    update_uniform_array_sizes(prog);
 
@@ -897,54 +975,23 @@ assign_uniform_locations(struct gl_shader_program *prog)
         if ((var == NULL) || (var->mode != ir_var_uniform))
            continue;
 
-        const unsigned vec4_slots = (var->component_slots() + 3) / 4;
-        if (vec4_slots == 0) {
-           /* If we've got a sampler or an aggregate of them, the size can
-            * end up zero.  Don't allocate any space.
+        if (strncmp(var->name, "gl_", 3) == 0) {
+           /* At the moment, we don't allocate uniform locations for
+            * builtin uniforms.  It's permitted by spec, and we'll
+            * likely switch to doing that at some point, but not yet.
             */
            continue;
         }
 
-        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 = strdup(var->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 (prog->_LinkedShaders[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(prog->_LinkedShaders[i]->Type != GL_GEOMETRY_SHADER);
-              break;
-           }
-
-           next_position++;
-        }
+        add_uniform(mem_ctx, &uniforms, ht, var->name, var->type,
+                    prog->_LinkedShaders[i]->Type,
+                    &next_position, &total_uniforms);
       }
    }
 
+   talloc_free(mem_ctx);
+
    gl_uniform_list *ul = (gl_uniform_list *)
       calloc(1, sizeof(gl_uniform_list));
 
@@ -960,8 +1007,8 @@ assign_uniform_locations(struct gl_shader_program *prog)
       next = (uniform_node *) node->link.next;
 
       node->link.remove();
-      memcpy(&ul->Uniforms[idx], node->u, sizeof(gl_uniform) * node->slots);
-      idx += node->slots;
+      memcpy(&ul->Uniforms[idx], node->u, sizeof(gl_uniform));
+      idx++;
 
       free(node->u);
       free(node);