summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/glsl/lower_ubo_reference.cpp89
1 files changed, 86 insertions, 3 deletions
diff --git a/src/glsl/lower_ubo_reference.cpp b/src/glsl/lower_ubo_reference.cpp
index 8d13ec18192..026197df7a9 100644
--- a/src/glsl/lower_ubo_reference.cpp
+++ b/src/glsl/lower_ubo_reference.cpp
@@ -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);