nir/glsl: Add an explicit_alignment field to glsl_type
[mesa.git] / src / compiler / glsl_types.cpp
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);