glsl: Correctly determine when the field of a UBO is row-major
authorIan Romanick <ian.d.romanick@intel.com>
Mon, 30 Jun 2014 17:05:27 +0000 (10:05 -0700)
committerIan Romanick <ian.d.romanick@intel.com>
Mon, 4 Aug 2014 21:40:07 +0000 (14:40 -0700)
Previously if a field of an block with an instance name was marked
row-major (but block itself was not), we would think the field (and it's
sub-fields) were column-major.

Fixes gles3conform failures in:

ES3-CTS.shaders.uniform_block.random.basic_types.7
ES3-CTS.shaders.uniform_block.random.basic_types.9
ES3-CTS.shaders.uniform_block.random.basic_instance_arrays.1
ES3-CTS.shaders.uniform_block.random.basic_instance_arrays.3
ES3-CTS.shaders.uniform_block.random.nested_structs.3
ES3-CTS.shaders.uniform_block.random.nested_structs.5
ES3-CTS.shaders.uniform_block.random.nested_structs.8
ES3-CTS.shaders.uniform_block.random.nested_structs_arrays.3
ES3-CTS.shaders.uniform_block.random.nested_structs_arrays.6
ES3-CTS.shaders.uniform_block.random.nested_structs_arrays.7
ES3-CTS.shaders.uniform_block.random.nested_structs_arrays.8
ES3-CTS.shaders.uniform_block.random.nested_structs_arrays.9
ES3-CTS.shaders.uniform_block.random.nested_structs_instance_arrays.0
ES3-CTS.shaders.uniform_block.random.nested_structs_instance_arrays.1
ES3-CTS.shaders.uniform_block.random.nested_structs_instance_arrays.2
ES3-CTS.shaders.uniform_block.random.nested_structs_instance_arrays.3
ES3-CTS.shaders.uniform_block.random.nested_structs_instance_arrays.4
ES3-CTS.shaders.uniform_block.random.nested_structs_instance_arrays.6
ES3-CTS.shaders.uniform_block.random.nested_structs_arrays_instance_arrays.0
ES3-CTS.shaders.uniform_block.random.nested_structs_arrays_instance_arrays.1
ES3-CTS.shaders.uniform_block.random.nested_structs_arrays_instance_arrays.5
ES3-CTS.shaders.uniform_block.random.all_per_block_buffers.0
ES3-CTS.shaders.uniform_block.random.all_per_block_buffers.4
ES3-CTS.shaders.uniform_block.random.all_per_block_buffers.7
ES3-CTS.shaders.uniform_block.random.all_per_block_buffers.8
ES3-CTS.shaders.uniform_block.random.all_per_block_buffers.12
ES3-CTS.shaders.uniform_block.random.all_per_block_buffers.14
ES3-CTS.shaders.uniform_block.random.all_per_block_buffers.15
ES3-CTS.shaders.uniform_block.random.all_per_block_buffers.16
ES3-CTS.shaders.uniform_block.random.all_shared_buffer.1
ES3-CTS.shaders.uniform_block.random.all_shared_buffer.8
ES3-CTS.shaders.uniform_block.random.all_shared_buffer.9
ES3-CTS.shaders.uniform_block.random.all_shared_buffer.10
ES3-CTS.shaders.uniform_block.random.all_shared_buffer.11
ES3-CTS.shaders.uniform_block.random.all_shared_buffer.13
ES3-CTS.shaders.uniform_block.random.all_shared_buffer.14
ES3-CTS.shaders.uniform_block.random.all_shared_buffer.15
ES3-CTS.shaders.uniform_block.random.all_shared_buffer.16
ES3-CTS.shaders.uniform_block.random.all_shared_buffer.17

Fixes gles3conform failures (caused by previous commits) in:

ES3-CTS.shaders.uniform_block.random.basic_types.8
ES3-CTS.shaders.uniform_block.random.basic_arrays.3
ES3-CTS.shaders.uniform_block.random.basic_instance_arrays.0
ES3-CTS.shaders.uniform_block.random.basic_instance_arrays.2
ES3-CTS.shaders.uniform_block.random.all_per_block_buffers.9
ES3-CTS.shaders.uniform_block.random.all_per_block_buffers.13
ES3-CTS.shaders.uniform_block.random.all_per_block_buffers.18
ES3-CTS.shaders.uniform_block.random.all_shared_buffer.4

v2: Fix rebase failure noticed by Matt.

v3: Use without_array() instead of older predicates.

v4: s/GLSL_MATRIX_LAYOUT_DEFAULT/GLSL_MATRIX_LAYOUT_INHERITED/g

Signed-off-by: Ian Romanick <ian.d.romanick@intel.com>
Reviewed-by: Matt Turner <mattst88@gmail.com> [v2]
src/glsl/lower_ubo_reference.cpp

index 2890d3e74d84a785a2b393539cba2aea8fb9efb0..48675da2f2b89634200a3b54a47eaa7cc6675896 100644 (file)
 
 using namespace ir_builder;
 
+/**
+ * Determine if a thing being dereferenced is row-major
+ *
+ * There is some trickery here.
+ *
+ * If the thing being dereferenced is a member of uniform block \b without an
+ * instance name, then the name of the \c ir_variable is the field name of an
+ * interface type.  If this field is row-major, then the thing referenced is
+ * row-major.
+ *
+ * If the thing being dereferenced is a member of uniform block \b with an
+ * instance name, then the last dereference in the tree will be an
+ * \c ir_dereference_record.  If that record field is row-major, then the
+ * thing referenced is row-major.
+ */
+static bool
+is_dereferenced_thing_row_major(const ir_dereference *deref)
+{
+   bool matrix = false;
+   const ir_rvalue *ir = deref;
+
+   while (true) {
+      matrix = matrix || ir->type->without_array()->is_matrix();
+
+      switch (ir->ir_type) {
+      case ir_type_dereference_array: {
+         const ir_dereference_array *const array_deref =
+            (const ir_dereference_array *) ir;
+
+         ir = array_deref->array;
+         break;
+      }
+
+      case ir_type_dereference_record: {
+         const ir_dereference_record *const record_deref =
+            (const ir_dereference_record *) ir;
+
+         ir = record_deref->record;
+
+         const int idx = ir->type->field_index(record_deref->field);
+         assert(idx >= 0);
+
+         const enum glsl_matrix_layout matrix_layout =
+            glsl_matrix_layout(ir->type->fields.structure[idx].matrix_layout);
+
+         switch (matrix_layout) {
+         case GLSL_MATRIX_LAYOUT_INHERITED:
+            break;
+         case GLSL_MATRIX_LAYOUT_COLUMN_MAJOR:
+            return false;
+         case GLSL_MATRIX_LAYOUT_ROW_MAJOR:
+            return matrix || deref->type->without_array()->is_record();
+         }
+
+         break;
+      }
+
+      case ir_type_dereference_variable: {
+         const ir_dereference_variable *const var_deref =
+            (const ir_dereference_variable *) ir;
+
+         const enum glsl_matrix_layout matrix_layout =
+            glsl_matrix_layout(var_deref->var->data.matrix_layout);
+
+         switch (matrix_layout) {
+         case GLSL_MATRIX_LAYOUT_INHERITED:
+            assert(!matrix);
+            return false;
+         case GLSL_MATRIX_LAYOUT_COLUMN_MAJOR:
+            return false;
+         case GLSL_MATRIX_LAYOUT_ROW_MAJOR:
+            return matrix || deref->type->is_record();
+         }
+
+         unreachable("invalid matrix layout");
+         break;
+      }
+
+      default:
+         return false;
+      }
+   }
+
+   /* The tree must have ended with a dereference that wasn't an
+    * ir_dereference_variable.  That is invalid, and it should be impossible.
+    */
+   unreachable("invalid dereference tree");
+   return false;
+}
+
 namespace {
 class lower_ubo_reference_visitor : public ir_rvalue_enter_visitor {
 public:
@@ -50,7 +140,7 @@ public:
 
    void handle_rvalue(ir_rvalue **rvalue);
    void emit_ubo_loads(ir_dereference *deref, ir_variable *base_offset,
-                      unsigned int deref_offset);
+                      unsigned int deref_offset, bool row_major);
    ir_expression *ubo_load(const struct glsl_type *type,
                           ir_rvalue *offset);
 
@@ -174,7 +264,7 @@ lower_ubo_reference_visitor::handle_rvalue(ir_rvalue **rvalue)
 
    ir_rvalue *offset = new(mem_ctx) ir_constant(0u);
    unsigned const_offset = 0;
-   bool row_major = ubo_var->RowMajor;
+   bool row_major = is_dereferenced_thing_row_major(deref);
 
    /* Calculate the offset to the start of the region of the UBO
     * dereferenced by *rvalue.  This may be a variable offset if an
@@ -240,14 +330,24 @@ lower_ubo_reference_visitor::handle_rvalue(ir_rvalue **rvalue)
         unsigned max_field_align = 16;
         for (unsigned int i = 0; i < struct_type->length; i++) {
            const glsl_type *type = struct_type->fields.structure[i].type;
-           unsigned field_align = type->std140_base_alignment(row_major);
+
+            ir_dereference_record *field_deref =
+               new(mem_ctx) ir_dereference_record(deref_record->record,
+                                                  struct_type->fields.structure[i].name);
+            const bool field_row_major =
+               is_dereferenced_thing_row_major(field_deref);
+
+            ralloc_free(field_deref);
+
+            unsigned field_align = type->std140_base_alignment(field_row_major);
+
            max_field_align = MAX2(field_align, max_field_align);
            intra_struct_offset = glsl_align(intra_struct_offset, field_align);
 
            if (strcmp(struct_type->fields.structure[i].name,
                       deref_record->field) == 0)
               break;
-           intra_struct_offset += type->std140_size(row_major);
+            intra_struct_offset += type->std140_size(field_row_major);
         }
 
         const_offset = glsl_align(const_offset, max_field_align);
@@ -279,7 +379,7 @@ lower_ubo_reference_visitor::handle_rvalue(ir_rvalue **rvalue)
    base_ir->insert_before(assign(load_offset, offset));
 
    deref = new(mem_ctx) ir_dereference_variable(load_var);
-   emit_ubo_loads(deref, load_offset, const_offset);
+   emit_ubo_loads(deref, load_offset, const_offset, row_major);
    *rvalue = deref;
 
    progress = true;
@@ -309,7 +409,8 @@ lower_ubo_reference_visitor::ubo_load(const glsl_type *type,
 void
 lower_ubo_reference_visitor::emit_ubo_loads(ir_dereference *deref,
                                            ir_variable *base_offset,
-                                           unsigned int deref_offset)
+                                            unsigned int deref_offset,
+                                            bool row_major)
 {
    if (deref->type->is_record()) {
       unsigned int field_offset = 0;
@@ -323,18 +424,19 @@ lower_ubo_reference_visitor::emit_ubo_loads(ir_dereference *deref,
 
         field_offset =
            glsl_align(field_offset,
-                      field->type->std140_base_alignment(ubo_var->RowMajor));
+                       field->type->std140_base_alignment(row_major));
 
-        emit_ubo_loads(field_deref, base_offset, deref_offset + field_offset);
+        emit_ubo_loads(field_deref, base_offset, deref_offset + field_offset,
+                        row_major);
 
-        field_offset += field->type->std140_size(ubo_var->RowMajor);
+        field_offset += field->type->std140_size(row_major);
       }
       return;
    }
 
    if (deref->type->is_array()) {
       unsigned array_stride =
-        glsl_align(deref->type->fields.array->std140_size(ubo_var->RowMajor),
+        glsl_align(deref->type->fields.array->std140_size(row_major),
                    16);
 
       for (unsigned i = 0; i < deref->type->length; i++) {
@@ -343,7 +445,8 @@ lower_ubo_reference_visitor::emit_ubo_loads(ir_dereference *deref,
            new(mem_ctx) ir_dereference_array(deref->clone(mem_ctx, NULL),
                                              element);
         emit_ubo_loads(element_deref, base_offset,
-                       deref_offset + i * array_stride);
+                       deref_offset + i * array_stride,
+                        row_major);
       }
       return;
    }
@@ -355,16 +458,18 @@ lower_ubo_reference_visitor::emit_ubo_loads(ir_dereference *deref,
            new(mem_ctx) ir_dereference_array(deref->clone(mem_ctx, NULL),
                                              col);
 
-         if (ubo_var->RowMajor) {
+         if (row_major) {
             /* For a row-major matrix, the next column starts at the next
              * element.
              */
-            emit_ubo_loads(col_deref, base_offset, deref_offset + i * 4);
+            emit_ubo_loads(col_deref, base_offset, deref_offset + i * 4,
+                           row_major);
          } else {
             /* std140 always rounds the stride of arrays (and matrices) to a
              * vec4, so matrices are always 16 between columns/rows.
              */
-            emit_ubo_loads(col_deref, base_offset, deref_offset + i * 16);
+            emit_ubo_loads(col_deref, base_offset, deref_offset + i * 16,
+                           row_major);
          }
       }
       return;
@@ -373,7 +478,7 @@ lower_ubo_reference_visitor::emit_ubo_loads(ir_dereference *deref,
    assert(deref->type->is_scalar() ||
          deref->type->is_vector());
 
-   if (!ubo_var->RowMajor) {
+   if (!row_major) {
       ir_rvalue *offset = add(base_offset,
                              new(mem_ctx) ir_constant(deref_offset));
       base_ir->insert_before(assign(deref->clone(mem_ctx, NULL),