| /* |
| * Copyright © 2009 Intel Corporation |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining a |
| * copy of this software and associated documentation files (the "Software"), |
| * to deal in the Software without restriction, including without limitation |
| * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
| * and/or sell copies of the Software, and to permit persons to whom the |
| * Software is furnished to do so, subject to the following conditions: |
| * |
| * The above copyright notice and this permission notice (including the next |
| * paragraph) shall be included in all copies or substantial portions of the |
| * Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
| * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
| * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
| * DEALINGS IN THE SOFTWARE. |
| */ |
| |
| #include <stdio.h> |
| #include "main/macros.h" |
| #include "compiler/glsl/glsl_parser_extras.h" |
| #include "glsl_types.h" |
| #include "util/hash_table.h" |
| #include "util/u_cpu_detect.h" |
| #include "util/u_string.h" |
| |
| |
| 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::struct_types = NULL; |
| hash_table *glsl_type::interface_types = NULL; |
| hash_table *glsl_type::function_types = NULL; |
| hash_table *glsl_type::subroutine_types = NULL; |
| |
| /* There might be multiple users for types (e.g. application using OpenGL |
| * and Vulkan simultaneously or app using multiple Vulkan instances). Counter |
| * is used to make sure we don't release the types if a user is still present. |
| */ |
| 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_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), |
| explicit_alignment(explicit_alignment) |
| { |
| /* Values of these types must fit in the two bits of |
| * glsl_type::sampled_type. |
| */ |
| STATIC_ASSERT((unsigned(GLSL_TYPE_UINT) & 3) == unsigned(GLSL_TYPE_UINT)); |
| STATIC_ASSERT((unsigned(GLSL_TYPE_INT) & 3) == unsigned(GLSL_TYPE_INT)); |
| STATIC_ASSERT((unsigned(GLSL_TYPE_FLOAT) & 3) == unsigned(GLSL_TYPE_FLOAT)); |
| |
| ASSERT_BITFIELD_SIZE(glsl_type, base_type, GLSL_TYPE_ERROR); |
| ASSERT_BITFIELD_SIZE(glsl_type, sampled_type, GLSL_TYPE_ERROR); |
| ASSERT_BITFIELD_SIZE(glsl_type, sampler_dimensionality, |
| GLSL_SAMPLER_DIM_SUBPASS_MS); |
| |
| this->mem_ctx = ralloc_context(NULL); |
| assert(this->mem_ctx != NULL); |
| |
| assert(name != NULL); |
| this->name = ralloc_strdup(this->mem_ctx, name); |
| |
| /* 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)); |
| } |
| |
| glsl_type::glsl_type(GLenum gl_type, glsl_base_type base_type, |
| enum glsl_sampler_dim dim, bool shadow, bool array, |
| glsl_base_type type, const char *name) : |
| gl_type(gl_type), |
| base_type(base_type), sampled_type(type), |
| sampler_dimensionality(dim), sampler_shadow(shadow), |
| sampler_array(array), interface_packing(0), |
| interface_row_major(0), packed(0), |
| length(0), explicit_stride(0), explicit_alignment(0) |
| { |
| this->mem_ctx = ralloc_context(NULL); |
| assert(this->mem_ctx != NULL); |
| |
| assert(name != NULL); |
| this->name = ralloc_strdup(this->mem_ctx, name); |
| |
| memset(& fields, 0, sizeof(fields)); |
| |
| matrix_columns = vector_elements = 1; |
| } |
| |
| glsl_type::glsl_type(const glsl_struct_field *fields, unsigned num_fields, |
| 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), |
| 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); |
| |
| assert(name != NULL); |
| this->name = ralloc_strdup(this->mem_ctx, name); |
| /* Zero-fill to prevent spurious Valgrind errors when serializing NIR |
| * due to uninitialized unused bits in bit fields. */ |
| this->fields.structure = rzalloc_array(this->mem_ctx, |
| glsl_struct_field, length); |
| |
| for (i = 0; i < length; i++) { |
| this->fields.structure[i] = fields[i]; |
| this->fields.structure[i].name = ralloc_strdup(this->fields.structure, |
| fields[i].name); |
| } |
| } |
| |
| glsl_type::glsl_type(const glsl_struct_field *fields, unsigned num_fields, |
| enum glsl_interface_packing packing, |
| bool row_major, const char *name) : |
| gl_type(0), |
| base_type(GLSL_TYPE_INTERFACE), sampled_type(GLSL_TYPE_VOID), |
| sampler_dimensionality(0), sampler_shadow(0), sampler_array(0), |
| interface_packing((unsigned) packing), |
| interface_row_major((unsigned) row_major), packed(0), |
| vector_elements(0), matrix_columns(0), |
| length(num_fields), explicit_stride(0), explicit_alignment(0) |
| { |
| unsigned int i; |
| |
| this->mem_ctx = ralloc_context(NULL); |
| assert(this->mem_ctx != NULL); |
| |
| assert(name != NULL); |
| this->name = ralloc_strdup(this->mem_ctx, name); |
| this->fields.structure = rzalloc_array(this->mem_ctx, |
| glsl_struct_field, length); |
| for (i = 0; i < length; i++) { |
| this->fields.structure[i] = fields[i]; |
| this->fields.structure[i].name = ralloc_strdup(this->fields.structure, |
| fields[i].name); |
| } |
| } |
| |
| glsl_type::glsl_type(const glsl_type *return_type, |
| const glsl_function_param *params, unsigned num_params) : |
| gl_type(0), |
| base_type(GLSL_TYPE_FUNCTION), sampled_type(GLSL_TYPE_VOID), |
| 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), explicit_alignment(0) |
| { |
| unsigned int i; |
| |
| this->mem_ctx = ralloc_context(NULL); |
| assert(this->mem_ctx != NULL); |
| |
| this->name = ralloc_strdup(this->mem_ctx, ""); |
| |
| this->fields.parameters = rzalloc_array(this->mem_ctx, |
| glsl_function_param, num_params + 1); |
| |
| /* We store the return type as the first parameter */ |
| this->fields.parameters[0].type = return_type; |
| this->fields.parameters[0].in = false; |
| this->fields.parameters[0].out = true; |
| |
| /* We store the i'th parameter in slot i+1 */ |
| for (i = 0; i < length; i++) { |
| this->fields.parameters[i + 1].type = params[i].type; |
| this->fields.parameters[i + 1].in = params[i].in; |
| this->fields.parameters[i + 1].out = params[i].out; |
| } |
| } |
| |
| glsl_type::glsl_type(const char *subroutine_name) : |
| gl_type(0), |
| base_type(GLSL_TYPE_SUBROUTINE), sampled_type(GLSL_TYPE_VOID), |
| 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), explicit_alignment(0) |
| { |
| this->mem_ctx = ralloc_context(NULL); |
| assert(this->mem_ctx != NULL); |
| |
| assert(subroutine_name != NULL); |
| this->name = ralloc_strdup(this->mem_ctx, subroutine_name); |
| } |
| |
| glsl_type::~glsl_type() |
| { |
| ralloc_free(this->mem_ctx); |
| } |
| |
| bool |
| glsl_type::contains_sampler() const |
| { |
| if (this->is_array()) { |
| return this->fields.array->contains_sampler(); |
| } else if (this->is_struct() || this->is_interface()) { |
| for (unsigned int i = 0; i < this->length; i++) { |
| if (this->fields.structure[i].type->contains_sampler()) |
| return true; |
| } |
| return false; |
| } else { |
| return this->is_sampler(); |
| } |
| } |
| |
| bool |
| glsl_type::contains_array() const |
| { |
| if (this->is_struct() || this->is_interface()) { |
| for (unsigned int i = 0; i < this->length; i++) { |
| if (this->fields.structure[i].type->contains_array()) |
| return true; |
| } |
| return false; |
| } else { |
| return this->is_array(); |
| } |
| } |
| |
| bool |
| glsl_type::contains_integer() const |
| { |
| if (this->is_array()) { |
| return this->fields.array->contains_integer(); |
| } else if (this->is_struct() || this->is_interface()) { |
| for (unsigned int i = 0; i < this->length; i++) { |
| if (this->fields.structure[i].type->contains_integer()) |
| return true; |
| } |
| return false; |
| } else { |
| return this->is_integer(); |
| } |
| } |
| |
| bool |
| glsl_type::contains_double() const |
| { |
| if (this->is_array()) { |
| return this->fields.array->contains_double(); |
| } else if (this->is_struct() || this->is_interface()) { |
| for (unsigned int i = 0; i < this->length; i++) { |
| if (this->fields.structure[i].type->contains_double()) |
| return true; |
| } |
| return false; |
| } else { |
| return this->is_double(); |
| } |
| } |
| |
| bool |
| glsl_type::contains_64bit() const |
| { |
| if (this->is_array()) { |
| return this->fields.array->contains_64bit(); |
| } else if (this->is_struct() || this->is_interface()) { |
| for (unsigned int i = 0; i < this->length; i++) { |
| if (this->fields.structure[i].type->contains_64bit()) |
| return true; |
| } |
| return false; |
| } else { |
| return this->is_64bit(); |
| } |
| } |
| |
| bool |
| glsl_type::contains_opaque() const { |
| switch (base_type) { |
| case GLSL_TYPE_SAMPLER: |
| case GLSL_TYPE_IMAGE: |
| case GLSL_TYPE_ATOMIC_UINT: |
| return true; |
| case GLSL_TYPE_ARRAY: |
| return fields.array->contains_opaque(); |
| case GLSL_TYPE_STRUCT: |
| case GLSL_TYPE_INTERFACE: |
| for (unsigned int i = 0; i < length; i++) { |
| if (fields.structure[i].type->contains_opaque()) |
| return true; |
| } |
| return false; |
| default: |
| return false; |
| } |
| } |
| |
| bool |
| glsl_type::contains_subroutine() const |
| { |
| if (this->is_array()) { |
| return this->fields.array->contains_subroutine(); |
| } else if (this->is_struct() || this->is_interface()) { |
| for (unsigned int i = 0; i < this->length; i++) { |
| if (this->fields.structure[i].type->contains_subroutine()) |
| return true; |
| } |
| return false; |
| } else { |
| return this->is_subroutine(); |
| } |
| } |
| |
| gl_texture_index |
| glsl_type::sampler_index() const |
| { |
| const glsl_type *const t = (this->is_array()) ? this->fields.array : this; |
| |
| assert(t->is_sampler() || t->is_image()); |
| |
| switch (t->sampler_dimensionality) { |
| case GLSL_SAMPLER_DIM_1D: |
| return (t->sampler_array) ? TEXTURE_1D_ARRAY_INDEX : TEXTURE_1D_INDEX; |
| case GLSL_SAMPLER_DIM_2D: |
| return (t->sampler_array) ? TEXTURE_2D_ARRAY_INDEX : TEXTURE_2D_INDEX; |
| case GLSL_SAMPLER_DIM_3D: |
| return TEXTURE_3D_INDEX; |
| case GLSL_SAMPLER_DIM_CUBE: |
| return (t->sampler_array) ? TEXTURE_CUBE_ARRAY_INDEX : TEXTURE_CUBE_INDEX; |
| case GLSL_SAMPLER_DIM_RECT: |
| return TEXTURE_RECT_INDEX; |
| case GLSL_SAMPLER_DIM_BUF: |
| return TEXTURE_BUFFER_INDEX; |
| case GLSL_SAMPLER_DIM_EXTERNAL: |
| return TEXTURE_EXTERNAL_INDEX; |
| case GLSL_SAMPLER_DIM_MS: |
| return (t->sampler_array) ? TEXTURE_2D_MULTISAMPLE_ARRAY_INDEX : TEXTURE_2D_MULTISAMPLE_INDEX; |
| default: |
| assert(!"Should not get here."); |
| return TEXTURE_BUFFER_INDEX; |
| } |
| } |
| |
| bool |
| glsl_type::contains_image() const |
| { |
| if (this->is_array()) { |
| return this->fields.array->contains_image(); |
| } else if (this->is_struct() || this->is_interface()) { |
| for (unsigned int i = 0; i < this->length; i++) { |
| if (this->fields.structure[i].type->contains_image()) |
| return true; |
| } |
| return false; |
| } else { |
| return this->is_image(); |
| } |
| } |
| |
| const glsl_type *glsl_type::get_base_type() const |
| { |
| switch (base_type) { |
| case GLSL_TYPE_UINT: |
| return uint_type; |
| case GLSL_TYPE_UINT16: |
| return uint16_t_type; |
| case GLSL_TYPE_UINT8: |
| return uint8_t_type; |
| case GLSL_TYPE_INT: |
| return int_type; |
| case GLSL_TYPE_INT16: |
| return int16_t_type; |
| case GLSL_TYPE_INT8: |
| return int8_t_type; |
| case GLSL_TYPE_FLOAT: |
| return float_type; |
| case GLSL_TYPE_FLOAT16: |
| return float16_t_type; |
| case GLSL_TYPE_DOUBLE: |
| return double_type; |
| case GLSL_TYPE_BOOL: |
| return bool_type; |
| case GLSL_TYPE_UINT64: |
| return uint64_t_type; |
| case GLSL_TYPE_INT64: |
| return int64_t_type; |
| default: |
| return error_type; |
| } |
| } |
| |
| |
| const glsl_type *glsl_type::get_scalar_type() const |
| { |
| const glsl_type *type = this; |
| |
| /* Handle arrays */ |
| while (type->base_type == GLSL_TYPE_ARRAY) |
| type = type->fields.array; |
| |
| const glsl_type *scalar_type = type->get_base_type(); |
| if (scalar_type == error_type) |
| return type; |
| |
| return scalar_type; |
| } |
| |
| |
| 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_struct_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"); |
| } |
| |
| const glsl_type *glsl_type::get_float16_type() const |
| { |
| assert(this->base_type == GLSL_TYPE_FLOAT); |
| |
| return get_instance(GLSL_TYPE_FLOAT16, |
| this->vector_elements, |
| this->matrix_columns, |
| this->explicit_stride, |
| this->interface_row_major); |
| } |
| |
| const glsl_type *glsl_type::get_int16_type() const |
| { |
| assert(this->base_type == GLSL_TYPE_INT); |
| |
| return get_instance(GLSL_TYPE_INT16, |
| this->vector_elements, |
| this->matrix_columns, |
| this->explicit_stride, |
| this->interface_row_major); |
| } |
| |
| const glsl_type *glsl_type::get_uint16_type() const |
| { |
| assert(this->base_type == GLSL_TYPE_UINT); |
| |
| return get_instance(GLSL_TYPE_UINT16, |
| this->vector_elements, |
| this->matrix_columns, |
| this->explicit_stride, |
| this->interface_row_major); |
| } |
| |
| static void |
| hash_free_type_function(struct hash_entry *entry) |
| { |
| glsl_type *type = (glsl_type *) entry->data; |
| |
| if (type->is_array()) |
| free((void*)entry->key); |
| |
| delete type; |
| } |
| |
| void |
| glsl_type_singleton_init_or_ref() |
| { |
| /* This is required for _mesa_half_to_float() which is |
| * required for constant-folding 16-bit float ops. |
| */ |
| util_cpu_detect(); |
| |
| mtx_lock(&glsl_type::hash_mutex); |
| glsl_type_users++; |
| mtx_unlock(&glsl_type::hash_mutex); |
| } |
| |
| void |
| glsl_type_singleton_decref() |
| { |
| mtx_lock(&glsl_type::hash_mutex); |
| assert(glsl_type_users > 0); |
| |
| /* Do not release glsl_types if they are still used. */ |
| if (--glsl_type_users) { |
| mtx_unlock(&glsl_type::hash_mutex); |
| return; |
| } |
| |
| 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; |
| } |
| |
| if (glsl_type::struct_types != NULL) { |
| _mesa_hash_table_destroy(glsl_type::struct_types, hash_free_type_function); |
| glsl_type::struct_types = NULL; |
| } |
| |
| if (glsl_type::interface_types != NULL) { |
| _mesa_hash_table_destroy(glsl_type::interface_types, hash_free_type_function); |
| glsl_type::interface_types = NULL; |
| } |
| |
| if (glsl_type::function_types != NULL) { |
| _mesa_hash_table_destroy(glsl_type::function_types, hash_free_type_function); |
| glsl_type::function_types = NULL; |
| } |
| |
| if (glsl_type::subroutine_types != NULL) { |
| _mesa_hash_table_destroy(glsl_type::subroutine_types, hash_free_type_function); |
| glsl_type::subroutine_types = NULL; |
| } |
| |
| mtx_unlock(&glsl_type::hash_mutex); |
| } |
| |
| |
| 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), packed(0), |
| vector_elements(0), matrix_columns(0), |
| 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 |
| * uniform/statevar handling in Mesa and the arrayness of the type |
| * is represented by the size rather than the type. |
| */ |
| this->gl_type = array->gl_type; |
| |
| /* Allow a maximum of 10 characters for the array size. This is enough |
| * for 32-bits of ~0. The extra 3 are for the '[', ']', and terminating |
| * NUL. |
| */ |
| const unsigned name_length = strlen(array->name) + 10 + 3; |
| |
| this->mem_ctx = ralloc_context(NULL); |
| assert(this->mem_ctx != NULL); |
| |
| char *const n = (char *) ralloc_size(this->mem_ctx, name_length); |
| |
| if (length == 0) |
| snprintf(n, name_length, "%s[]", array->name); |
| else { |
| /* insert outermost dimensions in the correct spot |
| * otherwise the dimension order will be backwards |
| */ |
| const char *pos = strchr(array->name, '['); |
| if (pos) { |
| int idx = pos - array->name; |
| snprintf(n, idx+1, "%s", array->name); |
| snprintf(n + idx, name_length - idx, "[%u]%s", |
| length, array->name + idx); |
| } else { |
| snprintf(n, name_length, "%s[%u]", array->name, length); |
| } |
| } |
| |
| this->name = n; |
| } |
| |
| const glsl_type * |
| glsl_type::vec(unsigned components, const glsl_type *const ts[]) |
| { |
| unsigned n = components; |
| |
| if (components == 8) |
| n = 5; |
| else if (components == 16) |
| n = 6; |
| |
| if (n == 0 || n > 6) |
| return error_type; |
| |
| return ts[n - 1]; |
| } |
| |
| #define VECN(components, sname, vname) \ |
| const glsl_type * \ |
| glsl_type:: vname (unsigned components) \ |
| { \ |
| static const glsl_type *const ts[] = { \ |
| sname ## _type, vname ## 2_type, \ |
| vname ## 3_type, vname ## 4_type, \ |
| vname ## 8_type, vname ## 16_type, \ |
| }; \ |
| return glsl_type::vec(components, ts); \ |
| } |
| |
| VECN(components, float, vec) |
| VECN(components, float16_t, f16vec) |
| VECN(components, double, dvec) |
| VECN(components, int, ivec) |
| VECN(components, uint, uvec) |
| VECN(components, bool, bvec) |
| VECN(components, int64_t, i64vec) |
| VECN(components, uint64_t, u64vec) |
| VECN(components, int16_t, i16vec) |
| VECN(components, uint16_t, u16vec) |
| VECN(components, int8_t, i8vec) |
| 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_alignment) |
| { |
| if (base_type == GLSL_TYPE_VOID) { |
| assert(explicit_stride == 0 && explicit_alignment == 0 && !row_major); |
| return void_type; |
| } |
| |
| /* 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 || 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 || (rows > 1 && !row_major)); |
| |
| char name[128]; |
| 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); |
| |
| if (explicit_matrix_types == NULL) { |
| explicit_matrix_types = |
| _mesa_hash_table_create(NULL, _mesa_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, |
| explicit_alignment); |
| |
| 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); |
| assert(((glsl_type *) entry->data)->explicit_alignment == explicit_alignment); |
| |
| const glsl_type *t = (const glsl_type *) entry->data; |
| |
| mtx_unlock(&glsl_type::hash_mutex); |
| |
| return t; |
| } |
| |
| assert(!row_major); |
| |
| /* Treat GLSL vectors as Nx1 matrices. |
| */ |
| if (columns == 1) { |
| switch (base_type) { |
| case GLSL_TYPE_UINT: |
| return uvec(rows); |
| case GLSL_TYPE_INT: |
| return ivec(rows); |
| case GLSL_TYPE_FLOAT: |
| return vec(rows); |
| case GLSL_TYPE_FLOAT16: |
| return f16vec(rows); |
| case GLSL_TYPE_DOUBLE: |
| return dvec(rows); |
| case GLSL_TYPE_BOOL: |
| return bvec(rows); |
| case GLSL_TYPE_UINT64: |
| return u64vec(rows); |
| case GLSL_TYPE_INT64: |
| return i64vec(rows); |
| case GLSL_TYPE_UINT16: |
| return u16vec(rows); |
| case GLSL_TYPE_INT16: |
| return i16vec(rows); |
| case GLSL_TYPE_UINT8: |
| return u8vec(rows); |
| case GLSL_TYPE_INT8: |
| return i8vec(rows); |
| default: |
| return error_type; |
| } |
| } else { |
| if ((base_type != GLSL_TYPE_FLOAT && |
| base_type != GLSL_TYPE_DOUBLE && |
| base_type != GLSL_TYPE_FLOAT16) || (rows == 1)) |
| return error_type; |
| |
| /* GLSL matrix types are named mat{COLUMNS}x{ROWS}. Only the following |
| * combinations are valid: |
| * |
| * 1 2 3 4 |
| * 1 |
| * 2 x x x |
| * 3 x x x |
| * 4 x x x |
| */ |
| #define IDX(c,r) (((c-1)*3) + (r-1)) |
| |
| switch (base_type) { |
| case GLSL_TYPE_DOUBLE: { |
| switch (IDX(columns, rows)) { |
| case IDX(2,2): return dmat2_type; |
| case IDX(2,3): return dmat2x3_type; |
| case IDX(2,4): return dmat2x4_type; |
| case IDX(3,2): return dmat3x2_type; |
| case IDX(3,3): return dmat3_type; |
| case IDX(3,4): return dmat3x4_type; |
| case IDX(4,2): return dmat4x2_type; |
| case IDX(4,3): return dmat4x3_type; |
| case IDX(4,4): return dmat4_type; |
| default: return error_type; |
| } |
| } |
| case GLSL_TYPE_FLOAT: { |
| switch (IDX(columns, rows)) { |
| case IDX(2,2): return mat2_type; |
| case IDX(2,3): return mat2x3_type; |
| case IDX(2,4): return mat2x4_type; |
| case IDX(3,2): return mat3x2_type; |
| case IDX(3,3): return mat3_type; |
| case IDX(3,4): return mat3x4_type; |
| case IDX(4,2): return mat4x2_type; |
| case IDX(4,3): return mat4x3_type; |
| case IDX(4,4): return mat4_type; |
| default: return error_type; |
| } |
| } |
| case GLSL_TYPE_FLOAT16: { |
| switch (IDX(columns, rows)) { |
| case IDX(2,2): return f16mat2_type; |
| case IDX(2,3): return f16mat2x3_type; |
| case IDX(2,4): return f16mat2x4_type; |
| case IDX(3,2): return f16mat3x2_type; |
| case IDX(3,3): return f16mat3_type; |
| case IDX(3,4): return f16mat3x4_type; |
| case IDX(4,2): return f16mat4x2_type; |
| case IDX(4,3): return f16mat4x3_type; |
| case IDX(4,4): return f16mat4_type; |
| default: return error_type; |
| } |
| } |
| default: return error_type; |
| } |
| } |
| |
| assert(!"Should not get here."); |
| return error_type; |
| } |
| |
| const glsl_type * |
| glsl_type::get_sampler_instance(enum glsl_sampler_dim dim, |
| bool shadow, |
| bool array, |
| glsl_base_type type) |
| { |
| switch (type) { |
| case GLSL_TYPE_FLOAT: |
| switch (dim) { |
| case GLSL_SAMPLER_DIM_1D: |
| if (shadow) |
| return (array ? sampler1DArrayShadow_type : sampler1DShadow_type); |
| else |
| return (array ? sampler1DArray_type : sampler1D_type); |
| case GLSL_SAMPLER_DIM_2D: |
| if (shadow) |
| return (array ? sampler2DArrayShadow_type : sampler2DShadow_type); |
| else |
| return (array ? sampler2DArray_type : sampler2D_type); |
| case GLSL_SAMPLER_DIM_3D: |
| if (shadow || array) |
| return error_type; |
| else |
| return sampler3D_type; |
| case GLSL_SAMPLER_DIM_CUBE: |
| if (shadow) |
| return (array ? samplerCubeArrayShadow_type : samplerCubeShadow_type); |
| else |
| return (array ? samplerCubeArray_type : samplerCube_type); |
| case GLSL_SAMPLER_DIM_RECT: |
| if (array) |
| return error_type; |
| if (shadow) |
| return sampler2DRectShadow_type; |
| else |
| return sampler2DRect_type; |
| case GLSL_SAMPLER_DIM_BUF: |
| if (shadow || array) |
| return error_type; |
| else |
| return samplerBuffer_type; |
| case GLSL_SAMPLER_DIM_MS: |
| if (shadow) |
| return error_type; |
| return (array ? sampler2DMSArray_type : sampler2DMS_type); |
| case GLSL_SAMPLER_DIM_EXTERNAL: |
| if (shadow || array) |
| return error_type; |
| else |
| return samplerExternalOES_type; |
| case GLSL_SAMPLER_DIM_SUBPASS: |
| case GLSL_SAMPLER_DIM_SUBPASS_MS: |
| return error_type; |
| } |
| case GLSL_TYPE_INT: |
| if (shadow) |
| return error_type; |
| switch (dim) { |
| case GLSL_SAMPLER_DIM_1D: |
| return (array ? isampler1DArray_type : isampler1D_type); |
| case GLSL_SAMPLER_DIM_2D: |
| return (array ? isampler2DArray_type : isampler2D_type); |
| case GLSL_SAMPLER_DIM_3D: |
| if (array) |
| return error_type; |
| return isampler3D_type; |
| case GLSL_SAMPLER_DIM_CUBE: |
| return (array ? isamplerCubeArray_type : isamplerCube_type); |
| case GLSL_SAMPLER_DIM_RECT: |
| if (array) |
| return error_type; |
| return isampler2DRect_type; |
| case GLSL_SAMPLER_DIM_BUF: |
| if (array) |
| return error_type; |
| return isamplerBuffer_type; |
| case GLSL_SAMPLER_DIM_MS: |
| return (array ? isampler2DMSArray_type : isampler2DMS_type); |
| case GLSL_SAMPLER_DIM_EXTERNAL: |
| return error_type; |
| case GLSL_SAMPLER_DIM_SUBPASS: |
| case GLSL_SAMPLER_DIM_SUBPASS_MS: |
| return error_type; |
| } |
| case GLSL_TYPE_UINT: |
| if (shadow) |
| return error_type; |
| switch (dim) { |
| case GLSL_SAMPLER_DIM_1D: |
| return (array ? usampler1DArray_type : usampler1D_type); |
| case GLSL_SAMPLER_DIM_2D: |
| return (array ? usampler2DArray_type : usampler2D_type); |
| case GLSL_SAMPLER_DIM_3D: |
| if (array) |
| return error_type; |
| return usampler3D_type; |
| case GLSL_SAMPLER_DIM_CUBE: |
| return (array ? usamplerCubeArray_type : usamplerCube_type); |
| case GLSL_SAMPLER_DIM_RECT: |
| if (array) |
| return error_type; |
| return usampler2DRect_type; |
| case GLSL_SAMPLER_DIM_BUF: |
| if (array) |
| return error_type; |
| return usamplerBuffer_type; |
| case GLSL_SAMPLER_DIM_MS: |
| return (array ? usampler2DMSArray_type : usampler2DMS_type); |
| case GLSL_SAMPLER_DIM_EXTERNAL: |
| return error_type; |
| case GLSL_SAMPLER_DIM_SUBPASS: |
| case GLSL_SAMPLER_DIM_SUBPASS_MS: |
| return error_type; |
| } |
| case GLSL_TYPE_VOID: |
| return shadow ? samplerShadow_type : sampler_type; |
| default: |
| return error_type; |
| } |
| |
| unreachable("switch statement above should be complete"); |
| } |
| |
| const glsl_type * |
| glsl_type::get_image_instance(enum glsl_sampler_dim dim, |
| bool array, glsl_base_type type) |
| { |
| switch (type) { |
| case GLSL_TYPE_FLOAT: |
| switch (dim) { |
| case GLSL_SAMPLER_DIM_1D: |
| return (array ? image1DArray_type : image1D_type); |
| case GLSL_SAMPLER_DIM_2D: |
| return (array ? image2DArray_type : image2D_type); |
| case GLSL_SAMPLER_DIM_3D: |
| return image3D_type; |
| case GLSL_SAMPLER_DIM_CUBE: |
| return (array ? imageCubeArray_type : imageCube_type); |
| case GLSL_SAMPLER_DIM_RECT: |
| if (array) |
| return error_type; |
| else |
| return image2DRect_type; |
| case GLSL_SAMPLER_DIM_BUF: |
| if (array) |
| return error_type; |
| else |
| return imageBuffer_type; |
| case GLSL_SAMPLER_DIM_MS: |
| return (array ? image2DMSArray_type : image2DMS_type); |
| case GLSL_SAMPLER_DIM_SUBPASS: |
| return subpassInput_type; |
| case GLSL_SAMPLER_DIM_SUBPASS_MS: |
| return subpassInputMS_type; |
| case GLSL_SAMPLER_DIM_EXTERNAL: |
| return error_type; |
| } |
| case GLSL_TYPE_INT: |
| switch (dim) { |
| case GLSL_SAMPLER_DIM_1D: |
| return (array ? iimage1DArray_type : iimage1D_type); |
| case GLSL_SAMPLER_DIM_2D: |
| return (array ? iimage2DArray_type : iimage2D_type); |
| case GLSL_SAMPLER_DIM_3D: |
| if (array) |
| return error_type; |
| return iimage3D_type; |
| case GLSL_SAMPLER_DIM_CUBE: |
| return (array ? iimageCubeArray_type : iimageCube_type); |
| case GLSL_SAMPLER_DIM_RECT: |
| if (array) |
| return error_type; |
| return iimage2DRect_type; |
| case GLSL_SAMPLER_DIM_BUF: |
| if (array) |
| return error_type; |
| return iimageBuffer_type; |
| case GLSL_SAMPLER_DIM_MS: |
| return (array ? iimage2DMSArray_type : iimage2DMS_type); |
| case GLSL_SAMPLER_DIM_SUBPASS: |
| return isubpassInput_type; |
| case GLSL_SAMPLER_DIM_SUBPASS_MS: |
| return isubpassInputMS_type; |
| case GLSL_SAMPLER_DIM_EXTERNAL: |
| return error_type; |
| } |
| case GLSL_TYPE_UINT: |
| switch (dim) { |
| case GLSL_SAMPLER_DIM_1D: |
| return (array ? uimage1DArray_type : uimage1D_type); |
| case GLSL_SAMPLER_DIM_2D: |
| return (array ? uimage2DArray_type : uimage2D_type); |
| case GLSL_SAMPLER_DIM_3D: |
| if (array) |
| return error_type; |
| return uimage3D_type; |
| case GLSL_SAMPLER_DIM_CUBE: |
| return (array ? uimageCubeArray_type : uimageCube_type); |
| case GLSL_SAMPLER_DIM_RECT: |
| if (array) |
| return error_type; |
| return uimage2DRect_type; |
| case GLSL_SAMPLER_DIM_BUF: |
| if (array) |
| return error_type; |
| return uimageBuffer_type; |
| case GLSL_SAMPLER_DIM_MS: |
| return (array ? uimage2DMSArray_type : uimage2DMS_type); |
| case GLSL_SAMPLER_DIM_SUBPASS: |
| return usubpassInput_type; |
| case GLSL_SAMPLER_DIM_SUBPASS_MS: |
| return usubpassInputMS_type; |
| case GLSL_SAMPLER_DIM_EXTERNAL: |
| return error_type; |
| } |
| case GLSL_TYPE_INT64: |
| switch (dim) { |
| case GLSL_SAMPLER_DIM_1D: |
| return (array ? i64image1DArray_type : i64image1D_type); |
| case GLSL_SAMPLER_DIM_2D: |
| return (array ? i64image2DArray_type : i64image2D_type); |
| case GLSL_SAMPLER_DIM_3D: |
| if (array) |
| return error_type; |
| return i64image3D_type; |
| case GLSL_SAMPLER_DIM_CUBE: |
| return (array ? i64imageCubeArray_type : i64imageCube_type); |
| case GLSL_SAMPLER_DIM_RECT: |
| if (array) |
| return error_type; |
| return i64image2DRect_type; |
| case GLSL_SAMPLER_DIM_BUF: |
| if (array) |
| return error_type; |
| return i64imageBuffer_type; |
| case GLSL_SAMPLER_DIM_MS: |
| return (array ? i64image2DMSArray_type : i64image2DMS_type); |
| case GLSL_SAMPLER_DIM_SUBPASS: |
| case GLSL_SAMPLER_DIM_SUBPASS_MS: |
| case GLSL_SAMPLER_DIM_EXTERNAL: |
| return error_type; |
| } |
| case GLSL_TYPE_UINT64: |
| switch (dim) { |
| case GLSL_SAMPLER_DIM_1D: |
| return (array ? u64image1DArray_type : u64image1D_type); |
| case GLSL_SAMPLER_DIM_2D: |
| return (array ? u64image2DArray_type : u64image2D_type); |
| case GLSL_SAMPLER_DIM_3D: |
| if (array) |
| return error_type; |
| return u64image3D_type; |
| case GLSL_SAMPLER_DIM_CUBE: |
| return (array ? u64imageCubeArray_type : u64imageCube_type); |
| case GLSL_SAMPLER_DIM_RECT: |
| if (array) |
| return error_type; |
| return u64image2DRect_type; |
| case GLSL_SAMPLER_DIM_BUF: |
| if (array) |
| return error_type; |
| return u64imageBuffer_type; |
| case GLSL_SAMPLER_DIM_MS: |
| return (array ? u64image2DMSArray_type : u64image2DMS_type); |
| case GLSL_SAMPLER_DIM_SUBPASS: |
| case GLSL_SAMPLER_DIM_SUBPASS_MS: |
| case GLSL_SAMPLER_DIM_EXTERNAL: |
| return error_type; |
| } |
| case GLSL_TYPE_VOID: |
| switch (dim) { |
| case GLSL_SAMPLER_DIM_1D: |
| return (array ? vimage1DArray_type : vimage1D_type); |
| case GLSL_SAMPLER_DIM_2D: |
| return (array ? vimage2DArray_type : vimage2D_type); |
| case GLSL_SAMPLER_DIM_3D: |
| return (array ? error_type : vimage3D_type); |
| case GLSL_SAMPLER_DIM_BUF: |
| return (array ? error_type : vbuffer_type); |
| default: |
| return error_type; |
| } |
| default: |
| return error_type; |
| } |
| |
| unreachable("switch statement above should be complete"); |
| } |
| |
| const glsl_type * |
| 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 |
| * shaders. For example, two shaders may have different record types |
| * named 'foo'. |
| */ |
| char key[128]; |
| snprintf(key, sizeof(key), "%p[%u]x%uB", (void *) base, array_size, |
| explicit_stride); |
| |
| mtx_lock(&glsl_type::hash_mutex); |
| assert(glsl_type_users > 0); |
| |
| if (array_types == NULL) { |
| array_types = _mesa_hash_table_create(NULL, _mesa_hash_string, |
| _mesa_key_string_equal); |
| } |
| |
| 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, explicit_stride); |
| |
| entry = _mesa_hash_table_insert(array_types, |
| strdup(key), |
| (void *) t); |
| } |
| |
| assert(((glsl_type *) entry->data)->base_type == GLSL_TYPE_ARRAY); |
| assert(((glsl_type *) entry->data)->length == array_size); |
| assert(((glsl_type *) entry->data)->fields.array == base); |
| |
| glsl_type *t = (glsl_type *) entry->data; |
| |
| mtx_unlock(&glsl_type::hash_mutex); |
| |
| return t; |
| } |
| |
| bool |
| glsl_type::compare_no_precision(const glsl_type *b) const |
| { |
| if (this == b) |
| return true; |
| |
| if (this->is_array()) { |
| if (!b->is_array() || this->length != b->length) |
| return false; |
| |
| const glsl_type *b_no_array = b->fields.array; |
| |
| return this->fields.array->compare_no_precision(b_no_array); |
| } |
| |
| if (this->is_struct()) { |
| if (!b->is_struct()) |
| return false; |
| } else if (this->is_interface()) { |
| if (!b->is_interface()) |
| return false; |
| } else { |
| return false; |
| } |
| |
| return record_compare(b, |
| true, /* match_name */ |
| true, /* match_locations */ |
| false /* match_precision */); |
| } |
| |
| bool |
| glsl_type::record_compare(const glsl_type *b, bool match_name, |
| bool match_locations, bool match_precision) const |
| { |
| if (this->length != b->length) |
| return false; |
| |
| if (this->interface_packing != b->interface_packing) |
| return false; |
| |
| if (this->interface_row_major != b->interface_row_major) |
| return false; |
| |
| if (this->explicit_alignment != b->explicit_alignment) |
| return false; |
| |
| if (this->packed != b->packed) |
| return false; |
| |
| /* From the GLSL 4.20 specification (Sec 4.2): |
| * |
| * "Structures must have the same name, sequence of type names, and |
| * type definitions, and field names to be considered the same type." |
| * |
| * GLSL ES behaves the same (Ver 1.00 Sec 4.2.4, Ver 3.00 Sec 4.2.5). |
| * |
| * Section 7.4.1 (Shader Interface Matching) of the OpenGL 4.30 spec says: |
| * |
| * "Variables or block members declared as structures are considered |
| * to match in type if and only if structure members match in name, |
| * type, qualification, and declaration order." |
| */ |
| if (match_name) |
| if (strcmp(this->name, b->name) != 0) |
| return false; |
| |
| for (unsigned i = 0; i < this->length; i++) { |
| if (match_precision) { |
| if (this->fields.structure[i].type != b->fields.structure[i].type) |
| return false; |
| } else { |
| const glsl_type *ta = this->fields.structure[i].type; |
| const glsl_type *tb = b->fields.structure[i].type; |
| if (!ta->compare_no_precision(tb)) |
| return false; |
| } |
| if (strcmp(this->fields.structure[i].name, |
| b->fields.structure[i].name) != 0) |
| return false; |
| if (this->fields.structure[i].matrix_layout |
| != b->fields.structure[i].matrix_layout) |
| return false; |
| if (match_locations && this->fields.structure[i].location |
| != b->fields.structure[i].location) |
| return false; |
| if (this->fields.structure[i].offset |
| != b->fields.structure[i].offset) |
| return false; |
| if (this->fields.structure[i].interpolation |
| != b->fields.structure[i].interpolation) |
| return false; |
| if (this->fields.structure[i].centroid |
| != b->fields.structure[i].centroid) |
| return false; |
| if (this->fields.structure[i].sample |
| != b->fields.structure[i].sample) |
| return false; |
| if (this->fields.structure[i].patch |
| != b->fields.structure[i].patch) |
| return false; |
| if (this->fields.structure[i].memory_read_only |
| != b->fields.structure[i].memory_read_only) |
| return false; |
| if (this->fields.structure[i].memory_write_only |
| != b->fields.structure[i].memory_write_only) |
| return false; |
| if (this->fields.structure[i].memory_coherent |
| != b->fields.structure[i].memory_coherent) |
| return false; |
| if (this->fields.structure[i].memory_volatile |
| != b->fields.structure[i].memory_volatile) |
| return false; |
| if (this->fields.structure[i].memory_restrict |
| != b->fields.structure[i].memory_restrict) |
| return false; |
| if (this->fields.structure[i].image_format |
| != b->fields.structure[i].image_format) |
| return false; |
| if (match_precision && |
| this->fields.structure[i].precision |
| != b->fields.structure[i].precision) |
| return false; |
| if (this->fields.structure[i].explicit_xfb_buffer |
| != b->fields.structure[i].explicit_xfb_buffer) |
| return false; |
| if (this->fields.structure[i].xfb_buffer |
| != b->fields.structure[i].xfb_buffer) |
| return false; |
| if (this->fields.structure[i].xfb_stride |
| != b->fields.structure[i].xfb_stride) |
| return false; |
| } |
| |
| return true; |
| } |
| |
| |
| bool |
| glsl_type::record_key_compare(const void *a, const void *b) |
| { |
| const glsl_type *const key1 = (glsl_type *) a; |
| const glsl_type *const key2 = (glsl_type *) b; |
| |
| return strcmp(key1->name, key2->name) == 0 && |
| key1->record_compare(key2, true); |
| } |
| |
| |
| /** |
| * Generate an integer hash value for a glsl_type structure type. |
| */ |
| unsigned |
| glsl_type::record_key_hash(const void *a) |
| { |
| const glsl_type *const key = (glsl_type *) a; |
| uintptr_t hash = key->length; |
| unsigned retval; |
| |
| for (unsigned i = 0; i < key->length; i++) { |
| /* casting pointer to uintptr_t */ |
| hash = (hash * 13 ) + (uintptr_t) key->fields.structure[i].type; |
| } |
| |
| if (sizeof(hash) == 8) |
| retval = (hash & 0xffffffff) ^ ((uint64_t) hash >> 32); |
| else |
| retval = hash; |
| |
| return retval; |
| } |
| |
| |
| const glsl_type * |
| glsl_type::get_struct_instance(const glsl_struct_field *fields, |
| unsigned num_fields, |
| const char *name, |
| bool packed, unsigned explicit_alignment) |
| { |
| const glsl_type key(fields, num_fields, name, packed, explicit_alignment); |
| |
| mtx_lock(&glsl_type::hash_mutex); |
| assert(glsl_type_users > 0); |
| |
| if (struct_types == NULL) { |
| struct_types = _mesa_hash_table_create(NULL, record_key_hash, |
| record_key_compare); |
| } |
| |
| 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, |
| explicit_alignment); |
| |
| entry = _mesa_hash_table_insert(struct_types, t, (void *) t); |
| } |
| |
| assert(((glsl_type *) entry->data)->base_type == GLSL_TYPE_STRUCT); |
| 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; |
| |
| mtx_unlock(&glsl_type::hash_mutex); |
| |
| return t; |
| } |
| |
| |
| const glsl_type * |
| glsl_type::get_interface_instance(const glsl_struct_field *fields, |
| unsigned num_fields, |
| enum glsl_interface_packing packing, |
| bool row_major, |
| const char *block_name) |
| { |
| const glsl_type key(fields, num_fields, packing, row_major, block_name); |
| |
| mtx_lock(&glsl_type::hash_mutex); |
| assert(glsl_type_users > 0); |
| |
| if (interface_types == NULL) { |
| interface_types = _mesa_hash_table_create(NULL, record_key_hash, |
| record_key_compare); |
| } |
| |
| const struct hash_entry *entry = _mesa_hash_table_search(interface_types, |
| &key); |
| if (entry == NULL) { |
| const glsl_type *t = new glsl_type(fields, num_fields, |
| packing, row_major, block_name); |
| |
| entry = _mesa_hash_table_insert(interface_types, t, (void *) t); |
| } |
| |
| assert(((glsl_type *) entry->data)->base_type == GLSL_TYPE_INTERFACE); |
| assert(((glsl_type *) entry->data)->length == num_fields); |
| assert(strcmp(((glsl_type *) entry->data)->name, block_name) == 0); |
| |
| glsl_type *t = (glsl_type *) entry->data; |
| |
| mtx_unlock(&glsl_type::hash_mutex); |
| |
| return t; |
| } |
| |
| const glsl_type * |
| glsl_type::get_subroutine_instance(const char *subroutine_name) |
| { |
| const glsl_type key(subroutine_name); |
| |
| mtx_lock(&glsl_type::hash_mutex); |
| assert(glsl_type_users > 0); |
| |
| if (subroutine_types == NULL) { |
| subroutine_types = _mesa_hash_table_create(NULL, record_key_hash, |
| record_key_compare); |
| } |
| |
| const struct hash_entry *entry = _mesa_hash_table_search(subroutine_types, |
| &key); |
| if (entry == NULL) { |
| const glsl_type *t = new glsl_type(subroutine_name); |
| |
| entry = _mesa_hash_table_insert(subroutine_types, t, (void *) t); |
| } |
| |
| assert(((glsl_type *) entry->data)->base_type == GLSL_TYPE_SUBROUTINE); |
| assert(strcmp(((glsl_type *) entry->data)->name, subroutine_name) == 0); |
| |
| glsl_type *t = (glsl_type *) entry->data; |
| |
| mtx_unlock(&glsl_type::hash_mutex); |
| |
| return t; |
| } |
| |
| |
| static bool |
| function_key_compare(const void *a, const void *b) |
| { |
| const glsl_type *const key1 = (glsl_type *) a; |
| const glsl_type *const key2 = (glsl_type *) b; |
| |
| if (key1->length != key2->length) |
| return false; |
| |
| return memcmp(key1->fields.parameters, key2->fields.parameters, |
| (key1->length + 1) * sizeof(*key1->fields.parameters)) == 0; |
| } |
| |
| |
| static uint32_t |
| function_key_hash(const void *a) |
| { |
| const glsl_type *const key = (glsl_type *) a; |
| return _mesa_hash_data(key->fields.parameters, |
| (key->length + 1) * sizeof(*key->fields.parameters)); |
| } |
| |
| const glsl_type * |
| glsl_type::get_function_instance(const glsl_type *return_type, |
| const glsl_function_param *params, |
| unsigned num_params) |
| { |
| const glsl_type key(return_type, params, num_params); |
| |
| mtx_lock(&glsl_type::hash_mutex); |
| assert(glsl_type_users > 0); |
| |
| if (function_types == NULL) { |
| function_types = _mesa_hash_table_create(NULL, function_key_hash, |
| function_key_compare); |
| } |
| |
| struct hash_entry *entry = _mesa_hash_table_search(function_types, &key); |
| if (entry == NULL) { |
| const glsl_type *t = new glsl_type(return_type, params, num_params); |
| |
| entry = _mesa_hash_table_insert(function_types, t, (void *) t); |
| } |
| |
| const glsl_type *t = (const glsl_type *)entry->data; |
| |
| assert(t->base_type == GLSL_TYPE_FUNCTION); |
| assert(t->length == num_params); |
| |
| mtx_unlock(&glsl_type::hash_mutex); |
| |
| return t; |
| } |
| |
| |
| const glsl_type * |
| glsl_type::get_mul_type(const glsl_type *type_a, const glsl_type *type_b) |
| { |
| if (type_a->is_matrix() && type_b->is_matrix()) { |
| /* Matrix multiply. The columns of A must match the rows of B. Given |
| * the other previously tested constraints, this means the vector type |
| * of a row from A must be the same as the vector type of a column from |
| * B. |
| */ |
| if (type_a->row_type() == type_b->column_type()) { |
| /* The resulting matrix has the number of columns of matrix B and |
| * the number of rows of matrix A. We get the row count of A by |
| * looking at the size of a vector that makes up a column. The |
| * transpose (size of a row) is done for B. |
| */ |
| const glsl_type *const type = |
| get_instance(type_a->base_type, |
| type_a->column_type()->vector_elements, |
| type_b->row_type()->vector_elements); |
| assert(type != error_type); |
| |
| return type; |
| } |
| } else if (type_a == type_b) { |
| return type_a; |
| } else if (type_a->is_matrix()) { |
| /* A is a matrix and B is a column vector. Columns of A must match |
| * rows of B. Given the other previously tested constraints, this |
| * means the vector type of a row from A must be the same as the |
| * vector the type of B. |
| */ |
| if (type_a->row_type() == type_b) { |
| /* The resulting vector has a number of elements equal to |
| * the number of rows of matrix A. */ |
| const glsl_type *const type = |
| get_instance(type_a->base_type, |
| type_a->column_type()->vector_elements, |
| 1); |
| assert(type != error_type); |
| |
| return type; |
| } |
| } else { |
| assert(type_b->is_matrix()); |
| |
| /* A is a row vector and B is a matrix. Columns of A must match rows |
| * of B. Given the other previously tested constraints, this means |
| * the type of A must be the same as the vector type of a column from |
| * B. |
| */ |
| if (type_a == type_b->column_type()) { |
| /* The resulting vector has a number of elements equal to |
| * the number of columns of matrix B. */ |
| const glsl_type *const type = |
| get_instance(type_a->base_type, |
| type_b->row_type()->vector_elements, |
| 1); |
| assert(type != error_type); |
| |
| return type; |
| } |
| } |
| |
| return error_type; |
| } |
| |
| |
| const glsl_type * |
| glsl_type::field_type(const char *name) const |
| { |
| if (this->base_type != GLSL_TYPE_STRUCT |
| && this->base_type != GLSL_TYPE_INTERFACE) |
| return error_type; |
| |
| for (unsigned i = 0; i < this->length; i++) { |
| if (strcmp(name, this->fields.structure[i].name) == 0) |
| return this->fields.structure[i].type; |
| } |
| |
| return error_type; |
| } |
| |
| |
| int |
| glsl_type::field_index(const char *name) const |
| { |
| if (this->base_type != GLSL_TYPE_STRUCT |
| && this->base_type != GLSL_TYPE_INTERFACE) |
| return -1; |
| |
| for (unsigned i = 0; i < this->length; i++) { |
| if (strcmp(name, this->fields.structure[i].name) == 0) |
| return i; |
| } |
| |
| return -1; |
| } |
| |
| |
| unsigned |
| glsl_type::component_slots() const |
| { |
| switch (this->base_type) { |
| case GLSL_TYPE_UINT: |
| case GLSL_TYPE_INT: |
| case GLSL_TYPE_UINT8: |
| case GLSL_TYPE_INT8: |
| case GLSL_TYPE_UINT16: |
| case GLSL_TYPE_INT16: |
| case GLSL_TYPE_FLOAT: |
| case GLSL_TYPE_FLOAT16: |
| case GLSL_TYPE_BOOL: |
| return this->components(); |
| |
| case GLSL_TYPE_DOUBLE: |
| case GLSL_TYPE_UINT64: |
| case GLSL_TYPE_INT64: |
| return 2 * this->components(); |
| |
| case GLSL_TYPE_STRUCT: |
| case GLSL_TYPE_INTERFACE: { |
| unsigned size = 0; |
| |
| for (unsigned i = 0; i < this->length; i++) |
| size += this->fields.structure[i].type->component_slots(); |
| |
| return size; |
| } |
| |
| case GLSL_TYPE_ARRAY: |
| return this->length * this->fields.array->component_slots(); |
| |
| case GLSL_TYPE_SAMPLER: |
| case GLSL_TYPE_IMAGE: |
| return 2; |
| |
| case GLSL_TYPE_SUBROUTINE: |
| return 1; |
| |
| case GLSL_TYPE_FUNCTION: |
| case GLSL_TYPE_ATOMIC_UINT: |
| case GLSL_TYPE_VOID: |
| case GLSL_TYPE_ERROR: |
| break; |
| } |
| |
| return 0; |
| } |
| |
| unsigned |
| glsl_type::component_slots_aligned(unsigned offset) const |
| { |
| /* Align 64bit type only if it crosses attribute slot boundary. */ |
| switch (this->base_type) { |
| case GLSL_TYPE_UINT: |
| case GLSL_TYPE_INT: |
| case GLSL_TYPE_UINT8: |
| case GLSL_TYPE_INT8: |
| case GLSL_TYPE_UINT16: |
| case GLSL_TYPE_INT16: |
| case GLSL_TYPE_FLOAT: |
| case GLSL_TYPE_FLOAT16: |
| case GLSL_TYPE_BOOL: |
| return this->components(); |
| |
| case GLSL_TYPE_DOUBLE: |
| case GLSL_TYPE_UINT64: |
| case GLSL_TYPE_INT64: { |
| unsigned size = 2 * this->components(); |
| if (offset % 2 == 1 && (offset % 4 + size) > 4) { |
| size++; |
| } |
| |
| return size; |
| } |
| |
| case GLSL_TYPE_STRUCT: |
| case GLSL_TYPE_INTERFACE: { |
| unsigned size = 0; |
| |
| for (unsigned i = 0; i < this->length; i++) { |
| const glsl_type *member = this->fields.structure[i].type; |
| size += member->component_slots_aligned(size + offset); |
| } |
| |
| return size; |
| } |
| |
| case GLSL_TYPE_ARRAY: { |
| unsigned size = 0; |
| |
| for (unsigned i = 0; i < this->length; i++) { |
| size += this->fields.array->component_slots_aligned(size + offset); |
| } |
| |
| return size; |
| } |
| |
| case GLSL_TYPE_SAMPLER: |
| case GLSL_TYPE_IMAGE: |
| return 2 + ((offset % 4) == 3 ? 1 : 0); |
| |
| case GLSL_TYPE_SUBROUTINE: |
| return 1; |
| |
| case GLSL_TYPE_FUNCTION: |
| case GLSL_TYPE_ATOMIC_UINT: |
| case GLSL_TYPE_VOID: |
| case GLSL_TYPE_ERROR: |
| break; |
| } |
| |
| return 0; |
| } |
| |
| unsigned |
| glsl_type::struct_location_offset(unsigned length) const |
| { |
| unsigned offset = 0; |
| const glsl_type *t = this->without_array(); |
| if (t->is_struct()) { |
| assert(length <= t->length); |
| |
| for (unsigned i = 0; i < length; i++) { |
| const glsl_type *st = t->fields.structure[i].type; |
| const glsl_type *wa = st->without_array(); |
| if (wa->is_struct()) { |
| unsigned r_offset = wa->struct_location_offset(wa->length); |
| offset += st->is_array() ? |
| st->arrays_of_arrays_size() * r_offset : r_offset; |
| } else if (st->is_array() && st->fields.array->is_array()) { |
| unsigned outer_array_size = st->length; |
| const glsl_type *base_type = st->fields.array; |
| |
| /* For arrays of arrays the outer arrays take up a uniform |
| * slot for each element. The innermost array elements share a |
| * single slot so we ignore the innermost array when calculating |
| * the offset. |
| */ |
| while (base_type->fields.array->is_array()) { |
| outer_array_size = outer_array_size * base_type->length; |
| base_type = base_type->fields.array; |
| } |
| offset += outer_array_size; |
| } else { |
| /* We dont worry about arrays here because unless the array |
| * contains a structure or another array it only takes up a single |
| * uniform slot. |
| */ |
| offset += 1; |
| } |
| } |
| } |
| return offset; |
| } |
| |
| unsigned |
| glsl_type::uniform_locations() const |
| { |
| unsigned size = 0; |
| |
| switch (this->base_type) { |
| case GLSL_TYPE_UINT: |
| case GLSL_TYPE_INT: |
| case GLSL_TYPE_FLOAT: |
| case GLSL_TYPE_FLOAT16: |
| case GLSL_TYPE_DOUBLE: |
| case GLSL_TYPE_UINT16: |
| case GLSL_TYPE_UINT8: |
| case GLSL_TYPE_INT16: |
| case GLSL_TYPE_INT8: |
| case GLSL_TYPE_UINT64: |
| case GLSL_TYPE_INT64: |
| case GLSL_TYPE_BOOL: |
| case GLSL_TYPE_SAMPLER: |
| case GLSL_TYPE_IMAGE: |
| case GLSL_TYPE_SUBROUTINE: |
| return 1; |
| |
| case GLSL_TYPE_STRUCT: |
| case GLSL_TYPE_INTERFACE: |
| for (unsigned i = 0; i < this->length; i++) |
| size += this->fields.structure[i].type->uniform_locations(); |
| return size; |
| case GLSL_TYPE_ARRAY: |
| return this->length * this->fields.array->uniform_locations(); |
| default: |
| return 0; |
| } |
| } |
| |
| unsigned |
| glsl_type::varying_count() const |
| { |
| unsigned size = 0; |
| |
| switch (this->base_type) { |
| case GLSL_TYPE_UINT: |
| case GLSL_TYPE_INT: |
| case GLSL_TYPE_FLOAT: |
| case GLSL_TYPE_FLOAT16: |
| case GLSL_TYPE_DOUBLE: |
| case GLSL_TYPE_BOOL: |
| case GLSL_TYPE_UINT16: |
| case GLSL_TYPE_UINT8: |
| case GLSL_TYPE_INT16: |
| case GLSL_TYPE_INT8: |
| case GLSL_TYPE_UINT64: |
| case GLSL_TYPE_INT64: |
| return 1; |
| |
| case GLSL_TYPE_STRUCT: |
| case GLSL_TYPE_INTERFACE: |
| for (unsigned i = 0; i < this->length; i++) |
| size += this->fields.structure[i].type->varying_count(); |
| return size; |
| case GLSL_TYPE_ARRAY: |
| /* Don't count innermost array elements */ |
| if (this->without_array()->is_struct() || |
| this->without_array()->is_interface() || |
| this->fields.array->is_array()) |
| return this->length * this->fields.array->varying_count(); |
| else |
| return this->fields.array->varying_count(); |
| default: |
| assert(!"unsupported varying type"); |
| return 0; |
| } |
| } |
| |
| bool |
| glsl_type::can_implicitly_convert_to(const glsl_type *desired, |
| _mesa_glsl_parse_state *state) const |
| { |
| if (this == desired) |
| return true; |
| |
| /* GLSL 1.10 and ESSL do not allow implicit conversions. If there is no |
| * state, we're doing intra-stage function linking where these checks have |
| * already been done. |
| */ |
| if (state && !state->has_implicit_conversions()) |
| return false; |
| |
| /* There is no conversion among matrix types. */ |
| if (this->matrix_columns > 1 || desired->matrix_columns > 1) |
| return false; |
| |
| /* Vector size must match. */ |
| if (this->vector_elements != desired->vector_elements) |
| return false; |
| |
| /* int and uint can be converted to float. */ |
| if (desired->is_float() && this->is_integer_32()) |
| return true; |
| |
| /* With GLSL 4.0, ARB_gpu_shader5, or MESA_shader_integer_functions, int |
| * can be converted to uint. Note that state may be NULL here, when |
| * resolving function calls in the linker. By this time, all the |
| * state-dependent checks have already happened though, so allow anything |
| * that's allowed in any shader version. |
| */ |
| if ((!state || state->has_implicit_int_to_uint_conversion()) && |
| desired->base_type == GLSL_TYPE_UINT && this->base_type == GLSL_TYPE_INT) |
| return true; |
| |
| /* No implicit conversions from double. */ |
| if ((!state || state->has_double()) && this->is_double()) |
| return false; |
| |
| /* Conversions from different types to double. */ |
| if ((!state || state->has_double()) && desired->is_double()) { |
| if (this->is_float()) |
| return true; |
| if (this->is_integer_32()) |
| return true; |
| } |
| |
| return false; |
| } |
| |
| unsigned |
| glsl_type::std140_base_alignment(bool row_major) const |
| { |
| unsigned N = is_64bit() ? 8 : 4; |
| |
| /* (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()) { |
| switch (this->vector_elements) { |
| case 1: |
| return N; |
| case 2: |
| return 2 * N; |
| case 3: |
| case 4: |
| return 4 * N; |
| } |
| } |
| |
| /* (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. |
| * |
| * (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). |
| * |
| * (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). |
| * |
| * (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_scalar() || |
| this->fields.array->is_vector() || |
| this->fields.array->is_matrix()) { |
| return MAX2(this->fields.array->std140_base_alignment(row_major), 16); |
| } else { |
| assert(this->fields.array->is_struct() || |
| this->fields.array->is_array()); |
| return this->fields.array->std140_base_alignment(row_major); |
| } |
| } |
| |
| /* (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). |
| * |
| * (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). |
| */ |
| if (this->is_matrix()) { |
| const struct glsl_type *vec_type, *array_type; |
| int c = this->matrix_columns; |
| int r = this->vector_elements; |
| |
| if (row_major) { |
| vec_type = get_instance(base_type, c, 1); |
| array_type = glsl_type::get_array_instance(vec_type, r); |
| } else { |
| vec_type = get_instance(base_type, r, 1); |
| array_type = glsl_type::get_array_instance(vec_type, c); |
| } |
| |
| return array_type->std140_base_alignment(false); |
| } |
| |
| /* (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_struct()) { |
| unsigned base_alignment = 16; |
| for (unsigned i = 0; i < this->length; i++) { |
| bool field_row_major = row_major; |
| const enum glsl_matrix_layout matrix_layout = |
| glsl_matrix_layout(this->fields.structure[i].matrix_layout); |
| if (matrix_layout == GLSL_MATRIX_LAYOUT_ROW_MAJOR) { |
| field_row_major = true; |
| } else if (matrix_layout == GLSL_MATRIX_LAYOUT_COLUMN_MAJOR) { |
| field_row_major = false; |
| } |
| |
| const struct glsl_type *field_type = this->fields.structure[i].type; |
| base_alignment = MAX2(base_alignment, |
| field_type->std140_base_alignment(field_row_major)); |
| } |
| return base_alignment; |
| } |
| |
| assert(!"not reached"); |
| return -1; |
| } |
| |
| unsigned |
| glsl_type::std140_size(bool row_major) const |
| { |
| unsigned N = is_64bit() ? 8 : 4; |
| |
| /* (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()) { |
| assert(this->explicit_stride == 0); |
| return this->vector_elements * N; |
| } |
| |
| /* (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->without_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->without_array(); |
| array_len = this->arrays_of_arrays_size(); |
| } else { |
| element_type = this; |
| array_len = 1; |
| } |
| |
| if (row_major) { |
| vec_type = get_instance(element_type->base_type, |
| element_type->matrix_columns, 1); |
| |
| array_len *= element_type->vector_elements; |
| } else { |
| vec_type = get_instance(element_type->base_type, |
| 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()) { |
| unsigned stride; |
| if (this->without_array()->is_struct()) { |
| stride = this->without_array()->std140_size(row_major); |
| } else { |
| unsigned element_base_align = |
| this->without_array()->std140_base_alignment(row_major); |
| stride = MAX2(element_base_align, 16); |
| } |
| |
| unsigned size = this->arrays_of_arrays_size() * stride; |
| assert(this->explicit_stride == 0 || |
| size == this->length * this->explicit_stride); |
| return size; |
| } |
| |
| /* (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_struct() || this->is_interface()) { |
| unsigned size = 0; |
| unsigned max_align = 0; |
| |
| for (unsigned i = 0; i < this->length; i++) { |
| bool field_row_major = row_major; |
| const enum glsl_matrix_layout matrix_layout = |
| glsl_matrix_layout(this->fields.structure[i].matrix_layout); |
| if (matrix_layout == GLSL_MATRIX_LAYOUT_ROW_MAJOR) { |
| field_row_major = true; |
| } else if (matrix_layout == GLSL_MATRIX_LAYOUT_COLUMN_MAJOR) { |
| field_row_major = false; |
| } |
| |
| const struct glsl_type *field_type = this->fields.structure[i].type; |
| unsigned align = field_type->std140_base_alignment(field_row_major); |
| |
| /* Ignore unsized arrays when calculating size */ |
| if (field_type->is_unsized_array()) |
| continue; |
| |
| size = glsl_align(size, align); |
| size += field_type->std140_size(field_row_major); |
| |
| max_align = MAX2(align, max_align); |
| |
| if (field_type->is_struct() && (i + 1 < this->length)) |
| size = glsl_align(size, 16); |
| } |
| size = glsl_align(size, MAX2(max_align, 16)); |
| return size; |
| } |
| |
| assert(!"not reached"); |
| return -1; |
| } |
| |
| const glsl_type * |
| glsl_type::get_explicit_std140_type(bool row_major) const |
| { |
| if (this->is_vector() || this->is_scalar()) { |
| return this; |
| } else if (this->is_matrix()) { |
| const glsl_type *vec_type; |
| if (row_major) |
| vec_type = get_instance(this->base_type, this->matrix_columns, 1); |
| else |
| vec_type = get_instance(this->base_type, this->vector_elements, 1); |
| unsigned elem_size = vec_type->std140_size(false); |
| unsigned stride = glsl_align(elem_size, 16); |
| return get_instance(this->base_type, this->vector_elements, |
| this->matrix_columns, stride, row_major); |
| } else if (this->is_array()) { |
| unsigned elem_size = this->fields.array->std140_size(row_major); |
| const glsl_type *elem_type = |
| this->fields.array->get_explicit_std140_type(row_major); |
| unsigned stride = glsl_align(elem_size, 16); |
| return get_array_instance(elem_type, this->length, stride); |
| } else if (this->is_struct() || this->is_interface()) { |
| glsl_struct_field *fields = new glsl_struct_field[this->length]; |
| unsigned offset = 0; |
| for (unsigned i = 0; i < length; i++) { |
| fields[i] = this->fields.structure[i]; |
| |
| bool field_row_major = row_major; |
| if (fields[i].matrix_layout == GLSL_MATRIX_LAYOUT_COLUMN_MAJOR) { |
| field_row_major = false; |
| } else if (fields[i].matrix_layout == GLSL_MATRIX_LAYOUT_ROW_MAJOR) { |
| field_row_major = true; |
| } |
| fields[i].type = |
| fields[i].type->get_explicit_std140_type(field_row_major); |
| |
| unsigned fsize = fields[i].type->std140_size(field_row_major); |
| unsigned falign = fields[i].type->std140_base_alignment(field_row_major); |
| /* From the GLSL 460 spec section "Uniform and Shader Storage Block |
| * Layout Qualifiers": |
| * |
| * "The actual offset of a member is computed as follows: If |
| * offset was declared, start with that offset, otherwise start |
| * with the next available offset. If the resulting offset is not |
| * a multiple of the actual alignment, increase it to the first |
| * offset that is a multiple of the actual alignment. This results |
| * in the actual offset the member will have." |
| */ |
| if (fields[i].offset >= 0) { |
| assert((unsigned)fields[i].offset >= offset); |
| offset = fields[i].offset; |
| } |
| offset = glsl_align(offset, falign); |
| fields[i].offset = offset; |
| offset += fsize; |
| } |
| |
| const glsl_type *type; |
| if (this->is_struct()) |
| type = get_struct_instance(fields, this->length, this->name); |
| else |
| type = get_interface_instance(fields, this->length, |
| (enum glsl_interface_packing)this->interface_packing, |
| this->interface_row_major, |
| this->name); |
| |
| delete[] fields; |
| return type; |
| } else { |
| unreachable("Invalid type for UBO or SSBO"); |
| } |
| } |
| |
| unsigned |
| glsl_type::std430_base_alignment(bool row_major) const |
| { |
| |
| unsigned N = is_64bit() ? 8 : 4; |
| |
| /* (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()) { |
| switch (this->vector_elements) { |
| case 1: |
| return N; |
| case 2: |
| return 2 * N; |
| case 3: |
| case 4: |
| return 4 * N; |
| } |
| } |
| |
| /* OpenGL 4.30 spec, section 7.6.2.2 "Standard Uniform Block Layout": |
| * |
| * "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. |
| */ |
| |
| /* (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_array()) |
| return this->fields.array->std430_base_alignment(row_major); |
| |
| /* (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). |
| * |
| * (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). |
| */ |
| if (this->is_matrix()) { |
| const struct glsl_type *vec_type, *array_type; |
| int c = this->matrix_columns; |
| int r = this->vector_elements; |
| |
| if (row_major) { |
| vec_type = get_instance(base_type, c, 1); |
| array_type = glsl_type::get_array_instance(vec_type, r); |
| } else { |
| vec_type = get_instance(base_type, r, 1); |
| array_type = glsl_type::get_array_instance(vec_type, c); |
| } |
| |
| return array_type->std430_base_alignment(false); |
| } |
| |
| /* (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_struct()) { |
| unsigned base_alignment = 0; |
| for (unsigned i = 0; i < this->length; i++) { |
| bool field_row_major = row_major; |
| const enum glsl_matrix_layout matrix_layout = |
| glsl_matrix_layout(this->fields.structure[i].matrix_layout); |
| if (matrix_layout == GLSL_MATRIX_LAYOUT_ROW_MAJOR) { |
| field_row_major = true; |
| } else if (matrix_layout == GLSL_MATRIX_LAYOUT_COLUMN_MAJOR) { |
| field_row_major = false; |
| } |
| |
| const struct glsl_type *field_type = this->fields.structure[i].type; |
| base_alignment = MAX2(base_alignment, |
| field_type->std430_base_alignment(field_row_major)); |
| } |
| assert(base_alignment > 0); |
| return base_alignment; |
| } |
| assert(!"not reached"); |
| return -1; |
| } |
| |
| unsigned |
| glsl_type::std430_array_stride(bool row_major) const |
| { |
| unsigned N = is_64bit() ? 8 : 4; |
| |
| /* 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" |
| * |
| * (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_vector() && this->vector_elements == 3) |
| return 4 * N; |
| |
| /* By default use std430_size(row_major) */ |
| unsigned stride = this->std430_size(row_major); |
| assert(this->explicit_stride == 0 || this->explicit_stride == stride); |
| return stride; |
| } |
| |
| /* Note that the value returned by this method is only correct if the |
| * explit offset, and stride values are set, so only with SPIR-V shaders. |
| * Should not be used with GLSL shaders. |
| */ |
| |
| unsigned |
| glsl_type::explicit_size(bool align_to_stride) const |
| { |
| if (this->is_struct() || this->is_interface()) { |
| if (this->length > 0) { |
| unsigned size = 0; |
| |
| for (unsigned i = 0; i < this->length; i++) { |
| assert(this->fields.structure[i].offset >= 0); |
| unsigned last_byte = this->fields.structure[i].offset + |
| this->fields.structure[i].type->explicit_size(); |
| size = MAX2(size, last_byte); |
| } |
| |
| return size; |
| } else { |
| return 0; |
| } |
| } else if (this->is_array()) { |
| /* From ARB_program_interface_query spec: |
| * |
| * "For the property of BUFFER_DATA_SIZE, then the implementation-dependent |
| * minimum total buffer object size, in basic machine units, required to |
| * hold all active variables associated with an active uniform block, shader |
| * storage block, or atomic counter buffer is written to <params>. If the |
| * final member of an active shader storage block is array with no declared |
| * size, the minimum buffer size is computed assuming the array was declared |
| * as an array with one element." |
| * |
| */ |
| if (this->is_unsized_array()) |
| return this->explicit_stride; |
| |
| assert(this->length > 0); |
| unsigned elem_size = align_to_stride ? this->explicit_stride : this->fields.array->explicit_size(); |
| assert(this->explicit_stride >= elem_size); |
| |
| return this->explicit_stride * (this->length - 1) + elem_size; |
| } else if (this->is_matrix()) { |
| const struct glsl_type *elem_type; |
| unsigned length; |
| |
| if (this->interface_row_major) { |
| elem_type = get_instance(this->base_type, |
| this->matrix_columns, 1); |
| length = this->vector_elements; |
| } else { |
| elem_type = get_instance(this->base_type, |
| this->vector_elements, 1); |
| length = this->matrix_columns; |
| } |
| |
| unsigned elem_size = align_to_stride ? this->explicit_stride : elem_type->explicit_size(); |
| |
| assert(this->explicit_stride); |
| return this->explicit_stride * (length - 1) + elem_size; |
| } |
| |
| unsigned N = this->bit_size() / 8; |
| |
| return this->vector_elements * N; |
| } |
| |
| unsigned |
| glsl_type::std430_size(bool row_major) const |
| { |
| unsigned N = is_64bit() ? 8 : 4; |
| |
| /* OpenGL 4.30 spec, section 7.6.2.2 "Standard Uniform Block Layout": |
| * |
| * "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 (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; |
| const struct glsl_type *vec_type; |
| unsigned int array_len; |
| |
| if (this->is_array()) { |
| element_type = this->without_array(); |
| array_len = this->arrays_of_arrays_size(); |
| } else { |
| element_type = this; |
| array_len = 1; |
| } |
| |
| if (row_major) { |
| vec_type = get_instance(element_type->base_type, |
| element_type->matrix_columns, 1); |
| |
| array_len *= element_type->vector_elements; |
| } else { |
| vec_type = get_instance(element_type->base_type, |
| 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->std430_size(false); |
| } |
| |
| if (this->is_array()) { |
| unsigned stride; |
| if (this->without_array()->is_struct()) |
| stride = this->without_array()->std430_size(row_major); |
| else |
| stride = this->without_array()->std430_base_alignment(row_major); |
| |
| unsigned size = this->arrays_of_arrays_size() * stride; |
| assert(this->explicit_stride == 0 || |
| size == this->length * this->explicit_stride); |
| return size; |
| } |
| |
| if (this->is_struct() || this->is_interface()) { |
| unsigned size = 0; |
| unsigned max_align = 0; |
| |
| for (unsigned i = 0; i < this->length; i++) { |
| bool field_row_major = row_major; |
| const enum glsl_matrix_layout matrix_layout = |
| glsl_matrix_layout(this->fields.structure[i].matrix_layout); |
| if (matrix_layout == GLSL_MATRIX_LAYOUT_ROW_MAJOR) { |
| field_row_major = true; |
| } else if (matrix_layout == GLSL_MATRIX_LAYOUT_COLUMN_MAJOR) { |
| field_row_major = false; |
| } |
| |
| const struct glsl_type *field_type = this->fields.structure[i].type; |
| unsigned align = field_type->std430_base_alignment(field_row_major); |
| size = glsl_align(size, align); |
| size += field_type->std430_size(field_row_major); |
| |
| max_align = MAX2(align, max_align); |
| } |
| size = glsl_align(size, max_align); |
| return size; |
| } |
| |
| assert(!"not reached"); |
| return -1; |
| } |
| |
| const glsl_type * |
| glsl_type::get_explicit_std430_type(bool row_major) const |
| { |
| if (this->is_vector() || this->is_scalar()) { |
| return this; |
| } else if (this->is_matrix()) { |
| const glsl_type *vec_type; |
| if (row_major) |
| vec_type = get_instance(this->base_type, this->matrix_columns, 1); |
| else |
| vec_type = get_instance(this->base_type, this->vector_elements, 1); |
| unsigned stride = vec_type->std430_array_stride(false); |
| return get_instance(this->base_type, this->vector_elements, |
| this->matrix_columns, stride, row_major); |
| } else if (this->is_array()) { |
| const glsl_type *elem_type = |
| this->fields.array->get_explicit_std430_type(row_major); |
| unsigned stride = this->fields.array->std430_array_stride(row_major); |
| return get_array_instance(elem_type, this->length, stride); |
| } else if (this->is_struct() || this->is_interface()) { |
| glsl_struct_field *fields = new glsl_struct_field[this->length]; |
| unsigned offset = 0; |
| for (unsigned i = 0; i < length; i++) { |
| fields[i] = this->fields.structure[i]; |
| |
| bool field_row_major = row_major; |
| if (fields[i].matrix_layout == GLSL_MATRIX_LAYOUT_COLUMN_MAJOR) { |
| field_row_major = false; |
| } else if (fields[i].matrix_layout == GLSL_MATRIX_LAYOUT_ROW_MAJOR) { |
| field_row_major = true; |
| } |
| fields[i].type = |
| fields[i].type->get_explicit_std430_type(field_row_major); |
| |
| unsigned fsize = fields[i].type->std430_size(field_row_major); |
| unsigned falign = fields[i].type->std430_base_alignment(field_row_major); |
| /* From the GLSL 460 spec section "Uniform and Shader Storage Block |
| * Layout Qualifiers": |
| * |
| * "The actual offset of a member is computed as follows: If |
| * offset was declared, start with that offset, otherwise start |
| * with the next available offset. If the resulting offset is not |
| * a multiple of the actual alignment, increase it to the first |
| * offset that is a multiple of the actual alignment. This results |
| * in the actual offset the member will have." |
| */ |
| if (fields[i].offset >= 0) { |
| assert((unsigned)fields[i].offset >= offset); |
| offset = fields[i].offset; |
| } |
| offset = glsl_align(offset, falign); |
| fields[i].offset = offset; |
| offset += fsize; |
| } |
| |
| const glsl_type *type; |
| if (this->is_struct()) |
| type = get_struct_instance(fields, this->length, this->name); |
| else |
| type = get_interface_instance(fields, this->length, |
| (enum glsl_interface_packing)this->interface_packing, |
| this->interface_row_major, |
| this->name); |
| |
| delete[] fields; |
| return type; |
| } else { |
| unreachable("Invalid type for SSBO"); |
| } |
| } |
| |
| const glsl_type * |
| glsl_type::get_explicit_interface_type(bool supports_std430) const |
| { |
| enum glsl_interface_packing packing = |
| this->get_internal_ifc_packing(supports_std430); |
| if (packing == GLSL_INTERFACE_PACKING_STD140) { |
| return this->get_explicit_std140_type(this->interface_row_major); |
| } else { |
| assert(packing == GLSL_INTERFACE_PACKING_STD430); |
| return this->get_explicit_std430_type(this->interface_row_major); |
| } |
| } |
| |
| static unsigned |
| explicit_type_scalar_byte_size(const glsl_type *type) |
| { |
| if (type->base_type == GLSL_TYPE_BOOL) |
| return 4; |
| else |
| return glsl_base_type_get_bit_size(type->base_type) / 8; |
| } |
| |
| /* This differs from get_explicit_std430_type() in that it: |
| * - can size arrays slightly smaller ("stride * (len - 1) + elem_size" instead |
| * of "stride * len") |
| * - consumes a glsl_type_size_align_func which allows 8 and 16-bit values to be |
| * packed more tightly |
| * - overrides any struct field offsets but get_explicit_std430_type() tries to |
| * respect any existing ones |
| */ |
| 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_image() || this->is_sampler()) { |
| type_info(this, size, alignment); |
| assert(*alignment > 0); |
| return this; |
| } else 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 > 0); |
| 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 = |
| this->fields.array->get_explicit_type_for_size_align(type_info, &elem_size, &elem_align); |
| |
| unsigned stride = align(elem_size, elem_align); |
| |
| *size = stride * (this->length - 1) + elem_size; |
| *alignment = elem_align; |
| return glsl_type::get_array_instance(explicit_element, this->length, stride); |
| } else if (this->is_struct() || this->is_interface()) { |
| struct glsl_struct_field *fields = (struct glsl_struct_field *) |
| malloc(sizeof(struct glsl_struct_field) * this->length); |
| |
| *size = 0; |
| *alignment = 0; |
| for (unsigned i = 0; i < this->length; i++) { |
| fields[i] = this->fields.structure[i]; |
| assert(fields[i].matrix_layout != GLSL_MATRIX_LAYOUT_ROW_MAJOR); |
| |
| unsigned field_size, field_align; |
| fields[i].type = |
| fields[i].type->get_explicit_type_for_size_align(type_info, &field_size, &field_align); |
| field_align = this->packed ? 1 : field_align; |
| fields[i].offset = align(*size, field_align); |
| |
| *size = fields[i].offset + field_size; |
| *alignment = MAX2(*alignment, field_align); |
| } |
| |
| const glsl_type *type; |
| if (this->is_struct()) { |
| type = get_struct_instance(fields, this->length, this->name, |
| this->packed, *alignment); |
| } else { |
| assert(!this->packed); |
| type = get_interface_instance(fields, this->length, |
| (enum glsl_interface_packing)this->interface_packing, |
| this->interface_row_major, |
| this->name); |
| } |
| free(fields); |
| return type; |
| } else if (this->is_matrix()) { |
| unsigned col_size, col_align; |
| type_info(this->column_type(), &col_size, &col_align); |
| unsigned stride = align(col_size, col_align); |
| |
| *size = this->matrix_columns * stride; |
| /* Matrix and column alignments match. See glsl_type::column_type() */ |
| assert(col_align > 0); |
| *alignment = col_align; |
| return glsl_type::get_instance(this->base_type, this->vector_elements, |
| this->matrix_columns, stride, false, *alignment); |
| } else { |
| unreachable("Unhandled type."); |
| } |
| } |
| |
| const glsl_type * |
| glsl_type::replace_vec3_with_vec4() const |
| { |
| if (this->is_scalar() || this->is_vector() || this->is_matrix()) { |
| if (this->interface_row_major) { |
| if (this->matrix_columns == 3) { |
| return glsl_type::get_instance(this->base_type, |
| this->vector_elements, |
| 4, /* matrix columns */ |
| this->explicit_stride, |
| this->interface_row_major, |
| this->explicit_alignment); |
| } else { |
| return this; |
| } |
| } else { |
| if (this->vector_elements == 3) { |
| return glsl_type::get_instance(this->base_type, |
| 4, /* vector elements */ |
| this->matrix_columns, |
| this->explicit_stride, |
| this->interface_row_major, |
| this->explicit_alignment); |
| } else { |
| return this; |
| } |
| } |
| } else if (this->is_array()) { |
| const glsl_type *vec4_elem_type = |
| this->fields.array->replace_vec3_with_vec4(); |
| if (vec4_elem_type == this->fields.array) |
| return this; |
| return glsl_type::get_array_instance(vec4_elem_type, |
| this->length, |
| this->explicit_stride); |
| } else if (this->is_struct() || this->is_interface()) { |
| struct glsl_struct_field *fields = (struct glsl_struct_field *) |
| malloc(sizeof(struct glsl_struct_field) * this->length); |
| |
| bool needs_new_type = false; |
| for (unsigned i = 0; i < this->length; i++) { |
| fields[i] = this->fields.structure[i]; |
| assert(fields[i].matrix_layout != GLSL_MATRIX_LAYOUT_ROW_MAJOR); |
| fields[i].type = fields[i].type->replace_vec3_with_vec4(); |
| if (fields[i].type != this->fields.structure[i].type) |
| needs_new_type = true; |
| } |
| |
| const glsl_type *type; |
| if (!needs_new_type) { |
| type = this; |
| } else if (this->is_struct()) { |
| type = get_struct_instance(fields, this->length, this->name, |
| this->packed, this->explicit_alignment); |
| } else { |
| assert(!this->packed); |
| type = get_interface_instance(fields, this->length, |
| (enum glsl_interface_packing)this->interface_packing, |
| this->interface_row_major, |
| this->name); |
| } |
| free(fields); |
| return type; |
| } else { |
| unreachable("Unhandled type."); |
| } |
| } |
| |
| unsigned |
| glsl_type::count_vec4_slots(bool is_gl_vertex_input, bool is_bindless) const |
| { |
| /* From page 31 (page 37 of the PDF) of the GLSL 1.50 spec: |
| * |
| * "A scalar input counts the same amount against this limit as a vec4, |
| * so applications may want to consider packing groups of four |
| * unrelated float inputs together into a vector to better utilize the |
| * capabilities of the underlying hardware. A matrix input will use up |
| * multiple locations. The number of locations used will equal the |
| * number of columns in the matrix." |
| * |
| * The spec does not explicitly say how arrays are counted. However, it |
| * should be safe to assume the total number of slots consumed by an array |
| * is the number of entries in the array multiplied by the number of slots |
| * consumed by a single element of the array. |
| * |
| * The spec says nothing about how structs are counted, because vertex |
| * attributes are not allowed to be (or contain) structs. However, Mesa |
| * allows varying structs, the number of varying slots taken up by a |
| * varying struct is simply equal to the sum of the number of slots taken |
| * up by each element. |
| * |
| * Doubles are counted different depending on whether they are vertex |
| * inputs or everything else. Vertex inputs from ARB_vertex_attrib_64bit |
| * take one location no matter what size they are, otherwise dvec3/4 |
| * take two locations. |
| */ |
| switch (this->base_type) { |
| case GLSL_TYPE_UINT: |
| case GLSL_TYPE_INT: |
| case GLSL_TYPE_UINT8: |
| case GLSL_TYPE_INT8: |
| case GLSL_TYPE_UINT16: |
| case GLSL_TYPE_INT16: |
| case GLSL_TYPE_FLOAT: |
| case GLSL_TYPE_FLOAT16: |
| case GLSL_TYPE_BOOL: |
| return this->matrix_columns; |
| case GLSL_TYPE_DOUBLE: |
| case GLSL_TYPE_UINT64: |
| case GLSL_TYPE_INT64: |
| if (this->vector_elements > 2 && !is_gl_vertex_input) |
| return this->matrix_columns * 2; |
| else |
| return this->matrix_columns; |
| case GLSL_TYPE_STRUCT: |
| case GLSL_TYPE_INTERFACE: { |
| unsigned size = 0; |
| |
| for (unsigned i = 0; i < this->length; i++) { |
| const glsl_type *member_type = this->fields.structure[i].type; |
| size += member_type->count_vec4_slots(is_gl_vertex_input, is_bindless); |
| } |
| |
| return size; |
| } |
| |
| case GLSL_TYPE_ARRAY: { |
| const glsl_type *element = this->fields.array; |
| return this->length * element->count_vec4_slots(is_gl_vertex_input, |
| is_bindless); |
| } |
| |
| case GLSL_TYPE_SAMPLER: |
| case GLSL_TYPE_IMAGE: |
| if (!is_bindless) |
| return 0; |
| else |
| return 1; |
| |
| case GLSL_TYPE_SUBROUTINE: |
| return 1; |
| |
| case GLSL_TYPE_FUNCTION: |
| case GLSL_TYPE_ATOMIC_UINT: |
| case GLSL_TYPE_VOID: |
| case GLSL_TYPE_ERROR: |
| break; |
| } |
| |
| assert(!"Unexpected type in count_attribute_slots()"); |
| |
| return 0; |
| } |
| |
| unsigned |
| glsl_type::count_dword_slots(bool is_bindless) const |
| { |
| switch (this->base_type) { |
| case GLSL_TYPE_UINT: |
| case GLSL_TYPE_INT: |
| case GLSL_TYPE_FLOAT: |
| case GLSL_TYPE_BOOL: |
| return this->components(); |
| case GLSL_TYPE_UINT16: |
| case GLSL_TYPE_INT16: |
| case GLSL_TYPE_FLOAT16: |
| return DIV_ROUND_UP(this->components(), 2); |
| case GLSL_TYPE_UINT8: |
| case GLSL_TYPE_INT8: |
| return DIV_ROUND_UP(this->components(), 4); |
| case GLSL_TYPE_IMAGE: |
| case GLSL_TYPE_SAMPLER: |
| if (!is_bindless) |
| return 0; |
| FALLTHROUGH; |
| case GLSL_TYPE_DOUBLE: |
| case GLSL_TYPE_UINT64: |
| case GLSL_TYPE_INT64: |
| return this->components() * 2; |
| case GLSL_TYPE_ARRAY: |
| return this->fields.array->count_dword_slots(is_bindless) * |
| this->length; |
| |
| case GLSL_TYPE_INTERFACE: |
| case GLSL_TYPE_STRUCT: { |
| unsigned size = 0; |
| for (unsigned i = 0; i < this->length; i++) { |
| size += this->fields.structure[i].type->count_dword_slots(is_bindless); |
| } |
| return size; |
| } |
| |
| case GLSL_TYPE_ATOMIC_UINT: |
| return 0; |
| case GLSL_TYPE_SUBROUTINE: |
| return 1; |
| case GLSL_TYPE_VOID: |
| case GLSL_TYPE_ERROR: |
| case GLSL_TYPE_FUNCTION: |
| default: |
| unreachable("invalid type in st_glsl_type_dword_size()"); |
| } |
| |
| return 0; |
| } |
| |
| int |
| glsl_type::coordinate_components() const |
| { |
| enum glsl_sampler_dim dim = (enum glsl_sampler_dim)sampler_dimensionality; |
| int size = glsl_get_sampler_dim_coordinate_components(dim); |
| |
| /* Array textures need an additional component for the array index, except |
| * for cubemap array images that behave like a 2D array of interleaved |
| * cubemap faces. |
| */ |
| if (sampler_array && |
| !(is_image() && sampler_dimensionality == GLSL_SAMPLER_DIM_CUBE)) |
| size += 1; |
| |
| return size; |
| } |
| |
| /** |
| * Declarations of type flyweights (glsl_type::_foo_type) and |
| * convenience pointers (glsl_type::foo_type). |
| * @{ |
| |