glsl: Drop exec_list argument to lower_ubo_reference
[mesa.git] / src / glsl / lower_ubo_reference.cpp
index 4e09b080e623ed3462895e02e8e2ec2ac02a85af..24806ac6ce911b43622d909ce0f9dc5f56c7e5bc 100644 (file)
@@ -203,55 +203,116 @@ static const char *
 interface_field_name(void *mem_ctx, char *base_name, ir_rvalue *d,
                      ir_rvalue **nonconst_block_index)
 {
-   ir_rvalue *previous_index = NULL;
    *nonconst_block_index = NULL;
+   char *name_copy = NULL;
+   size_t base_length = 0;
+
+   /* Loop back through the IR until we find the uniform block */
+   ir_rvalue *ir = d;
+   while (ir != NULL) {
+      switch (ir->ir_type) {
+      case ir_type_dereference_variable: {
+         /* Exit loop */
+         ir = NULL;
+         break;
+      }
+
+      case ir_type_dereference_record: {
+         ir_dereference_record *r = (ir_dereference_record *) ir;
+         ir = r->record->as_dereference();
+
+         /* If we got here it means any previous array subscripts belong to
+          * block members and not the block itself so skip over them in the
+          * next pass.
+          */
+         d = ir;
+         break;
+      }
+
+      case ir_type_dereference_array: {
+         ir_dereference_array *a = (ir_dereference_array *) ir;
+         ir = a->array->as_dereference();
+         break;
+      }
+
+      case ir_type_swizzle: {
+         ir_swizzle *s = (ir_swizzle *) ir;
+         ir = s->val->as_dereference();
+         /* Skip swizzle in the next pass */
+         d = ir;
+         break;
+      }
+
+      default:
+         assert(!"Should not get here.");
+         break;
+      }
+   }
 
    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()) {
-
-            ir_constant *const_index = previous_index->as_constant();
-            if (!const_index) {
-               *nonconst_block_index = previous_index;
-               return ralloc_asprintf(mem_ctx, "%s[0]", base_name);
-            } else {
-               return ralloc_asprintf(mem_ctx,
-                                      "%s[%d]",
-                                      base_name,
-                                      const_index->get_uint_component(0));
-            }
+         if (name_copy != NULL &&
+             v->var->is_interface_instance() &&
+             v->var->type->is_array()) {
+            return name_copy;
          } else {
+            *nonconst_block_index = NULL;
             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;
+         size_t new_length;
+
+         if (name_copy == NULL) {
+            name_copy = ralloc_strdup(mem_ctx, base_name);
+            base_length = strlen(name_copy);
+         }
+
+         /* For arrays of arrays we start at the innermost array and work our
+          * way out so we need to insert the subscript at the base of the
+          * name string rather than just attaching it to the end.
+          */
+         new_length = base_length;
+         ir_constant *const_index = a->array_index->as_constant();
+         char *end = ralloc_strdup(NULL, &name_copy[new_length]);
+         if (!const_index) {
+            ir_rvalue *array_index = a->array_index;
+            if (array_index->type != glsl_type::uint_type)
+               array_index = i2u(array_index);
+
+            if (a->array->type->is_array() &&
+                a->array->type->fields.array->is_array()) {
+               ir_constant *base_size = new(mem_ctx)
+                  ir_constant(a->array->type->fields.array->arrays_of_arrays_size());
+               array_index = mul(array_index, base_size);
+            }
+
+            if (*nonconst_block_index) {
+               *nonconst_block_index = add(*nonconst_block_index, array_index);
+            } else {
+               *nonconst_block_index = array_index;
+            }
+
+            ralloc_asprintf_rewrite_tail(&name_copy, &new_length, "[0]%s",
+                                         end);
+         } else {
+            ralloc_asprintf_rewrite_tail(&name_copy, &new_length, "[%d]%s",
+                                         const_index->get_uint_component(0),
+                                         end);
+         }
+         ralloc_free(end);
 
          d = a->array->as_dereference();
-         previous_index = a->array_index;
 
          break;
       }
-      case ir_type_swizzle: {
-         ir_swizzle *s = (ir_swizzle *) d;
 
-         d = s->val->as_dereference();
-         break;
-      }
       default:
          assert(!"Should not get here.");
          break;
@@ -277,27 +338,31 @@ lower_ubo_reference_visitor::setup_for_load_or_store(ir_variable *var,
       interface_field_name(mem_ctx, (char *) var->get_interface_type()->name,
                            deref, &nonconst_block_index);
 
-   /* Locate the ubo block by interface name */
+   /* Locate the block by interface name */
+   this->is_shader_storage = var->is_in_shader_storage_block();
+   unsigned num_blocks;
+   struct gl_uniform_block **blocks;
+   if (this->is_shader_storage) {
+      num_blocks = shader->NumShaderStorageBlocks;
+      blocks = shader->ShaderStorageBlocks;
+   } else {
+      num_blocks = shader->NumUniformBlocks;
+      blocks = shader->UniformBlocks;
+   }
    this->uniform_block = NULL;
-   for (unsigned i = 0; i < shader->NumUniformBlocks; i++) {
-      if (strcmp(field_name, shader->UniformBlocks[i].Name) == 0) {
+   for (unsigned i = 0; i < num_blocks; i++) {
+      if (strcmp(field_name, blocks[i]->Name) == 0) {
 
          ir_constant *index = new(mem_ctx) ir_constant(i);
 
          if (nonconst_block_index) {
-            if (nonconst_block_index->type != glsl_type::uint_type)
-               nonconst_block_index = i2u(nonconst_block_index);
             this->uniform_block = add(nonconst_block_index, index);
          } else {
             this->uniform_block = index;
          }
 
-         this->is_shader_storage = shader->UniformBlocks[i].IsShaderStorage;
-
-         struct gl_uniform_block *block = &shader->UniformBlocks[i];
-
          this->ubo_var = var->is_interface_instance()
-            ? &block->Uniforms[0] : &block->Uniforms[var->data.location];
+            ? &blocks[i]->Uniforms[0] : &blocks[i]->Uniforms[var->data.location];
 
          break;
       }
@@ -335,7 +400,7 @@ lower_ubo_reference_visitor::setup_for_load_or_store(ir_variable *var,
             if (deref_array->array->type->is_double())
                array_stride *= 2;
             *matrix_columns = deref_array->array->type->matrix_columns;
-         } else if (deref_array->type->is_interface()) {
+         } else if (deref_array->type->without_array()->is_interface()) {
             /* We're processing an array dereference of an interface instance
              * array. The thing being dereferenced *must* be a variable
              * dereference because interfaces cannot be embedded in other
@@ -344,7 +409,6 @@ lower_ubo_reference_visitor::setup_for_load_or_store(ir_variable *var,
              * 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 {
@@ -744,7 +808,31 @@ lower_ubo_reference_visitor::emit_access(bool is_write,
        * or 32 depending on the number of columns.
        */
       assert(matrix_columns <= 4);
-      unsigned matrix_stride = glsl_align(matrix_columns * N, 16);
+      unsigned matrix_stride = 0;
+      /* Matrix stride for std430 mat2xY matrices are not rounded up to
+       * vec4 size. From OpenGL 4.3 spec, section 7.6.2.2 "Standard Uniform
+       * Block Layout":
+       *
+       * "2. If the member is a two- or four-component vector with components
+       * consuming N basic machine units, the base alignment is 2N or 4N,
+       * respectively." [...]
+       * "4. If the member is an array of scalars or vectors, the base alignment
+       * and array stride are set to match the base alignment of a single array
+       * element, according to rules (1), (2), and (3), and rounded up to the
+       * base alignment of a vec4." [...]
+       * "7. If the member is a row-major matrix with C columns and R rows, the
+       * matrix is stored identically to an array of R row vectors with C
+       * components each, according to rule (4)." [...]
+       * "When using the std430 storage layout, shader storage blocks will be
+       * laid out in buffer storage identically to uniform and shader storage
+       * blocks using the std140 layout, except that the base alignment and
+       * stride of arrays of scalars and vectors in rule 4 and of structures in
+       * rule 9 are not rounded up a multiple of the base alignment of a vec4."
+       */
+      if (packing == GLSL_INTERFACE_PACKING_STD430 && matrix_columns == 2)
+         matrix_stride = 2 * N;
+      else
+         matrix_stride = glsl_align(matrix_columns * N, 16);
 
       const glsl_type *deref_type = deref->type->base_type == GLSL_TYPE_FLOAT ?
          glsl_type::float_type : glsl_type::double_type;
@@ -754,6 +842,12 @@ lower_ubo_reference_visitor::emit_access(bool is_write,
             add(base_offset,
                 new(mem_ctx) ir_constant(deref_offset + i * matrix_stride));
          if (is_write) {
+            /* If the component is not in the writemask, then don't
+             * store any value.
+             */
+            if (!((1 << i) & write_mask))
+               continue;
+
             base_ir->insert_after(ssbo_store(swizzle(deref, i, 1), chan_offset, 1));
          } else {
             if (!this->is_shader_storage) {
@@ -922,12 +1016,14 @@ lower_ubo_reference_visitor::calculate_unsized_array_stride(ir_dereference *dere
    case ir_type_dereference_record:
    {
       ir_dereference_record *deref_record = (ir_dereference_record *) deref;
-      const struct glsl_type *deref_record_type =
-         deref_record->record->as_dereference()->type;
-      unsigned record_length = deref_record_type->length;
+      ir_dereference *interface_deref =
+         deref_record->record->as_dereference();
+      assert(interface_deref != NULL);
+      const struct glsl_type *interface_type = interface_deref->type;
+      unsigned record_length = interface_type->length;
       /* Unsized array is always the last element of the interface */
       const struct glsl_type *unsized_array_type =
-         deref_record_type->fields.structure[record_length - 1].type->fields.array;
+         interface_type->fields.structure[record_length - 1].type->fields.array;
 
       const bool array_row_major =
          is_dereferenced_thing_row_major(deref_record);
@@ -1174,7 +1270,7 @@ lower_ubo_reference_visitor::visit_enter(ir_call *ir)
 } /* unnamed namespace */
 
 void
-lower_ubo_reference(struct gl_shader *shader, exec_list *instructions)
+lower_ubo_reference(struct gl_shader *shader)
 {
    lower_ubo_reference_visitor v(shader);
 
@@ -1185,6 +1281,6 @@ lower_ubo_reference(struct gl_shader *shader, exec_list *instructions)
     */
    do {
       v.progress = false;
-      visit_list_elements(&v, instructions);
+      visit_list_elements(&v, shader->ir);
    } while (v.progress);
 }