nir/glsl: Add an explicit_alignment field to glsl_type
authorJason Ekstrand <jason@jlekstrand.net>
Sat, 29 Aug 2020 23:01:46 +0000 (18:01 -0500)
committerMarge Bot <eric+marge@anholt.net>
Thu, 3 Sep 2020 18:02:50 +0000 (18:02 +0000)
When creating explicit type, the alignment information is lost, thus
forcing explicit type users to recalculate the alignment using the same
size_align() function. Let's add a new field to cache this information.

Only structs, matrices, and vectors have and explicit alignment.  Arrays
alignment is implicitly set to its element alignment and matrices are
required to have an alignment that matches that of its vector columns.
the concept of alignment simply doesn't apply to other types.

We make the strategic choice to not allow explicit alignments on
scalars.  This is for a couple of reasons:

 1. There are no cases today where we use explicit types where we want
    any other alignment for scalars than natural alignment.

 2. Vectors don't have a component alignment that's separate from the
    explicit_alignment so it's impossible to get an explicitly aligned
    scalar type which is the component of the explicitly aligned vector
    type.

This choice may cause problems if we ever want to use explicitly laid
out types for things like varyings where we sometimes want vec4
alignment of scalars.  We can deal with that when the time comes.

Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/6472>

src/compiler/glsl_types.cpp
src/compiler/glsl_types.h
src/compiler/nir_types.cpp
src/compiler/nir_types.h

index 1aeb44395447a8ab1e94a602f9c3af2c496e5013..288ddcf5dea9ac39e10d6119f2dc531cdbf688cd 100644 (file)
@@ -46,13 +46,15 @@ static uint32_t glsl_type_users = 0;
 glsl_type::glsl_type(GLenum gl_type,
                      glsl_base_type base_type, unsigned vector_elements,
                      unsigned matrix_columns, const char *name,
-                     unsigned explicit_stride, bool row_major) :
+                     unsigned explicit_stride, bool row_major,
+                     unsigned explicit_alignment) :
    gl_type(gl_type),
    base_type(base_type), sampled_type(GLSL_TYPE_VOID),
    sampler_dimensionality(0), sampler_shadow(0), sampler_array(0),
    interface_packing(0), interface_row_major(row_major), packed(0),
    vector_elements(vector_elements), matrix_columns(matrix_columns),
-   length(0), explicit_stride(explicit_stride)
+   length(0), explicit_stride(explicit_stride),
+   explicit_alignment(explicit_alignment)
 {
    /* Values of these types must fit in the two bits of
     * glsl_type::sampled_type.
@@ -75,6 +77,7 @@ glsl_type::glsl_type(GLenum gl_type,
    /* Neither dimension is zero or both dimensions are zero.
     */
    assert((vector_elements == 0) == (matrix_columns == 0));
+   assert(util_is_power_of_two_or_zero(explicit_alignment));
    memset(& fields, 0, sizeof(fields));
 }
 
@@ -86,7 +89,7 @@ glsl_type::glsl_type(GLenum gl_type, glsl_base_type base_type,
    sampler_dimensionality(dim), sampler_shadow(shadow),
    sampler_array(array), interface_packing(0),
    interface_row_major(0), packed(0),
-   length(0), explicit_stride(0)
+   length(0), explicit_stride(0), explicit_alignment(0)
 {
    this->mem_ctx = ralloc_context(NULL);
    assert(this->mem_ctx != NULL);
@@ -100,16 +103,20 @@ glsl_type::glsl_type(GLenum gl_type, glsl_base_type base_type,
 }
 
 glsl_type::glsl_type(const glsl_struct_field *fields, unsigned num_fields,
-                     const char *name, bool packed) :
+                     const char *name, bool packed,
+                     unsigned explicit_alignment) :
    gl_type(0),
    base_type(GLSL_TYPE_STRUCT), sampled_type(GLSL_TYPE_VOID),
    sampler_dimensionality(0), sampler_shadow(0), sampler_array(0),
    interface_packing(0), interface_row_major(0), packed(packed),
    vector_elements(0), matrix_columns(0),
-   length(num_fields), explicit_stride(0)
+   length(num_fields), explicit_stride(0),
+   explicit_alignment(explicit_alignment)
 {
    unsigned int i;
 
+   assert(util_is_power_of_two_or_zero(explicit_alignment));
+
    this->mem_ctx = ralloc_context(NULL);
    assert(this->mem_ctx != NULL);
 
@@ -136,7 +143,7 @@ glsl_type::glsl_type(const glsl_struct_field *fields, unsigned num_fields,
    interface_packing((unsigned) packing),
    interface_row_major((unsigned) row_major), packed(0),
    vector_elements(0), matrix_columns(0),
-   length(num_fields), explicit_stride(0)
+   length(num_fields), explicit_stride(0), explicit_alignment(0)
 {
    unsigned int i;
 
@@ -161,7 +168,7 @@ glsl_type::glsl_type(const glsl_type *return_type,
    sampler_dimensionality(0), sampler_shadow(0), sampler_array(0),
    interface_packing(0), interface_row_major(0), packed(0),
    vector_elements(0), matrix_columns(0),
-   length(num_params), explicit_stride(0)
+   length(num_params), explicit_stride(0), explicit_alignment(0)
 {
    unsigned int i;
 
@@ -190,7 +197,7 @@ glsl_type::glsl_type(const char *subroutine_name) :
    sampler_dimensionality(0), sampler_shadow(0), sampler_array(0),
    interface_packing(0), interface_row_major(0), packed(0),
    vector_elements(1), matrix_columns(1),
-   length(0), explicit_stride(0)
+   length(0), explicit_stride(0), explicit_alignment(0)
 {
    this->mem_ctx = ralloc_context(NULL);
    assert(this->mem_ctx != NULL);
@@ -567,7 +574,8 @@ glsl_type::glsl_type(const glsl_type *array, unsigned length,
    sampler_dimensionality(0), sampler_shadow(0), sampler_array(0),
    interface_packing(0), interface_row_major(0), packed(0),
    vector_elements(0), matrix_columns(0),
-   length(length), name(NULL), explicit_stride(explicit_stride)
+   length(length), name(NULL), explicit_stride(explicit_stride),
+   explicit_alignment(array->explicit_alignment)
 {
    this->fields.array = array;
    /* Inherit the gl type of the base. The GL type is used for
@@ -650,24 +658,30 @@ VECN(components, uint8_t, u8vec)
 
 const glsl_type *
 glsl_type::get_instance(unsigned base_type, unsigned rows, unsigned columns,
-                        unsigned explicit_stride, bool row_major)
+                        unsigned explicit_stride, bool row_major,
+                        unsigned explicit_alignment)
 {
    if (base_type == GLSL_TYPE_VOID) {
-      assert(explicit_stride == 0 && !row_major);
+      assert(explicit_stride == 0 && explicit_alignment == 0 && !row_major);
       return void_type;
    }
 
-   /* Matrix and vector types with explicit strides have to be looked up in a
-    * table so they're handled separately.
+   /* Matrix and vector types with explicit strides or alignment have to be
+    * looked up in a table so they're handled separately.
     */
-   if (explicit_stride > 0) {
+   if (explicit_stride > 0 || explicit_alignment > 0) {
+      if (explicit_alignment > 0) {
+         assert(util_is_power_of_two_nonzero(explicit_alignment));
+         assert(explicit_stride % explicit_alignment == 0);
+      }
+
       const glsl_type *bare_type = get_instance(base_type, rows, columns);
 
-      assert(columns > 1 || !row_major);
+      assert(columns > 1 || (rows > 1 && !row_major));
 
       char name[128];
-      snprintf(name, sizeof(name), "%sx%uB%s", bare_type->name,
-               explicit_stride, row_major ? "RM" : "");
+      snprintf(name, sizeof(name), "%sx%ua%uB%s", bare_type->name,
+               explicit_stride, explicit_alignment, row_major ? "RM" : "");
 
       mtx_lock(&glsl_type::hash_mutex);
       assert(glsl_type_users > 0);
@@ -684,7 +698,8 @@ glsl_type::get_instance(unsigned base_type, unsigned rows, unsigned columns,
          const glsl_type *t = new glsl_type(bare_type->gl_type,
                                             (glsl_base_type)base_type,
                                             rows, columns, name,
-                                            explicit_stride, row_major);
+                                            explicit_stride, row_major,
+                                            explicit_alignment);
 
          entry = _mesa_hash_table_insert(explicit_matrix_types,
                                          t->name, (void *)t);
@@ -694,6 +709,7 @@ glsl_type::get_instance(unsigned base_type, unsigned rows, unsigned columns,
       assert(((glsl_type *) entry->data)->vector_elements == rows);
       assert(((glsl_type *) entry->data)->matrix_columns == columns);
       assert(((glsl_type *) entry->data)->explicit_stride == explicit_stride);
+      assert(((glsl_type *) entry->data)->explicit_alignment == explicit_alignment);
 
       const glsl_type *t = (const glsl_type *) entry->data;
 
@@ -1124,6 +1140,9 @@ glsl_type::record_compare(const glsl_type *b, bool match_name,
    if (this->interface_row_major != b->interface_row_major)
       return false;
 
+   if (this->explicit_alignment != b->explicit_alignment)
+      return false;
+
    /* From the GLSL 4.20 specification (Sec 4.2):
     *
     *     "Structures must have the same name, sequence of type names, and
@@ -1251,9 +1270,9 @@ const glsl_type *
 glsl_type::get_struct_instance(const glsl_struct_field *fields,
                                unsigned num_fields,
                                const char *name,
-                               bool packed)
+                               bool packed, unsigned explicit_alignment)
 {
-   const glsl_type key(fields, num_fields, name, packed);
+   const glsl_type key(fields, num_fields, name, packed, explicit_alignment);
 
    mtx_lock(&glsl_type::hash_mutex);
    assert(glsl_type_users > 0);
@@ -1266,7 +1285,8 @@ glsl_type::get_struct_instance(const glsl_struct_field *fields,
    const struct hash_entry *entry = _mesa_hash_table_search(struct_types,
                                                             &key);
    if (entry == NULL) {
-      const glsl_type *t = new glsl_type(fields, num_fields, name, packed);
+      const glsl_type *t = new glsl_type(fields, num_fields, name, packed,
+                                         explicit_alignment);
 
       entry = _mesa_hash_table_insert(struct_types, t, (void *) t);
    }
@@ -1275,6 +1295,7 @@ glsl_type::get_struct_instance(const glsl_struct_field *fields,
    assert(((glsl_type *) entry->data)->length == num_fields);
    assert(strcmp(((glsl_type *) entry->data)->name, name) == 0);
    assert(((glsl_type *) entry->data)->packed == packed);
+   assert(((glsl_type *) entry->data)->explicit_alignment == explicit_alignment);
 
    glsl_type *t = (glsl_type *) entry->data;
 
@@ -2448,9 +2469,16 @@ const glsl_type *
 glsl_type::get_explicit_type_for_size_align(glsl_type_size_align_func type_info,
                                             unsigned *size, unsigned *alignment) const
 {
-   if (this->is_scalar() || this->is_vector()) {
+   if (this->is_scalar()) {
       type_info(this, size, alignment);
+      assert(*size == explicit_type_scalar_byte_size(this));
+      assert(*alignment == explicit_type_scalar_byte_size(this));
       return this;
+   } else if (this->is_vector()) {
+      type_info(this, size, alignment);
+      assert(*alignment % explicit_type_scalar_byte_size(this) == 0);
+      return glsl_type::get_instance(this->base_type, this->vector_elements,
+                                     1, 0, false, *alignment);
    } else if (this->is_array()) {
       unsigned elem_size, elem_align;
       const struct glsl_type *explicit_element =
@@ -2484,7 +2512,7 @@ glsl_type::get_explicit_type_for_size_align(glsl_type_size_align_func type_info,
       const glsl_type *type;
       if (this->is_struct()) {
          type = get_struct_instance(fields, this->length, this->name,
-                                    this->packed);
+                                    this->packed, *alignment);
       } else {
          assert(!this->packed);
          type = get_interface_instance(fields, this->length,
@@ -2500,9 +2528,10 @@ glsl_type::get_explicit_type_for_size_align(glsl_type_size_align_func type_info,
       unsigned stride = align(col_size, col_align);
 
       *size = this->matrix_columns * stride;
+      /* Matrix and column alignments match. See glsl_type::column_type() */
       *alignment = col_align;
       return glsl_type::get_instance(this->base_type, this->vector_elements,
-                                     this->matrix_columns, stride, false);
+                                     this->matrix_columns, stride, false, *alignment);
    } else {
       unreachable("Unhandled type.");
    }
@@ -2684,7 +2713,8 @@ union packed_type {
       unsigned interface_row_major:1;
       unsigned vector_elements:3;
       unsigned matrix_columns:3;
-      unsigned explicit_stride:20;
+      unsigned explicit_stride:16;
+      unsigned explicit_alignment:4;
    } basic;
    struct {
       unsigned base_type:5;
@@ -2703,7 +2733,8 @@ union packed_type {
       unsigned base_type:5;
       unsigned interface_packing_or_packed:2;
       unsigned interface_row_major:1;
-      unsigned length:24;
+      unsigned length:20;
+      unsigned explicit_alignment:4;
    } strct;
 };
 
@@ -2768,13 +2799,17 @@ encode_type_to_blob(struct blob *blob, const glsl_type *type)
       else if (type->vector_elements == 16)
          encoded.basic.vector_elements = 6;
       encoded.basic.matrix_columns = type->matrix_columns;
-      encoded.basic.explicit_stride = MIN2(type->explicit_stride, 0xfffff);
+      encoded.basic.explicit_stride = MIN2(type->explicit_stride, 0xffff);
+      encoded.basic.explicit_alignment =
+         MIN2(ffs(type->explicit_alignment), 0xf);
       blob_write_uint32(blob, encoded.u32);
       /* If we don't have enough bits for explicit_stride, store it
        * separately.
        */
-      if (encoded.basic.explicit_stride == 0xfffff)
+      if (encoded.basic.explicit_stride == 0xffff)
          blob_write_uint32(blob, type->explicit_stride);
+      if (encoded.basic.explicit_alignment == 0xf)
+         blob_write_uint32(blob, type->explicit_alignment);
       return;
    case GLSL_TYPE_SAMPLER:
       encoded.sampler.dimensionality = type->sampler_dimensionality;
@@ -2808,7 +2843,9 @@ encode_type_to_blob(struct blob *blob, const glsl_type *type)
       return;
    case GLSL_TYPE_STRUCT:
    case GLSL_TYPE_INTERFACE:
-      encoded.strct.length = MIN2(type->length, 0xffffff);
+      encoded.strct.length = MIN2(type->length, 0xfffff);
+      encoded.strct.explicit_alignment =
+         MIN2(ffs(type->explicit_alignment), 0xf);
       if (type->is_interface()) {
          encoded.strct.interface_packing_or_packed = type->interface_packing;
          encoded.strct.interface_row_major = type->interface_row_major;
@@ -2819,8 +2856,10 @@ encode_type_to_blob(struct blob *blob, const glsl_type *type)
       blob_write_string(blob, type->name);
 
       /* If we don't have enough bits for length, store it separately. */
-      if (encoded.strct.length == 0xffffff)
+      if (encoded.strct.length == 0xfffff)
          blob_write_uint32(blob, type->length);
+      if (encoded.strct.length == 0xf)
+         blob_write_uint32(blob, type->explicit_alignment);
 
       for (unsigned i = 0; i < type->length; i++)
          encode_glsl_struct_field(blob, &type->fields.structure[i]);
@@ -2863,8 +2902,13 @@ decode_type_from_blob(struct blob_reader *blob)
    case GLSL_TYPE_INT64:
    case GLSL_TYPE_BOOL: {
       unsigned explicit_stride = encoded.basic.explicit_stride;
-      if (explicit_stride == 0xfffff)
+      if (explicit_stride == 0xffff)
          explicit_stride = blob_read_uint32(blob);
+      unsigned explicit_alignment = encoded.basic.explicit_alignment;
+      if (explicit_alignment == 0xf)
+         explicit_alignment = blob_read_uint32(blob);
+      else if (explicit_alignment > 0)
+         explicit_alignment = 1 << (explicit_alignment - 1);
       uint32_t vector_elements = encoded.basic.vector_elements;
       if (vector_elements == 5)
          vector_elements = 8;
@@ -2873,7 +2917,8 @@ decode_type_from_blob(struct blob_reader *blob)
       return glsl_type::get_instance(base_type, encoded.basic.vector_elements,
                                      encoded.basic.matrix_columns,
                                      explicit_stride,
-                                     encoded.basic.interface_row_major);
+                                     encoded.basic.interface_row_major,
+                                     explicit_alignment);
    }
    case GLSL_TYPE_SAMPLER:
       return glsl_type::get_sampler_instance((enum glsl_sampler_dim)encoded.sampler.dimensionality,
@@ -2902,8 +2947,13 @@ decode_type_from_blob(struct blob_reader *blob)
    case GLSL_TYPE_INTERFACE: {
       char *name = blob_read_string(blob);
       unsigned num_fields = encoded.strct.length;
-      if (num_fields == 0xffffff)
+      if (num_fields == 0xfffff)
          num_fields = blob_read_uint32(blob);
+      unsigned explicit_alignment = encoded.strct.explicit_alignment;
+      if (explicit_alignment == 0xf)
+         explicit_alignment = blob_read_uint32(blob);
+      else if (explicit_alignment > 0)
+         explicit_alignment = 1 << (explicit_alignment - 1);
 
       glsl_struct_field *fields =
          (glsl_struct_field *) malloc(sizeof(glsl_struct_field) * num_fields);
@@ -2912,6 +2962,7 @@ decode_type_from_blob(struct blob_reader *blob)
 
       const glsl_type *t;
       if (base_type == GLSL_TYPE_INTERFACE) {
+         assert(explicit_alignment == 0);
          enum glsl_interface_packing packing =
             (glsl_interface_packing) encoded.strct.interface_packing_or_packed;
          bool row_major = encoded.strct.interface_row_major;
@@ -2919,7 +2970,8 @@ decode_type_from_blob(struct blob_reader *blob)
                                                row_major, name);
       } else {
          unsigned packed = encoded.strct.interface_packing_or_packed;
-         t = glsl_type::get_struct_instance(fields, num_fields, name, packed);
+         t = glsl_type::get_struct_instance(fields, num_fields, name, packed,
+                                            explicit_alignment);
       }
 
       free(fields);
index 6a57c7026a6d87e8d0172489df350875977a12da..8058425e0d087a195339510caacd6f03a9c2d757 100644 (file)
@@ -332,6 +332,13 @@ public:
     */
    unsigned explicit_stride;
 
+   /**
+    * Explicit alignment. This is used to communicate explicit alignment
+    * constraints. Should be 0 if the type has no explicit alignment
+    * constraint.
+    */
+   unsigned explicit_alignment;
+
    /**
     * Subtype of composite data types.
     */
@@ -420,7 +427,8 @@ public:
    static const glsl_type *get_instance(unsigned base_type, unsigned rows,
                                         unsigned columns,
                                         unsigned explicit_stride = 0,
-                                        bool row_major = false);
+                                        bool row_major = false,
+                                        unsigned explicit_alignment = 0);
 
    /**
     * Get the instance of a sampler type
@@ -446,7 +454,8 @@ public:
    static const glsl_type *get_struct_instance(const glsl_struct_field *fields,
                                               unsigned num_fields,
                                               const char *name,
-                                              bool packed = false);
+                                              bool packed = false,
+                                              unsigned explicit_alignment = 0);
 
    /**
     * Get the instance of an interface block type
@@ -1107,10 +1116,21 @@ public:
       if (!is_matrix())
          return error_type;
 
-      if (explicit_stride && interface_row_major)
-         return get_instance(base_type, vector_elements, 1, explicit_stride);
-      else
-         return get_instance(base_type, vector_elements, 1);
+      if (interface_row_major) {
+         /* If we're row-major, the vector element stride is the same as the
+          * matrix stride and we have no alignment (i.e. component-aligned).
+          */
+         return get_instance(base_type, vector_elements, 1,
+                             explicit_stride, false, 0);
+      } else {
+         /* Otherwise, the vector is tightly packed (stride=0).  For
+          * alignment, we treat a matrix as an array of columns make the same
+          * assumption that the alignment of the column is the same as the
+          * alignment of the whole matrix.
+          */
+         return get_instance(base_type, vector_elements, 1,
+                             0, false, explicit_alignment);
+      }
    }
 
    /**
@@ -1236,7 +1256,8 @@ private:
    glsl_type(GLenum gl_type,
              glsl_base_type base_type, unsigned vector_elements,
              unsigned matrix_columns, const char *name,
-             unsigned explicit_stride = 0, bool row_major = false);
+             unsigned explicit_stride = 0, bool row_major = false,
+             unsigned explicit_alignment = 0);
 
    /** Constructor for sampler or image types */
    glsl_type(GLenum gl_type, glsl_base_type base_type,
@@ -1245,7 +1266,8 @@ private:
 
    /** Constructor for record types */
    glsl_type(const glsl_struct_field *fields, unsigned num_fields,
-            const char *name, bool packed = false);
+            const char *name, bool packed = false,
+            unsigned explicit_alignment = 0);
 
    /** Constructor for interface types */
    glsl_type(const glsl_struct_field *fields, unsigned num_fields,
index 9b4f9c5b0aacb6d1eba0dde92359ca28e99d2fee..1fff15c7cd58d480d5792c30542267804e51515a 100644 (file)
@@ -860,6 +860,12 @@ glsl_get_explicit_size(const struct glsl_type *type, bool align_to_stride)
    return type->explicit_size(align_to_stride);
 }
 
+unsigned
+glsl_get_explicit_alignment(const struct glsl_type *type)
+{
+   return type->explicit_alignment;
+}
+
 bool
 glsl_type_is_packed(const struct glsl_type *type)
 {
index 2df1e2c8b9b55d31ff112743dc6544e6ea00e955..14fae6a5f58099ccc83eb22b1caf4fe4f1f38559 100644 (file)
@@ -122,6 +122,7 @@ void glsl_get_cl_type_size_align(const struct glsl_type *type,
                                  unsigned *size, unsigned *align);
 
 unsigned glsl_get_explicit_size(const struct glsl_type *type, bool align_to_stride);
+unsigned glsl_get_explicit_alignment(const struct glsl_type *type);
 
 static inline unsigned
 glsl_get_bit_size(const struct glsl_type *type)