glsl: Lower UBO references using link-time data instead of compile-time data
authorIan Romanick <ian.d.romanick@intel.com>
Tue, 22 Jan 2013 05:44:58 +0000 (00:44 -0500)
committerIan Romanick <ian.d.romanick@intel.com>
Fri, 25 Jan 2013 14:07:35 +0000 (09:07 -0500)
Pretty much all of the compile-time, per-compilation unit block data is
about to get the axe.

Signed-off-by: Ian Romanick <ian.d.romanick@intel.com>
Reviewed-by: Jordan Justen <jordan.l.justen@intel.com>
src/glsl/lower_ubo_reference.cpp

index 8d13ec181923c8b46d5e09526212863d1340065d..026197df7a9b65a0659805bf4865d82735b153dc 100644 (file)
@@ -61,6 +61,60 @@ public:
    bool progress;
 };
 
+/**
+ * Determine the name of the interface block field
+ *
+ * This is the name of the specific member as it would appear in the
+ * \c gl_uniform_buffer_variable::Name field in the shader's
+ * \c UniformBlocks array.
+ */
+static const char *
+interface_field_name(void *mem_ctx, char *base_name, ir_dereference *d)
+{
+   ir_constant *previous_index = NULL;
+
+   while (d != NULL) {
+      switch (d->ir_type) {
+      case ir_type_dereference_variable: {
+         ir_dereference_variable *v = (ir_dereference_variable *) d;
+         if (previous_index
+             && v->var->is_interface_instance()
+             && v->var->type->is_array())
+            return ralloc_asprintf(mem_ctx,
+                                   "%s[%d]",
+                                   base_name,
+                                   previous_index->get_uint_component(0));
+         else
+            return base_name;
+
+         break;
+      }
+
+      case ir_type_dereference_record: {
+         ir_dereference_record *r = (ir_dereference_record *) d;
+
+         d = r->record->as_dereference();
+         break;
+      }
+
+      case ir_type_dereference_array: {
+         ir_dereference_array *a = (ir_dereference_array *) d;
+
+         d = a->array->as_dereference();
+         previous_index = a->array_index->as_constant();
+         break;
+      }
+
+      default:
+         assert(!"Should not get here.");
+         break;
+      }
+   }
+
+   assert(!"Should not get here.");
+   return NULL;
+}
+
 void
 lower_ubo_reference_visitor::handle_rvalue(ir_rvalue **rvalue)
 {
@@ -76,9 +130,26 @@ lower_ubo_reference_visitor::handle_rvalue(ir_rvalue **rvalue)
       return;
 
    mem_ctx = ralloc_parent(*rvalue);
-   uniform_block = var->uniform_block;
-   struct gl_uniform_block *block = &shader->UniformBlocks[uniform_block];
-   this->ubo_var = &block->Uniforms[var->location];
+
+   const char *const field_name =
+      interface_field_name(mem_ctx, (char *) var->interface_type->name, deref);
+
+   this->uniform_block = -1;
+   for (unsigned i = 0; i < shader->NumUniformBlocks; i++) {
+      if (strcmp(field_name, shader->UniformBlocks[i].Name) == 0) {
+         this->uniform_block = i;
+
+         struct gl_uniform_block *block = &shader->UniformBlocks[i];
+
+         this->ubo_var = var->is_interface_instance()
+            ? &block->Uniforms[0] : &block->Uniforms[var->location];
+
+         break;
+      }
+   }
+
+   assert(this->uniform_block != (unsigned) -1);
+
    ir_rvalue *offset = new(mem_ctx) ir_constant(0u);
    unsigned const_offset = 0;
    bool row_major = ubo_var->RowMajor;
@@ -105,6 +176,18 @@ lower_ubo_reference_visitor::handle_rvalue(ir_rvalue **rvalue)
             * vector) is handled below in emit_ubo_loads.
             */
            array_stride = 4;
+         } else if (deref_array->type->is_interface()) {
+            /* We're processing an array dereference of an interface instance
+            * array.  The thing being dereferenced *must* be a variable
+            * dereference because intefaces cannot be embedded an other
+            * types.  In terms of calculating the offsets for the lowering
+            * pass, we don't care about the array index.  All elements of an
+            * interface instance array will have the same offsets relative to
+            * the base of the block that backs them.
+             */
+            assert(deref_array->array->as_dereference_variable());
+            deref = deref_array->array->as_dereference();
+            break;
         } else {
            array_stride = deref_array->type->std140_size(row_major);
            array_stride = glsl_align(array_stride, 16);