Example #1
0
 virtual void leave_record(const glsl_type *type, const char *,
                           bool row_major, const unsigned packing) {
    assert(type->is_record());
    if (this->buffer_block_index == -1)
       return;
    if (packing == GLSL_INTERFACE_PACKING_STD430)
       this->ubo_byte_offset = glsl_align(
          this->ubo_byte_offset, type->std430_base_alignment(row_major));
    else
       this->ubo_byte_offset = glsl_align(
          this->ubo_byte_offset, type->std140_base_alignment(row_major));
 }
   virtual void visit_field(const glsl_type *type, const char *name,
                            bool row_major, const glsl_type *record_type)
   {
      assert(this->index < this->num_variables);

      gl_uniform_buffer_variable *v = &this->variables[this->index++];

      v->Name = ralloc_strdup(mem_ctx, name);
      v->Type = type;
      v->RowMajor = row_major;

      if (this->is_array_instance) {
         v->IndexName = ralloc_strdup(mem_ctx, name);

         char *open_bracket = strchr(v->IndexName, '[');
         assert(open_bracket != NULL);

         char *close_bracket = strchr(open_bracket, ']');
         assert(close_bracket != NULL);

         /* Length of the tail without the ']' but with the NUL.
          */
         unsigned len = strlen(close_bracket + 1) + 1;

         memmove(open_bracket, close_bracket + 1, len);
     } else {
         v->IndexName = v->Name;
      }

      const unsigned alignment = record_type
	 ? record_type->std140_base_alignment(!!v->RowMajor)
	 : type->std140_base_alignment(!!v->RowMajor);
      unsigned size = type->std140_size(!!v->RowMajor);

      this->offset = glsl_align(this->offset, alignment);
      v->Offset = this->offset;
      this->offset += size;

      /* From the GL_ARB_uniform_buffer_object spec:
       *
       *     "For uniform blocks laid out according to [std140] rules, the
       *      minimum buffer object size returned by the
       *      UNIFORM_BLOCK_DATA_SIZE query is derived by taking the offset of
       *      the last basic machine unit consumed by the last uniform of the
       *      uniform block (including any end-of-array or end-of-structure
       *      padding), adding one, and rounding up to the next multiple of
       *      the base alignment required for a vec4."
       */
      this->buffer_size = glsl_align(this->offset, 16);
   }
Example #3
0
 virtual void leave_record(const glsl_type *type, const char *,
                           bool row_major) {
     assert(type->is_record());
     if (this->ubo_block_index == -1)
         return;
     this->ubo_byte_offset = glsl_align(
                                 this->ubo_byte_offset, type->std140_base_alignment(row_major));
 }
 virtual void visit_field(const glsl_struct_field *field)
 {
    /* FINISHME: When support for doubles (dvec4, etc.) is added to the
     * FINISHME: compiler, this may be incorrect for a structure in a UBO
     * FINISHME: like struct s { struct { float f } s1; dvec4 v; };.
     */
    this->offset = glsl_align(this->offset,
                              field->type->std140_base_alignment(false));
 }
   virtual void visit_field(const glsl_type *type, const char *name,
                            bool row_major)
   {
      assert(!type->is_record());
      assert(!(type->is_array() && type->fields.array->is_record()));
      assert(!type->is_interface());
      assert(!(type->is_array() && type->fields.array->is_interface()));

      (void) row_major;

      unsigned id;
      bool found = this->map->get(id, name);
      assert(found);

      if (!found)
	 return;

      /* If there is already storage associated with this uniform, it means
       * that it was set while processing an earlier shader stage.  For
       * example, we may be processing the uniform in the fragment shader, but
       * the uniform was already processed in the vertex shader.
       */
      if (this->uniforms[id].storage != NULL) {
	 /* If the uniform already has storage set from another shader stage,
	  * mark the samplers used for this shader stage.
	  */
	 if (type->contains_sampler()) {
	    const unsigned count = MAX2(1, this->uniforms[id].array_elements);
	    const unsigned shadow = (type->is_array())
	       ? type->fields.array->sampler_shadow : type->sampler_shadow;

	    for (unsigned i = 0; i < count; i++) {
	       const unsigned s = this->uniforms[id].sampler + i;

	       this->shader_samplers_used |= 1U << s;
	       this->shader_shadow_samplers |= shadow << s;
	    }
	 }

	 return;
      }

      const glsl_type *base_type;
      if (type->is_array()) {
	 this->uniforms[id].array_elements = type->length;
	 base_type = type->fields.array;
      } else {
	 this->uniforms[id].array_elements = 0;
	 base_type = type;
      }

      if (base_type->is_sampler()) {
	 this->uniforms[id].sampler = this->next_sampler;

	 /* Increment the sampler by 1 for non-arrays and by the number of
	  * array elements for arrays.
	  */
	 this->next_sampler += MAX2(1, this->uniforms[id].array_elements);

	 const gl_texture_index target = base_type->sampler_index();
	 const unsigned shadow = base_type->sampler_shadow;
	 for (unsigned i = this->uniforms[id].sampler
		 ; i < MIN2(this->next_sampler, MAX_SAMPLERS)
		 ; i++) {
	    this->targets[i] = target;
	    this->shader_samplers_used |= 1U << i;
	    this->shader_shadow_samplers |= shadow << i;
	 }

      } else {
	 this->uniforms[id].sampler = ~0;
      }

      this->uniforms[id].name = ralloc_strdup(this->uniforms, name);
      this->uniforms[id].type = base_type;
      this->uniforms[id].initialized = 0;
      this->uniforms[id].num_driver_storage = 0;
      this->uniforms[id].driver_storage = NULL;
      this->uniforms[id].storage = this->values;
      if (this->ubo_block_index != -1) {
	 this->uniforms[id].block_index = this->ubo_block_index;

	 unsigned alignment = type->std140_base_alignment(ubo_row_major);
	 this->ubo_byte_offset = glsl_align(this->ubo_byte_offset, alignment);
	 this->uniforms[id].offset = this->ubo_byte_offset;
	 this->ubo_byte_offset += type->std140_size(ubo_row_major);

	 if (type->is_array()) {
	    this->uniforms[id].array_stride =
	       glsl_align(type->fields.array->std140_size(ubo_row_major), 16);
	 } else {
	    this->uniforms[id].array_stride = 0;
	 }

	 if (type->is_matrix() ||
	     (type->is_array() && type->fields.array->is_matrix())) {
	    this->uniforms[id].matrix_stride = 16;
	    this->uniforms[id].row_major = ubo_row_major;
	 } else {
	    this->uniforms[id].matrix_stride = 0;
	    this->uniforms[id].row_major = false;
	 }
      } else {
	 this->uniforms[id].block_index = -1;
	 this->uniforms[id].offset = -1;
	 this->uniforms[id].array_stride = -1;
	 this->uniforms[id].matrix_stride = -1;
	 this->uniforms[id].row_major = false;
      }

      this->values += values_for_type(type);
   }
   virtual void visit_field(const glsl_type *type, const char *name,
                            bool row_major, const glsl_type *record_type,
                            bool last_field)
   {
      assert(!type->without_array()->is_record());
      assert(!type->without_array()->is_interface());

      unsigned id;
      bool found = this->map->get(id, name);
      assert(found);

      if (!found)
	 return;

      const glsl_type *base_type;
      if (type->is_array()) {
	 this->uniforms[id].array_elements = type->length;
	 base_type = type->fields.array;
      } else {
	 this->uniforms[id].array_elements = 0;
	 base_type = type;
      }

      /* This assigns uniform indices to sampler and image uniforms. */
      handle_samplers(base_type, &this->uniforms[id]);
      handle_images(base_type, &this->uniforms[id]);

      /* If there is already storage associated with this uniform, it means
       * that it was set while processing an earlier shader stage.  For
       * example, we may be processing the uniform in the fragment shader, but
       * the uniform was already processed in the vertex shader.
       */
      if (this->uniforms[id].storage != NULL) {
         return;
      }

      /* Assign explicit locations. */
      if (current_var->data.explicit_location) {
         /* Set sequential locations for struct fields. */
         if (record_type != NULL) {
            const unsigned entries = MAX2(1, this->uniforms[id].array_elements);
            this->uniforms[id].remap_location =
               current_var->data.location + field_counter;
            field_counter += entries;
         } else {
            this->uniforms[id].remap_location = current_var->data.location;
         }
      } else {
         /* Initialize to to indicate that no location is set */
         this->uniforms[id].remap_location = UNMAPPED_UNIFORM_LOC;
      }

      this->uniforms[id].name = ralloc_strdup(this->uniforms, name);
      this->uniforms[id].type = base_type;
      this->uniforms[id].initialized = 0;
      this->uniforms[id].num_driver_storage = 0;
      this->uniforms[id].driver_storage = NULL;
      this->uniforms[id].storage = this->values;
      this->uniforms[id].atomic_buffer_index = -1;
      if (this->ubo_block_index != -1) {
	 this->uniforms[id].block_index = this->ubo_block_index;

	 const unsigned alignment = record_type
	    ? record_type->std140_base_alignment(row_major)
	    : type->std140_base_alignment(row_major);
	 this->ubo_byte_offset = glsl_align(this->ubo_byte_offset, alignment);
	 this->uniforms[id].offset = this->ubo_byte_offset;
	 this->ubo_byte_offset += type->std140_size(row_major);

         if (last_field)
            this->ubo_byte_offset = glsl_align(this->ubo_byte_offset, 16);

	 if (type->is_array()) {
	    this->uniforms[id].array_stride =
	       glsl_align(type->fields.array->std140_size(row_major), 16);
	 } else {
	    this->uniforms[id].array_stride = 0;
	 }

	 if (type->without_array()->is_matrix()) {
	    this->uniforms[id].matrix_stride = 16;
	    this->uniforms[id].row_major = row_major;
	 } else {
	    this->uniforms[id].matrix_stride = 0;
	    this->uniforms[id].row_major = false;
	 }
      } else {
	 this->uniforms[id].block_index = -1;
	 this->uniforms[id].offset = -1;
	 this->uniforms[id].array_stride = -1;
	 this->uniforms[id].matrix_stride = -1;
	 this->uniforms[id].row_major = false;
      }

      this->values += values_for_type(type);
   }
Example #7
0
unsigned
glsl_type::std140_size(bool row_major) const
{
   /* (1) If the member is a scalar consuming <N> basic machine units, the
    *     base alignment is <N>.
    *
    * (2) If the member is a two- or four-component vector with components
    *     consuming <N> basic machine units, the base alignment is 2<N> or
    *     4<N>, respectively.
    *
    * (3) If the member is a three-component vector with components consuming
    *     <N> basic machine units, the base alignment is 4<N>.
    */
   if (this->is_scalar() || this->is_vector()) {
      return this->vector_elements * 4;
   }

   /* (5) If the member is a column-major matrix with <C> columns and
    *     <R> rows, the matrix is stored identically to an array of
    *     <C> column vectors with <R> components each, according to
    *     rule (4).
    *
    * (6) If the member is an array of <S> column-major matrices with <C>
    *     columns and <R> rows, the matrix is stored identically to a row of
    *     <S>*<C> column vectors with <R> components each, according to rule
    *     (4).
    *
    * (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).
    *
    * (8) If the member is an array of <S> row-major matrices with <C> columns
    *     and <R> rows, the matrix is stored identically to a row of <S>*<R>
    *     row vectors with <C> components each, according to rule (4).
    */
   if (this->is_matrix() || (this->is_array() &&
			     this->fields.array->is_matrix())) {
      const struct glsl_type *element_type;
      const struct glsl_type *vec_type;
      unsigned int array_len;

      if (this->is_array()) {
	 element_type = this->fields.array;
	 array_len = this->length;
      } else {
	 element_type = this;
	 array_len = 1;
      }

      if (row_major) {
	 vec_type = get_instance(GLSL_TYPE_FLOAT,
				 element_type->matrix_columns, 1);
	 array_len *= element_type->vector_elements;
      } else {
	 vec_type = get_instance(GLSL_TYPE_FLOAT,
				 element_type->vector_elements, 1);
	 array_len *= element_type->matrix_columns;
      }
      const glsl_type *array_type = glsl_type::get_array_instance(vec_type,
								  array_len);

      return array_type->std140_size(false);
   }

   /* (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. The array may have padding at the
    *     end; the base offset of the member following the array is rounded up
    *     to the next multiple of the base alignment.
    *
    * (10) If the member is an array of <S> structures, the <S> elements of
    *      the array are laid out in order, according to rule (9).
    */
   if (this->is_array()) {
      if (this->fields.array->is_record()) {
	 return this->length * this->fields.array->std140_size(row_major);
      } else {
	 unsigned element_base_align =
	    this->fields.array->std140_base_alignment(row_major);
	 return this->length * MAX2(element_base_align, 16);
      }
   }

   /* (9) If the member is a structure, the base alignment of the
    *     structure is <N>, where <N> is the largest base alignment
    *     value of any of its members, and rounded up to the base
    *     alignment of a vec4. The individual members of this
    *     sub-structure are then assigned offsets by applying this set
    *     of rules recursively, where the base offset of the first
    *     member of the sub-structure is equal to the aligned offset
    *     of the structure. The structure may have padding at the end;
    *     the base offset of the member following the sub-structure is
    *     rounded up to the next multiple of the base alignment of the
    *     structure.
    */
   if (this->is_record()) {
      unsigned size = 0;
      for (unsigned i = 0; i < this->length; i++) {
	 const struct glsl_type *field_type = this->fields.structure[i].type;
	 unsigned align = field_type->std140_base_alignment(row_major);
	 size = glsl_align(size, align);
	 size += field_type->std140_size(row_major);
      }
      size = glsl_align(size,
			this->fields.structure[0].type->std140_base_alignment(row_major));
      return size;
   }

   assert(!"not reached");
   return -1;
}
Example #8
0
   virtual void visit_field(const glsl_type *type, const char *name,
                            bool row_major)
   {
      assert(!type->is_record());
      assert(!(type->is_array() && type->fields.array->is_record()));
      assert(!type->is_interface());
      assert(!(type->is_array() && type->fields.array->is_interface()));

      (void) row_major;

      unsigned id;
      bool found = this->map->get(id, name);
      assert(found);

      if (!found)
	 return;

      const glsl_type *base_type;
      if (type->is_array()) {
	 this->uniforms[id].array_elements = type->length;
	 base_type = type->fields.array;
      } else {
	 this->uniforms[id].array_elements = 0;
	 base_type = type;
      }

      /* This assigns sampler uniforms to sampler units. */
      handle_samplers(base_type, &this->uniforms[id]);

      /* If there is already storage associated with this uniform, it means
       * that it was set while processing an earlier shader stage.  For
       * example, we may be processing the uniform in the fragment shader, but
       * the uniform was already processed in the vertex shader.
       */
      if (this->uniforms[id].storage != NULL) {
         return;
      }

      this->uniforms[id].name = ralloc_strdup(this->uniforms, name);
      this->uniforms[id].type = base_type;
      this->uniforms[id].initialized = 0;
      this->uniforms[id].num_driver_storage = 0;
      this->uniforms[id].driver_storage = NULL;
      this->uniforms[id].storage = this->values;
      if (this->ubo_block_index != -1) {
	 this->uniforms[id].block_index = this->ubo_block_index;

	 unsigned alignment = type->std140_base_alignment(ubo_row_major);
	 this->ubo_byte_offset = glsl_align(this->ubo_byte_offset, alignment);
	 this->uniforms[id].offset = this->ubo_byte_offset;
	 this->ubo_byte_offset += type->std140_size(ubo_row_major);

	 if (type->is_array()) {
	    this->uniforms[id].array_stride =
	       glsl_align(type->fields.array->std140_size(ubo_row_major), 16);
	 } else {
	    this->uniforms[id].array_stride = 0;
	 }

	 if (type->is_matrix() ||
	     (type->is_array() && type->fields.array->is_matrix())) {
	    this->uniforms[id].matrix_stride = 16;
	    this->uniforms[id].row_major = ubo_row_major;
	 } else {
	    this->uniforms[id].matrix_stride = 0;
	    this->uniforms[id].row_major = false;
	 }
      } else {
	 this->uniforms[id].block_index = -1;
	 this->uniforms[id].offset = -1;
	 this->uniforms[id].array_stride = -1;
	 this->uniforms[id].matrix_stride = -1;
	 this->uniforms[id].row_major = false;
      }

      this->values += values_for_type(type);
   }
Example #9
0
    virtual void visit_field(const glsl_type *type, const char *name,
                             bool row_major, const glsl_type *record_type,
                             bool /* last_field */)
    {
        assert(!type->without_array()->is_record());
        assert(!type->without_array()->is_interface());

        unsigned id;
        bool found = this->map->get(id, name);
        assert(found);

        if (!found)
            return;

        const glsl_type *base_type;
        if (type->is_array()) {
            this->uniforms[id].array_elements = type->length;
            base_type = type->fields.array;
        } else {
            this->uniforms[id].array_elements = 0;
            base_type = type;
        }

        /* This assigns uniform indices to sampler and image uniforms. */
        handle_samplers(base_type, &this->uniforms[id]);
        handle_images(base_type, &this->uniforms[id]);
        handle_subroutines(base_type, &this->uniforms[id]);

        /* If there is already storage associated with this uniform or if the
         * uniform is set as builtin, it means that it was set while processing
         * an earlier shader stage.  For example, we may be processing the
         * uniform in the fragment shader, but the uniform was already processed
         * in the vertex shader.
         */
        if (this->uniforms[id].storage != NULL || this->uniforms[id].builtin) {
            return;
        }

        /* Assign explicit locations. */
        if (current_var->data.explicit_location) {
            /* Set sequential locations for struct fields. */
            if (record_type != NULL) {
                const unsigned entries = MAX2(1, this->uniforms[id].array_elements);
                this->uniforms[id].remap_location =
                    current_var->data.location + field_counter;
                field_counter += entries;
            } else {
                this->uniforms[id].remap_location = current_var->data.location;
            }
        } else {
            /* Initialize to to indicate that no location is set */
            this->uniforms[id].remap_location = UNMAPPED_UNIFORM_LOC;
        }

        this->uniforms[id].name = ralloc_strdup(this->uniforms, name);
        this->uniforms[id].type = base_type;
        this->uniforms[id].initialized = 0;
        this->uniforms[id].num_driver_storage = 0;
        this->uniforms[id].driver_storage = NULL;
        this->uniforms[id].atomic_buffer_index = -1;
        this->uniforms[id].hidden =
            current_var->data.how_declared == ir_var_hidden;
        this->uniforms[id].builtin = is_gl_identifier(name);

        /* Do not assign storage if the uniform is builtin */
        if (!this->uniforms[id].builtin)
            this->uniforms[id].storage = this->values;

        if (this->ubo_block_index != -1) {
            this->uniforms[id].block_index = this->ubo_block_index;

            const unsigned alignment = type->std140_base_alignment(row_major);
            this->ubo_byte_offset = glsl_align(this->ubo_byte_offset, alignment);
            this->uniforms[id].offset = this->ubo_byte_offset;
            this->ubo_byte_offset += type->std140_size(row_major);

            if (type->is_array()) {
                this->uniforms[id].array_stride =
                    glsl_align(type->fields.array->std140_size(row_major), 16);
            } else {
                this->uniforms[id].array_stride = 0;
            }

            if (type->without_array()->is_matrix()) {
                const glsl_type *matrix = type->without_array();
                const unsigned N = matrix->base_type == GLSL_TYPE_DOUBLE ? 8 : 4;
                const unsigned items = row_major ? matrix->matrix_columns : matrix->vector_elements;

                assert(items <= 4);
                this->uniforms[id].matrix_stride = glsl_align(items * N, 16);
                this->uniforms[id].row_major = row_major;
            } else {
                this->uniforms[id].matrix_stride = 0;
                this->uniforms[id].row_major = false;
            }
        } else {
            this->uniforms[id].block_index = -1;
            this->uniforms[id].offset = -1;
            this->uniforms[id].array_stride = -1;
            this->uniforms[id].matrix_stride = -1;
            this->uniforms[id].row_major = false;
        }

        this->values += values_for_type(type);
    }
/**
 * Takes a deref and recursively calls itself to break the deref down to the
 * point that the reads or writes generated are contiguous scalars or vectors.
 */
void
lower_buffer_access::emit_access(void *mem_ctx,
                                 bool is_write,
                                 ir_dereference *deref,
                                 ir_variable *base_offset,
                                 unsigned int deref_offset,
                                 bool row_major,
                                 int matrix_columns,
                                 unsigned int packing,
                                 unsigned int write_mask)
{
   if (deref->type->is_record()) {
      unsigned int field_offset = 0;

      for (unsigned i = 0; i < deref->type->length; i++) {
         const struct glsl_struct_field *field =
            &deref->type->fields.structure[i];
         ir_dereference *field_deref =
            new(mem_ctx) ir_dereference_record(deref->clone(mem_ctx, NULL),
                                               field->name);

         field_offset =
            glsl_align(field_offset,
                       field->type->std140_base_alignment(row_major));

         emit_access(mem_ctx, is_write, field_deref, base_offset,
                     deref_offset + field_offset,
                     row_major, 1, packing,
                     writemask_for_size(field_deref->type->vector_elements));

         field_offset += field->type->std140_size(row_major);
      }
      return;
   }

   if (deref->type->is_array()) {
      unsigned array_stride = packing == GLSL_INTERFACE_PACKING_STD430 ?
         deref->type->fields.array->std430_array_stride(row_major) :
         glsl_align(deref->type->fields.array->std140_size(row_major), 16);

      for (unsigned i = 0; i < deref->type->length; i++) {
         ir_constant *element = new(mem_ctx) ir_constant(i);
         ir_dereference *element_deref =
            new(mem_ctx) ir_dereference_array(deref->clone(mem_ctx, NULL),
                                              element);
         emit_access(mem_ctx, is_write, element_deref, base_offset,
                     deref_offset + i * array_stride,
                     row_major, 1, packing,
                     writemask_for_size(element_deref->type->vector_elements));
      }
      return;
   }

   if (deref->type->is_matrix()) {
      for (unsigned i = 0; i < deref->type->matrix_columns; i++) {
         ir_constant *col = new(mem_ctx) ir_constant(i);
         ir_dereference *col_deref =
            new(mem_ctx) ir_dereference_array(deref->clone(mem_ctx, NULL), col);

         if (row_major) {
            /* For a row-major matrix, the next column starts at the next
             * element.
             */
            int size_mul = deref->type->is_double() ? 8 : 4;
            emit_access(mem_ctx, is_write, col_deref, base_offset,
                        deref_offset + i * size_mul,
                        row_major, deref->type->matrix_columns, packing,
                        writemask_for_size(col_deref->type->vector_elements));
         } else {
            int size_mul;

            /* std430 doesn't round up vec2 size to a vec4 size */
            if (packing == GLSL_INTERFACE_PACKING_STD430 &&
                deref->type->vector_elements == 2 &&
                !deref->type->is_double()) {
               size_mul = 8;
            } else {
               /* std140 always rounds the stride of arrays (and matrices) to a
                * vec4, so matrices are always 16 between columns/rows. With
                * doubles, they will be 32 apart when there are more than 2 rows.
                *
                * For both std140 and std430, if the member is a
                * three-'component vector with components consuming N basic
                * machine units, the base alignment is 4N. For vec4, base
                * alignment is 4N.
                */
               size_mul = (deref->type->is_double() &&
                           deref->type->vector_elements > 2) ? 32 : 16;
            }

            emit_access(mem_ctx, is_write, col_deref, base_offset,
                        deref_offset + i * size_mul,
                        row_major, deref->type->matrix_columns, packing,
                        writemask_for_size(col_deref->type->vector_elements));
         }
      }
      return;
   }

   assert(deref->type->is_scalar() || deref->type->is_vector());

   if (!row_major) {
      ir_rvalue *offset =
         add(base_offset, new(mem_ctx) ir_constant(deref_offset));
      unsigned mask =
         is_write ? write_mask : (1 << deref->type->vector_elements) - 1;
      insert_buffer_access(mem_ctx, deref, deref->type, offset, mask, -1);
   } else {
      unsigned N = deref->type->is_double() ? 8 : 4;

      /* We're dereffing a column out of a row-major matrix, so we
       * gather the vector from each stored row.
      */
      assert(deref->type->base_type == GLSL_TYPE_FLOAT ||
             deref->type->base_type == GLSL_TYPE_DOUBLE);
      /* Matrices, row_major or not, are stored as if they were
       * arrays of vectors of the appropriate size in std140.
       * Arrays have their strides rounded up to a vec4, so the
       * matrix stride is always 16. However a double matrix may either be 16
       * or 32 depending on the number of columns.
       */
      assert(matrix_columns <= 4);
      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;

      for (unsigned i = 0; i < deref->type->vector_elements; i++) {
         ir_rvalue *chan_offset =
            add(base_offset,
                new(mem_ctx) ir_constant(deref_offset + i * matrix_stride));
         if (!is_write || ((1U << i) & write_mask))
            insert_buffer_access(mem_ctx, deref, deref_type, chan_offset,
                                 (1U << i), i);
      }
   }
}
/**
 * This function initializes various values that will be used later by
 * emit_access when actually emitting loads or stores.
 *
 * Note: const_offset is an input as well as an output, clients must
 * initialize it to the offset of the variable in the underlying block, and
 * this function will adjust it by adding the constant offset of the member
 * being accessed into that variable.
 */
void
lower_buffer_access::setup_buffer_access(void *mem_ctx,
                                         ir_variable *var,
                                         ir_rvalue *deref,
                                         ir_rvalue **offset,
                                         unsigned *const_offset,
                                         bool *row_major,
                                         int *matrix_columns,
                                         const glsl_struct_field **struct_field,
                                         unsigned packing)
{
   *offset = new(mem_ctx) ir_constant(0u);
   *row_major = is_dereferenced_thing_row_major(deref);
   *matrix_columns = 1;

   /* Calculate the offset to the start of the region of the UBO
    * dereferenced by *rvalue.  This may be a variable offset if an
    * array dereference has a variable index.
    */
   while (deref) {
      switch (deref->ir_type) {
      case ir_type_dereference_variable: {
         deref = NULL;
         break;
      }

      case ir_type_dereference_array: {
         ir_dereference_array *deref_array = (ir_dereference_array *) deref;
         unsigned array_stride;
         if (deref_array->array->type->is_vector()) {
            /* We get this when storing or loading a component out of a vector
             * with a non-constant index. This happens for v[i] = f where v is
             * a vector (or m[i][j] = f where m is a matrix). If we don't
             * lower that here, it gets turned into v = vector_insert(v, i,
             * f), which loads the entire vector, modifies one component and
             * then write the entire thing back.  That breaks if another
             * thread or SIMD channel is modifying the same vector.
             */
            array_stride = 4;
            if (deref_array->array->type->is_double())
               array_stride *= 2;
         } else if (deref_array->array->type->is_matrix() && *row_major) {
            /* When loading a vector out of a row major matrix, the
             * step between the columns (vectors) is the size of a
             * float, while the step between the rows (elements of a
             * vector) is handled below in emit_ubo_loads.
             */
            array_stride = 4;
            if (deref_array->array->type->is_double())
               array_stride *= 2;
            *matrix_columns = deref_array->array->type->matrix_columns;
         } 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
             * 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.
             */
            deref = deref_array->array->as_dereference();
            break;
         } else {
            /* Whether or not the field is row-major (because it might be a
             * bvec2 or something) does not affect the array itself. We need
             * to know whether an array element in its entirety is row-major.
             */
            const bool array_row_major =
               is_dereferenced_thing_row_major(deref_array);

            /* The array type will give the correct interface packing
             * information
             */
            if (packing == GLSL_INTERFACE_PACKING_STD430) {
               array_stride = deref_array->type->std430_array_stride(array_row_major);
            } else {
               array_stride = deref_array->type->std140_size(array_row_major);
               array_stride = glsl_align(array_stride, 16);
            }
         }

         ir_rvalue *array_index = deref_array->array_index;
         if (array_index->type->base_type == GLSL_TYPE_INT)
            array_index = i2u(array_index);

         ir_constant *const_index =
            array_index->constant_expression_value(NULL);
         if (const_index) {
            *const_offset += array_stride * const_index->value.u[0];
         } else {
            *offset = add(*offset,
                          mul(array_index,
                              new(mem_ctx) ir_constant(array_stride)));
         }
         deref = deref_array->array->as_dereference();
         break;
      }

      case ir_type_dereference_record: {
         ir_dereference_record *deref_record = (ir_dereference_record *) deref;
         const glsl_type *struct_type = deref_record->record->type;
         unsigned intra_struct_offset = 0;

         for (unsigned int i = 0; i < struct_type->length; i++) {
            const glsl_type *type = struct_type->fields.structure[i].type;

            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 = 0;

            if (packing == GLSL_INTERFACE_PACKING_STD430)
               field_align = type->std430_base_alignment(field_row_major);
            else
               field_align = type->std140_base_alignment(field_row_major);

            intra_struct_offset = glsl_align(intra_struct_offset, field_align);

            if (strcmp(struct_type->fields.structure[i].name,
                       deref_record->field) == 0) {
               if (struct_field)
                  *struct_field = &struct_type->fields.structure[i];
               break;
            }

            if (packing == GLSL_INTERFACE_PACKING_STD430)
               intra_struct_offset += type->std430_size(field_row_major);
            else
               intra_struct_offset += type->std140_size(field_row_major);

            /* If the field just examined was itself a structure, apply rule
             * #9:
             *
             *     "The structure may have padding at the end; the base offset
             *     of the member following the sub-structure is rounded up to
             *     the next multiple of the base alignment of the structure."
             */
            if (type->without_array()->is_record()) {
               intra_struct_offset = glsl_align(intra_struct_offset,
                                                field_align);

            }
         }

         *const_offset += intra_struct_offset;
         deref = deref_record->record->as_dereference();
         break;
      }

      case ir_type_swizzle: {
         ir_swizzle *deref_swizzle = (ir_swizzle *) deref;

         assert(deref_swizzle->mask.num_components == 1);

         *const_offset += deref_swizzle->mask.x * sizeof(int);
         deref = deref_swizzle->val->as_dereference();
         break;
      }

      default:
         assert(!"not reached");
         deref = NULL;
         break;
      }
   }
}
 virtual void visit_field(const glsl_struct_field *field)
 {
    this->offset = glsl_align(this->offset,
                              field->type->std140_base_alignment(false));
 }