From a0b82c24b6d08cc3f07b4ddad16c7e1b986ad983 Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Sat, 29 Aug 2020 18:01:46 -0500 Subject: [PATCH] nir/glsl: Add an explicit_alignment field to glsl_type 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 Part-of: --- src/compiler/glsl_types.cpp | 120 ++++++++++++++++++++++++++---------- src/compiler/glsl_types.h | 38 +++++++++--- src/compiler/nir_types.cpp | 6 ++ src/compiler/nir_types.h | 1 + 4 files changed, 123 insertions(+), 42 deletions(-) diff --git a/src/compiler/glsl_types.cpp b/src/compiler/glsl_types.cpp index 1aeb4439544..288ddcf5dea 100644 --- a/src/compiler/glsl_types.cpp +++ b/src/compiler/glsl_types.cpp @@ -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); diff --git a/src/compiler/glsl_types.h b/src/compiler/glsl_types.h index 6a57c7026a6..8058425e0d0 100644 --- a/src/compiler/glsl_types.h +++ b/src/compiler/glsl_types.h @@ -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, diff --git a/src/compiler/nir_types.cpp b/src/compiler/nir_types.cpp index 9b4f9c5b0aa..1fff15c7cd5 100644 --- a/src/compiler/nir_types.cpp +++ b/src/compiler/nir_types.cpp @@ -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) { diff --git a/src/compiler/nir_types.h b/src/compiler/nir_types.h index 2df1e2c8b9b..14fae6a5f58 100644 --- a/src/compiler/nir_types.h +++ b/src/compiler/nir_types.h @@ -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) -- 2.30.2