X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fcompiler%2Fglsl_types.cpp;h=2213055021d9b3fbbb9714f7c9cacf543f54d84f;hb=9f37bc419cb842bee902eb3117a20b7a57d64381;hp=899dd16878e76586649dc8d47a9da0f7f7310b34;hpb=659f333b3a4ff92ff985b168728ad37fe3d7e437;p=mesa.git diff --git a/src/compiler/glsl_types.cpp b/src/compiler/glsl_types.cpp index 899dd16878e..2213055021d 100644 --- a/src/compiler/glsl_types.cpp +++ b/src/compiler/glsl_types.cpp @@ -37,6 +37,12 @@ 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 simultanously 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, @@ -44,7 +50,7 @@ glsl_type::glsl_type(GLenum gl_type, 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), + interface_packing(0), interface_row_major(row_major), packed(0), vector_elements(vector_elements), matrix_columns(matrix_columns), length(0), explicit_stride(explicit_stride) { @@ -79,7 +85,7 @@ 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), + interface_row_major(0), packed(0), length(0), explicit_stride(0) { this->mem_ctx = ralloc_context(NULL); @@ -128,7 +134,7 @@ glsl_type::glsl_type(const glsl_struct_field *fields, unsigned num_fields, 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), + interface_row_major((unsigned) row_major), packed(0), vector_elements(0), matrix_columns(0), length(num_fields), explicit_stride(0) { @@ -153,7 +159,7 @@ glsl_type::glsl_type(const glsl_type *return_type, 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), + interface_packing(0), interface_row_major(0), packed(0), vector_elements(0), matrix_columns(0), length(num_params), explicit_stride(0) { @@ -182,7 +188,7 @@ 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), + interface_packing(0), interface_row_major(0), packed(0), vector_elements(1), matrix_columns(1), length(0), explicit_stride(0) { @@ -469,12 +475,25 @@ hash_free_type_function(struct hash_entry *entry) } void -_mesa_glsl_release_types(void) +glsl_type_singleton_init_or_ref() { - /* Should only be called during atexit (either when unloading shared - * object, or if process terminates), so no mutex-locking should be - * necessary. - */ + 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); @@ -505,6 +524,8 @@ _mesa_glsl_release_types(void) _mesa_hash_table_destroy(glsl_type::subroutine_types, hash_free_type_function); glsl_type::subroutine_types = NULL; } + + mtx_unlock(&glsl_type::hash_mutex); } @@ -512,7 +533,7 @@ 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), + interface_packing(0), interface_row_major(0), packed(0), vector_elements(0), matrix_columns(0), length(length), name(NULL), explicit_stride(explicit_stride) { @@ -535,7 +556,7 @@ glsl_type::glsl_type(const glsl_type *array, unsigned length, char *const n = (char *) ralloc_size(this->mem_ctx, name_length); if (length == 0) - util_snprintf(n, name_length, "%s[]", array->name); + snprintf(n, name_length, "%s[]", array->name); else { /* insert outermost dimensions in the correct spot * otherwise the dimension order will be backwards @@ -543,11 +564,11 @@ glsl_type::glsl_type(const glsl_type *array, unsigned length, const char *pos = strchr(array->name, '['); if (pos) { int idx = pos - array->name; - util_snprintf(n, idx+1, "%s", array->name); - util_snprintf(n + idx, name_length - idx, "[%u]%s", + snprintf(n, idx+1, "%s", array->name); + snprintf(n + idx, name_length - idx, "[%u]%s", length, array->name + idx); } else { - util_snprintf(n, name_length, "%s[%u]", array->name, length); + snprintf(n, name_length, "%s[%u]", array->name, length); } } @@ -613,10 +634,11 @@ glsl_type::get_instance(unsigned base_type, unsigned rows, unsigned 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" : ""); + snprintf(name, sizeof(name), "%sx%uB%s", bare_type->name, + explicit_stride, row_major ? "RM" : ""); mtx_lock(&glsl_type::hash_mutex); + assert(glsl_type_users > 0); if (explicit_matrix_types == NULL) { explicit_matrix_types = @@ -978,10 +1000,11 @@ glsl_type::get_array_instance(const glsl_type *base, * named 'foo'. */ char key[128]; - util_snprintf(key, sizeof(key), "%p[%u]x%uB", (void *) base, array_size, - explicit_stride); + 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_key_hash_string, @@ -1006,9 +1029,40 @@ glsl_type::get_array_instance(const glsl_type *base, return (glsl_type *) entry->data; } +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_locations) const +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; @@ -1025,13 +1079,27 @@ glsl_type::record_compare(const glsl_type *b, bool match_locations) const * 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 (strcmp(this->name, b->name) != 0) - return false; + if (match_name) + if (strcmp(this->name, b->name) != 0) + return false; for (unsigned i = 0; i < this->length; i++) { - if (this->fields.structure[i].type != b->fields.structure[i].type) - return false; + 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; @@ -1074,7 +1142,8 @@ glsl_type::record_compare(const glsl_type *b, bool match_locations) const if (this->fields.structure[i].image_format != b->fields.structure[i].image_format) return false; - if (this->fields.structure[i].precision + if (match_precision && + this->fields.structure[i].precision != b->fields.structure[i].precision) return false; if (this->fields.structure[i].explicit_xfb_buffer @@ -1098,7 +1167,8 @@ 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); + return strcmp(key1->name, key2->name) == 0 && + key1->record_compare(key2, true); } @@ -1135,6 +1205,7 @@ glsl_type::get_struct_instance(const glsl_struct_field *fields, const glsl_type key(fields, num_fields, name, packed); 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, @@ -1170,6 +1241,7 @@ glsl_type::get_interface_instance(const glsl_struct_field *fields, 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, @@ -1200,6 +1272,7 @@ 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, @@ -1253,6 +1326,7 @@ glsl_type::get_function_instance(const glsl_type *return_type, 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, @@ -1564,7 +1638,7 @@ glsl_type::can_implicitly_convert_to(const glsl_type *desired, return false; /* int and uint can be converted to float. */ - if (desired->is_float() && this->is_integer()) + if (desired->is_float() && this->is_integer_32()) return true; /* With GLSL 4.0, ARB_gpu_shader5, or MESA_shader_integer_functions, int @@ -1585,7 +1659,7 @@ glsl_type::can_implicitly_convert_to(const glsl_type *desired, if ((!state || state->has_double()) && desired->is_double()) { if (this->is_float()) return true; - if (this->is_integer()) + if (this->is_integer_32()) return true; } @@ -2055,6 +2129,74 @@ glsl_type::std430_array_stride(bool row_major) const 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 . 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 { @@ -2228,6 +2370,67 @@ glsl_type::get_explicit_interface_type(bool supports_std430) const } } +/* 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_scalar() || this->is_vector()) { + type_info(this, size, alignment); + return this; + } 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()) { + 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); + fields[i].offset = align(*size, field_align); + + *size = fields[i].offset + field_size; + *alignment = MAX2(*alignment, field_align); + } + + const glsl_type *type = glsl_type::get_struct_instance(fields, this->length, this->name, false); + 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; + *alignment = col_align; + return glsl_type::get_instance(this->base_type, this->vector_elements, + this->matrix_columns, stride, false); + } else { + unreachable("Unhandled type."); + } +} + unsigned glsl_type::count_attribute_slots(bool is_gl_vertex_input) const { @@ -2554,3 +2757,51 @@ decode_type_from_blob(struct blob_reader *blob) return NULL; } } + +unsigned +glsl_type::cl_alignment() const +{ + /* vectors unlike arrays are aligned to their size */ + if (this->is_scalar() || this->is_vector()) + return this->cl_size(); + else if (this->is_array()) + return this->without_array()->cl_alignment(); + else if (this->is_struct()) { + /* Packed Structs are 0x1 aligned despite their size. */ + if (this->packed) + return 1; + + unsigned res = 1; + for (unsigned i = 0; i < this->length; ++i) { + struct glsl_struct_field &field = this->fields.structure[i]; + res = MAX2(res, field.type->cl_alignment()); + } + return res; + } + return 1; +} + +unsigned +glsl_type::cl_size() const +{ + if (this->is_scalar()) { + return glsl_base_type_get_bit_size(this->base_type) / 8; + } else if (this->is_vector()) { + unsigned vec_elemns = this->vector_elements == 3 ? 4 : this->vector_elements; + return vec_elemns * glsl_base_type_get_bit_size(this->base_type) / 8; + } else if (this->is_array()) { + unsigned size = this->without_array()->cl_size(); + return size * this->length; + } else if (this->is_struct()) { + unsigned size = 0; + for (unsigned i = 0; i < this->length; ++i) { + struct glsl_struct_field &field = this->fields.structure[i]; + /* if a struct is packed, members don't get aligned */ + if (!this->packed) + size = align(size, field.type->cl_alignment()); + size += field.type->cl_size(); + } + return size; + } + return 1; +}