summaryrefslogtreecommitdiff
path: root/src/compiler/glsl_types.cpp
diff options
context:
space:
mode:
authorJason Ekstrand <jason.ekstrand@intel.com>2018-12-12 14:32:19 -0600
committerJason Ekstrand <jason@jlekstrand.net>2019-01-08 00:38:29 +0000
commit6cebeb4f71918aded1ddade5727f79fae83780fd (patch)
tree9de5dba8aa2944b15f516d541abe8ad7f62c54c1 /src/compiler/glsl_types.cpp
parent7f70b3e55514f1744e9aab6d2145e855603bd1dc (diff)
glsl_type: Add support for explicitly laid out matrices and arrays
SPIR-V allows for matrix and array types to be decorated with explicit byte stride decorations and matrix types to be decorated row- or column-major. This commit adds support to glsl_type to encode this information. Because this doesn't work nicely with std430 and std140 alignments, we add asserts to ensure that we don't use any of the std430 or std140 layout functions with explicitly laid out types. In SPIR-V, the layout information for matrices is applied to the parent struct member instead of to the matrix type itself. However, this is gets rather clumsy when you're walking derefs trying to compute offsets because, the moment you hit a matrix, you have to crawl back the deref chain and find the struct. Instead, we take the same path here as we've taken in spirv_to_nir and put the decorations on the matrix type itself. This also subtly adds support for strided vector types. These don't come up in SPIR-V directly but you can get one as the result of taking a column from a row-major matrix or a row from a column-major matrix. Reviewed-by: Alejandro PiƱeiro <apinheiro@igalia.com>
Diffstat (limited to 'src/compiler/glsl_types.cpp')
-rw-r--r--src/compiler/glsl_types.cpp170
1 files changed, 149 insertions, 21 deletions
diff --git a/src/compiler/glsl_types.cpp b/src/compiler/glsl_types.cpp
index 67f3967d0c1..00be0e00a9e 100644
--- a/src/compiler/glsl_types.cpp
+++ b/src/compiler/glsl_types.cpp
@@ -30,6 +30,7 @@
mtx_t glsl_type::hash_mutex = _MTX_INITIALIZER_NP;
+hash_table *glsl_type::explicit_matrix_types = NULL;
hash_table *glsl_type::array_types = NULL;
hash_table *glsl_type::record_types = NULL;
hash_table *glsl_type::interface_types = NULL;
@@ -38,13 +39,14 @@ hash_table *glsl_type::subroutine_types = NULL;
glsl_type::glsl_type(GLenum gl_type,
glsl_base_type base_type, unsigned vector_elements,
- unsigned matrix_columns, const char *name) :
+ unsigned matrix_columns, const char *name,
+ unsigned explicit_stride, bool row_major) :
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(0),
+ interface_packing(0), interface_row_major(row_major),
vector_elements(vector_elements), matrix_columns(matrix_columns),
- length(0)
+ length(0), explicit_stride(explicit_stride)
{
/* Values of these types must fit in the two bits of
* glsl_type::sampled_type.
@@ -77,7 +79,8 @@ glsl_type::glsl_type(GLenum gl_type, glsl_base_type base_type,
base_type(base_type), sampled_type(type),
sampler_dimensionality(dim), sampler_shadow(shadow),
sampler_array(array), interface_packing(0),
- interface_row_major(0), length(0)
+ interface_row_major(0),
+ length(0), explicit_stride(0)
{
this->mem_ctx = ralloc_context(NULL);
assert(this->mem_ctx != NULL);
@@ -97,7 +100,7 @@ glsl_type::glsl_type(const glsl_struct_field *fields, unsigned num_fields,
sampler_dimensionality(0), sampler_shadow(0), sampler_array(0),
interface_packing(0), interface_row_major(0),
vector_elements(0), matrix_columns(0),
- length(num_fields)
+ length(num_fields), explicit_stride(0)
{
unsigned int i;
@@ -127,7 +130,7 @@ glsl_type::glsl_type(const glsl_struct_field *fields, unsigned num_fields,
interface_packing((unsigned) packing),
interface_row_major((unsigned) row_major),
vector_elements(0), matrix_columns(0),
- length(num_fields)
+ length(num_fields), explicit_stride(0)
{
unsigned int i;
@@ -152,7 +155,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),
vector_elements(0), matrix_columns(0),
- length(num_params)
+ length(num_params), explicit_stride(0)
{
unsigned int i;
@@ -181,7 +184,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),
vector_elements(1), matrix_columns(1),
- length(0)
+ length(0), explicit_stride(0)
{
this->mem_ctx = ralloc_context(NULL);
assert(this->mem_ctx != NULL);
@@ -389,6 +392,55 @@ const glsl_type *glsl_type::get_scalar_type() const
}
+const glsl_type *glsl_type::get_bare_type() const
+{
+ switch (this->base_type) {
+ case GLSL_TYPE_UINT8:
+ case GLSL_TYPE_INT8:
+ case GLSL_TYPE_UINT16:
+ case GLSL_TYPE_INT16:
+ case GLSL_TYPE_FLOAT16:
+ case GLSL_TYPE_UINT:
+ case GLSL_TYPE_INT:
+ case GLSL_TYPE_FLOAT:
+ case GLSL_TYPE_BOOL:
+ case GLSL_TYPE_DOUBLE:
+ case GLSL_TYPE_UINT64:
+ case GLSL_TYPE_INT64:
+ return get_instance(this->base_type, this->vector_elements,
+ this->matrix_columns);
+
+ case GLSL_TYPE_STRUCT:
+ case GLSL_TYPE_INTERFACE: {
+ glsl_struct_field *bare_fields = new glsl_struct_field[this->length];
+ for (unsigned i = 0; i < this->length; i++) {
+ bare_fields[i].type = this->fields.structure[i].type->get_bare_type();
+ bare_fields[i].name = this->fields.structure[i].name;
+ }
+ const glsl_type *bare_type =
+ get_record_instance(bare_fields, this->length, this->name);
+ delete[] bare_fields;
+ return bare_type;
+ }
+
+ case GLSL_TYPE_ARRAY:
+ return get_array_instance(this->fields.array->get_bare_type(),
+ this->length);
+
+ case GLSL_TYPE_SAMPLER:
+ case GLSL_TYPE_IMAGE:
+ case GLSL_TYPE_ATOMIC_UINT:
+ case GLSL_TYPE_VOID:
+ case GLSL_TYPE_SUBROUTINE:
+ case GLSL_TYPE_FUNCTION:
+ case GLSL_TYPE_ERROR:
+ return this;
+ }
+
+ unreachable("Invalid base type");
+}
+
+
static void
hash_free_type_function(struct hash_entry *entry)
{
@@ -407,6 +459,12 @@ _mesa_glsl_release_types(void)
* object, or if process terminates), so no mutex-locking should be
* necessary.
*/
+ if (glsl_type::explicit_matrix_types != NULL) {
+ _mesa_hash_table_destroy(glsl_type::explicit_matrix_types,
+ hash_free_type_function);
+ glsl_type::explicit_matrix_types = NULL;
+ }
+
if (glsl_type::array_types != NULL) {
_mesa_hash_table_destroy(glsl_type::array_types, hash_free_type_function);
glsl_type::array_types = NULL;
@@ -434,12 +492,13 @@ _mesa_glsl_release_types(void)
}
-glsl_type::glsl_type(const glsl_type *array, unsigned length) :
+glsl_type::glsl_type(const glsl_type *array, unsigned length,
+ unsigned explicit_stride) :
base_type(GLSL_TYPE_ARRAY), sampled_type(GLSL_TYPE_VOID),
sampler_dimensionality(0), sampler_shadow(0), sampler_array(0),
interface_packing(0), interface_row_major(0),
vector_elements(0), matrix_columns(0),
- length(length), name(NULL)
+ length(length), name(NULL), explicit_stride(explicit_stride)
{
this->fields.array = array;
/* Inherit the gl type of the base. The GL type is used for
@@ -521,10 +580,57 @@ VECN(components, int8_t, i8vec)
VECN(components, uint8_t, u8vec)
const glsl_type *
-glsl_type::get_instance(unsigned base_type, unsigned rows, unsigned columns)
+glsl_type::get_instance(unsigned base_type, unsigned rows, unsigned columns,
+ unsigned explicit_stride, bool row_major)
{
- if (base_type == GLSL_TYPE_VOID)
+ if (base_type == GLSL_TYPE_VOID) {
+ assert(explicit_stride == 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.
+ */
+ if (explicit_stride > 0) {
+ const glsl_type *bare_type = get_instance(base_type, rows, columns);
+
+ assert(columns > 1 || !row_major);
+
+ char name[128];
+ util_snprintf(name, sizeof(name), "%sx%uB%s", bare_type->name,
+ explicit_stride, row_major ? "RM" : "");
+
+ mtx_lock(&glsl_type::hash_mutex);
+
+ if (explicit_matrix_types == NULL) {
+ explicit_matrix_types =
+ _mesa_hash_table_create(NULL, _mesa_key_hash_string,
+ _mesa_key_string_equal);
+ }
+
+ const struct hash_entry *entry =
+ _mesa_hash_table_search(explicit_matrix_types, name);
+ if (entry == NULL) {
+ const glsl_type *t = new glsl_type(bare_type->gl_type,
+ (glsl_base_type)base_type,
+ rows, columns, name,
+ explicit_stride, row_major);
+
+ entry = _mesa_hash_table_insert(explicit_matrix_types,
+ t->name, (void *)t);
+ }
+
+ assert(((glsl_type *) entry->data)->base_type == base_type);
+ 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);
+
+ mtx_unlock(&glsl_type::hash_mutex);
+
+ return (const glsl_type *) entry->data;
+ }
+
+ assert(!row_major);
/* Treat GLSL vectors as Nx1 matrices.
*/
@@ -846,7 +952,9 @@ glsl_type::get_image_instance(enum glsl_sampler_dim dim,
}
const glsl_type *
-glsl_type::get_array_instance(const glsl_type *base, unsigned array_size)
+glsl_type::get_array_instance(const glsl_type *base,
+ unsigned array_size,
+ unsigned explicit_stride)
{
/* Generate a name using the base type pointer in the key. This is
* done because the name of the base type may not be unique across
@@ -854,7 +962,8 @@ glsl_type::get_array_instance(const glsl_type *base, unsigned array_size)
* named 'foo'.
*/
char key[128];
- util_snprintf(key, sizeof(key), "%p[%u]", (void *) base, array_size);
+ util_snprintf(key, sizeof(key), "%p[%u]x%uB", (void *) base, array_size,
+ explicit_stride);
mtx_lock(&glsl_type::hash_mutex);
@@ -865,7 +974,7 @@ glsl_type::get_array_instance(const glsl_type *base, unsigned array_size)
const struct hash_entry *entry = _mesa_hash_table_search(array_types, key);
if (entry == NULL) {
- const glsl_type *t = new glsl_type(base, array_size);
+ const glsl_type *t = new glsl_type(base, array_size, explicit_stride);
entry = _mesa_hash_table_insert(array_types,
strdup(key),
@@ -1599,6 +1708,7 @@ glsl_type::std140_size(bool row_major) const
* <N> basic machine units, the base alignment is 4<N>.
*/
if (this->is_scalar() || this->is_vector()) {
+ assert(this->explicit_stride == 0);
return this->vector_elements * N;
}
@@ -1633,6 +1743,8 @@ glsl_type::std140_size(bool row_major) const
array_len = 1;
}
+ assert(element_type->explicit_stride == 0);
+
if (row_major) {
vec_type = get_instance(element_type->base_type,
element_type->matrix_columns, 1);
@@ -1660,6 +1772,7 @@ glsl_type::std140_size(bool row_major) const
* the array are laid out in order, according to rule (9).
*/
if (this->is_array()) {
+ assert(this->explicit_stride == 0);
if (this->without_array()->is_record()) {
return this->arrays_of_arrays_size() *
this->without_array()->std140_size(row_major);
@@ -1834,6 +1947,8 @@ glsl_type::std430_array_stride(bool row_major) const
{
unsigned N = is_64bit() ? 8 : 4;
+ assert(explicit_stride == 0);
+
/* Notice that the array stride of a vec3 is not 3 * N but 4 * N.
* See OpenGL 4.30 spec, section 7.6.2.2 "Standard Uniform Block Layout"
*
@@ -1860,8 +1975,10 @@ glsl_type::std430_size(bool row_major) const
* 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 (this->is_scalar() || this->is_vector())
- return this->vector_elements * N;
+ if (this->is_scalar() || this->is_vector()) {
+ assert(this->explicit_stride == 0);
+ return this->vector_elements * N;
+ }
if (this->without_array()->is_matrix()) {
const struct glsl_type *element_type;
@@ -1876,6 +1993,8 @@ glsl_type::std430_size(bool row_major) const
array_len = 1;
}
+ assert(element_type->explicit_stride == 0);
+
if (row_major) {
vec_type = get_instance(element_type->base_type,
element_type->matrix_columns, 1);
@@ -1893,6 +2012,7 @@ glsl_type::std430_size(bool row_major) const
}
if (this->is_array()) {
+ assert(this->explicit_stride == 0);
if (this->without_array()->is_record())
return this->arrays_of_arrays_size() *
this->without_array()->std430_size(row_major);
@@ -2092,9 +2212,12 @@ encode_type_to_blob(struct blob *blob, const glsl_type *type)
case GLSL_TYPE_INT64:
case GLSL_TYPE_BOOL:
encoding = (type->base_type << 24) |
+ (type->interface_row_major << 10) |
(type->vector_elements << 4) |
(type->matrix_columns);
- break;
+ blob_write_uint32(blob, encoding);
+ blob_write_uint32(blob, type->explicit_stride);
+ return;
case GLSL_TYPE_SAMPLER:
encoding = (type->base_type) << 24 |
(type->sampler_dimensionality << 4) |
@@ -2119,6 +2242,7 @@ encode_type_to_blob(struct blob *blob, const glsl_type *type)
case GLSL_TYPE_ARRAY:
blob_write_uint32(blob, (type->base_type) << 24);
blob_write_uint32(blob, type->length);
+ blob_write_uint32(blob, type->explicit_stride);
encode_type_to_blob(blob, type->fields.array);
return;
case GLSL_TYPE_STRUCT:
@@ -2181,8 +2305,11 @@ decode_type_from_blob(struct blob_reader *blob)
case GLSL_TYPE_INT16:
case GLSL_TYPE_UINT64:
case GLSL_TYPE_INT64:
- case GLSL_TYPE_BOOL:
- return glsl_type::get_instance(base_type, (u >> 4) & 0x0f, u & 0x0f);
+ case GLSL_TYPE_BOOL: {
+ unsigned explicit_stride = blob_read_uint32(blob);
+ return glsl_type::get_instance(base_type, (u >> 4) & 0x0f, u & 0x0f,
+ explicit_stride, (u >> 10) & 0x1);
+ }
case GLSL_TYPE_SAMPLER:
return glsl_type::get_sampler_instance((enum glsl_sampler_dim) ((u >> 4) & 0x07),
(u >> 3) & 0x01,
@@ -2198,8 +2325,9 @@ decode_type_from_blob(struct blob_reader *blob)
return glsl_type::atomic_uint_type;
case GLSL_TYPE_ARRAY: {
unsigned length = blob_read_uint32(blob);
+ unsigned explicit_stride = blob_read_uint32(blob);
return glsl_type::get_array_instance(decode_type_from_blob(blob),
- length);
+ length, explicit_stride);
}
case GLSL_TYPE_STRUCT:
case GLSL_TYPE_INTERFACE: {