X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fglsl%2Fglsl_types.cpp;h=37406b8073efb9acb26ea3316342f2c9e26d4db7;hb=a62edcce4eb4c800d972817a20ee874bf2a2c3ef;hp=8b0a2480585de96b1e94e7d1c7f9c652f56ac1bb;hpb=bcdda04349e1f2b32fb2eca32c6589858c1e38e6;p=mesa.git diff --git a/src/glsl/glsl_types.cpp b/src/glsl/glsl_types.cpp index 8b0a2480585..37406b8073e 100644 --- a/src/glsl/glsl_types.cpp +++ b/src/glsl/glsl_types.cpp @@ -22,19 +22,17 @@ */ #include -#include -#include "main/core.h" /* for Elements */ -#include "glsl_symbol_table.h" +#include "main/core.h" /* for Elements, MAX2 */ #include "glsl_parser_extras.h" #include "glsl_types.h" -#include "builtin_types.h" -extern "C" { #include "program/hash_table.h" -} + +mtx_t glsl_type::mutex = _MTX_INITIALIZER_NP; hash_table *glsl_type::array_types = NULL; hash_table *glsl_type::record_types = NULL; hash_table *glsl_type::interface_types = NULL; +hash_table *glsl_type::function_types = NULL; void *glsl_type::mem_ctx = NULL; void @@ -56,27 +54,45 @@ glsl_type::glsl_type(GLenum gl_type, vector_elements(vector_elements), matrix_columns(matrix_columns), length(0) { + mtx_lock(&glsl_type::mutex); + init_ralloc_type_ctx(); + assert(name != NULL); this->name = ralloc_strdup(this->mem_ctx, name); + + mtx_unlock(&glsl_type::mutex); + /* Neither dimension is zero or both dimensions are zero. */ assert((vector_elements == 0) == (matrix_columns == 0)); memset(& fields, 0, sizeof(fields)); } -glsl_type::glsl_type(GLenum gl_type, +glsl_type::glsl_type(GLenum gl_type, glsl_base_type base_type, enum glsl_sampler_dim dim, bool shadow, bool array, unsigned type, const char *name) : gl_type(gl_type), - base_type(GLSL_TYPE_SAMPLER), + base_type(base_type), sampler_dimensionality(dim), sampler_shadow(shadow), sampler_array(array), sampler_type(type), interface_packing(0), - vector_elements(0), matrix_columns(0), length(0) { + mtx_lock(&glsl_type::mutex); + init_ralloc_type_ctx(); + assert(name != NULL); this->name = ralloc_strdup(this->mem_ctx, name); + + mtx_unlock(&glsl_type::mutex); + memset(& fields, 0, sizeof(fields)); + + if (base_type == GLSL_TYPE_SAMPLER) { + /* Samplers take no storage whatsoever. */ + matrix_columns = vector_elements = 0; + } else { + matrix_columns = vector_elements = 1; + } } glsl_type::glsl_type(const glsl_struct_field *fields, unsigned num_fields, @@ -90,16 +106,26 @@ glsl_type::glsl_type(const glsl_struct_field *fields, unsigned num_fields, { unsigned int i; + mtx_lock(&glsl_type::mutex); + init_ralloc_type_ctx(); + assert(name != NULL); this->name = ralloc_strdup(this->mem_ctx, name); this->fields.structure = ralloc_array(this->mem_ctx, glsl_struct_field, length); + for (i = 0; i < length; i++) { this->fields.structure[i].type = fields[i].type; this->fields.structure[i].name = ralloc_strdup(this->fields.structure, fields[i].name); - this->fields.structure[i].row_major = fields[i].row_major; + this->fields.structure[i].location = fields[i].location; + this->fields.structure[i].interpolation = fields[i].interpolation; + this->fields.structure[i].centroid = fields[i].centroid; + this->fields.structure[i].sample = fields[i].sample; + this->fields.structure[i].matrix_layout = fields[i].matrix_layout; } + + mtx_unlock(&glsl_type::mutex); } glsl_type::glsl_type(const glsl_struct_field *fields, unsigned num_fields, @@ -113,7 +139,10 @@ glsl_type::glsl_type(const glsl_struct_field *fields, unsigned num_fields, { unsigned int i; + mtx_lock(&glsl_type::mutex); + init_ralloc_type_ctx(); + assert(name != NULL); this->name = ralloc_strdup(this->mem_ctx, name); this->fields.structure = ralloc_array(this->mem_ctx, glsl_struct_field, length); @@ -121,27 +150,50 @@ glsl_type::glsl_type(const glsl_struct_field *fields, unsigned num_fields, this->fields.structure[i].type = fields[i].type; this->fields.structure[i].name = ralloc_strdup(this->fields.structure, fields[i].name); - this->fields.structure[i].row_major = fields[i].row_major; + this->fields.structure[i].location = fields[i].location; + this->fields.structure[i].interpolation = fields[i].interpolation; + this->fields.structure[i].centroid = fields[i].centroid; + this->fields.structure[i].sample = fields[i].sample; + this->fields.structure[i].matrix_layout = fields[i].matrix_layout; } + + mtx_unlock(&glsl_type::mutex); } -static void -add_types_to_symbol_table(glsl_symbol_table *symtab, - const struct glsl_type *types, - unsigned num_types, bool warn, - bool skip_1d) +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), + sampler_dimensionality(0), sampler_shadow(0), sampler_array(0), + sampler_type(0), interface_packing(0), + vector_elements(0), matrix_columns(0), + length(num_params) { - (void) warn; + unsigned int i; + + mtx_lock(&glsl_type::mutex); + + init_ralloc_type_ctx(); - for (unsigned i = 0; i < num_types; i++) { - if (skip_1d && types[i].base_type == GLSL_TYPE_SAMPLER - && types[i].sampler_dimensionality == GLSL_SAMPLER_DIM_1D) - continue; + this->fields.parameters = rzalloc_array(this->mem_ctx, + glsl_function_param, num_params + 1); - symtab->add_type(types[i].name, & types[i]); + /* 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; } + + mtx_unlock(&glsl_type::mutex); } + bool glsl_type::contains_sampler() const { @@ -175,6 +227,41 @@ glsl_type::contains_integer() const } } +bool +glsl_type::contains_double() const +{ + if (this->is_array()) { + return this->fields.array->contains_double(); + } else if (this->is_record()) { + 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_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: + for (unsigned int i = 0; i < length; i++) { + if (fields.structure[i].type->contains_opaque()) + return true; + } + return false; + default: + return false; + } +} gl_texture_index glsl_type::sampler_index() const @@ -206,243 +293,22 @@ glsl_type::sampler_index() const } } -void -glsl_type::generate_100ES_types(glsl_symbol_table *symtab) -{ - bool skip_1d = false; - add_types_to_symbol_table(symtab, builtin_core_types, - Elements(builtin_core_types), - false, skip_1d); - add_types_to_symbol_table(symtab, builtin_structure_types, - Elements(builtin_structure_types), - false, skip_1d); - add_types_to_symbol_table(symtab, void_type, 1, false, skip_1d); -} - -void -glsl_type::generate_300ES_types(glsl_symbol_table *symtab) -{ - /* GLSL 3.00 ES types are the same as GLSL 1.30 types, except that 1D - * samplers are skipped, and samplerCubeShadow is added. - */ - bool add_deprecated = false; - bool skip_1d = true; - - generate_130_types(symtab, add_deprecated, skip_1d); - - add_types_to_symbol_table(symtab, &_samplerCubeShadow_type, 1, false, - skip_1d); -} - -void -glsl_type::generate_110_types(glsl_symbol_table *symtab, bool add_deprecated, - bool skip_1d) -{ - generate_100ES_types(symtab); - - add_types_to_symbol_table(symtab, builtin_110_types, - Elements(builtin_110_types), - false, skip_1d); - add_types_to_symbol_table(symtab, &_sampler3D_type, 1, false, skip_1d); - if (add_deprecated) { - add_types_to_symbol_table(symtab, builtin_110_deprecated_structure_types, - Elements(builtin_110_deprecated_structure_types), - false, skip_1d); - } -} - - -void -glsl_type::generate_120_types(glsl_symbol_table *symtab, bool add_deprecated, - bool skip_1d) -{ - generate_110_types(symtab, add_deprecated, skip_1d); - - add_types_to_symbol_table(symtab, builtin_120_types, - Elements(builtin_120_types), false, skip_1d); -} - - -void -glsl_type::generate_130_types(glsl_symbol_table *symtab, bool add_deprecated, - bool skip_1d) -{ - generate_120_types(symtab, add_deprecated, skip_1d); - - add_types_to_symbol_table(symtab, builtin_130_types, - Elements(builtin_130_types), false, skip_1d); - generate_EXT_texture_array_types(symtab, false); -} - - -void -glsl_type::generate_140_types(glsl_symbol_table *symtab) -{ - bool skip_1d = false; - - generate_130_types(symtab, false, skip_1d); - - add_types_to_symbol_table(symtab, builtin_140_types, - Elements(builtin_140_types), false, skip_1d); - - add_types_to_symbol_table(symtab, builtin_EXT_texture_buffer_object_types, - Elements(builtin_EXT_texture_buffer_object_types), - false, skip_1d); -} - - -void -glsl_type::generate_150_types(glsl_symbol_table *symtab) -{ - generate_140_types(symtab); - generate_ARB_texture_multisample_types(symtab, false); -} - - -void -glsl_type::generate_ARB_texture_rectangle_types(glsl_symbol_table *symtab, - bool warn) -{ - bool skip_1d = false; - - add_types_to_symbol_table(symtab, builtin_ARB_texture_rectangle_types, - Elements(builtin_ARB_texture_rectangle_types), - warn, skip_1d); -} - - -void -glsl_type::generate_EXT_texture_array_types(glsl_symbol_table *symtab, - bool warn) -{ - bool skip_1d = false; - - add_types_to_symbol_table(symtab, builtin_EXT_texture_array_types, - Elements(builtin_EXT_texture_array_types), - warn, skip_1d); -} - - -void -glsl_type::generate_OES_texture_3D_types(glsl_symbol_table *symtab, bool warn) -{ - bool skip_1d = false; - - add_types_to_symbol_table(symtab, &_sampler3D_type, 1, warn, skip_1d); -} - - -void -glsl_type::generate_OES_EGL_image_external_types(glsl_symbol_table *symtab, - bool warn) -{ - bool skip_1d = false; - - add_types_to_symbol_table(symtab, builtin_OES_EGL_image_external_types, - Elements(builtin_OES_EGL_image_external_types), - warn, skip_1d); -} - -void -glsl_type::generate_ARB_texture_cube_map_array_types(glsl_symbol_table *symtab, - bool warn) -{ - bool skip_1d = false; - - add_types_to_symbol_table(symtab, builtin_ARB_texture_cube_map_array_types, - Elements(builtin_ARB_texture_cube_map_array_types), - warn, skip_1d); -} - -void -glsl_type::generate_ARB_texture_multisample_types(glsl_symbol_table *symtab, - bool warn) -{ - bool skip_1d = false; - add_types_to_symbol_table(symtab, builtin_ARB_texture_multisample_types, - Elements(builtin_ARB_texture_multisample_types), - warn, skip_1d); -} - -void -_mesa_glsl_initialize_types(struct _mesa_glsl_parse_state *state) +bool +glsl_type::contains_image() const { - if (state->es_shader) { - switch (state->language_version) { - case 100: - assert(state->es_shader); - glsl_type::generate_100ES_types(state->symbols); - break; - case 300: - glsl_type::generate_300ES_types(state->symbols); - break; - default: - assert(!"Unexpected language version"); - break; + if (this->is_array()) { + return this->fields.array->contains_image(); + } else if (this->is_record()) { + for (unsigned int i = 0; i < this->length; i++) { + if (this->fields.structure[i].type->contains_image()) + return true; } + return false; } else { - bool skip_1d = false; - switch (state->language_version) { - case 110: - glsl_type::generate_110_types(state->symbols, true, skip_1d); - break; - case 120: - glsl_type::generate_120_types(state->symbols, true, skip_1d); - break; - case 130: - glsl_type::generate_130_types(state->symbols, true, skip_1d); - break; - case 140: - glsl_type::generate_140_types(state->symbols); - break; - case 150: - glsl_type::generate_150_types(state->symbols); - break; - default: - assert(!"Unexpected language version"); - break; - } - } - - if (state->ARB_texture_rectangle_enable || - state->is_version(140, 0)) { - glsl_type::generate_ARB_texture_rectangle_types(state->symbols, - state->ARB_texture_rectangle_warn); - } - if (state->OES_texture_3D_enable - && state->is_version(0, 100)) { - glsl_type::generate_OES_texture_3D_types(state->symbols, - state->OES_texture_3D_warn); - } - - if (state->EXT_texture_array_enable - && !state->is_version(130, 0)) { - // These are already included in 130; don't create twice. - glsl_type::generate_EXT_texture_array_types(state->symbols, - state->EXT_texture_array_warn); - } - - /* We cannot check for language_version == 100 here because we need the - * types to support fixed-function program generation. But this is fine - * since the extension is never enabled for OpenGL contexts. - */ - if (state->OES_EGL_image_external_enable) { - glsl_type::generate_OES_EGL_image_external_types(state->symbols, - state->OES_EGL_image_external_warn); - } - - if (state->ARB_texture_cube_map_array_enable) { - glsl_type::generate_ARB_texture_cube_map_array_types(state->symbols, - state->ARB_texture_cube_map_array_warn); - } - - if (state->ARB_texture_multisample_enable) { - glsl_type::generate_ARB_texture_multisample_types(state->symbols, - state->ARB_texture_multisample_warn); + return this->is_image(); } } - const glsl_type *glsl_type::get_base_type() const { switch (base_type) { @@ -452,6 +318,8 @@ const glsl_type *glsl_type::get_base_type() const return int_type; case GLSL_TYPE_FLOAT: return float_type; + case GLSL_TYPE_DOUBLE: + return double_type; case GLSL_TYPE_BOOL: return bool_type; default: @@ -476,6 +344,10 @@ const glsl_type *glsl_type::get_scalar_type() const return int_type; case GLSL_TYPE_FLOAT: return float_type; + case GLSL_TYPE_DOUBLE: + return double_type; + case GLSL_TYPE_BOOL: + return bool_type; default: /* Handle everything else */ return type; @@ -486,6 +358,8 @@ const glsl_type *glsl_type::get_scalar_type() const void _mesa_glsl_release_types(void) { + mtx_lock(&glsl_type::mutex); + if (glsl_type::array_types != NULL) { hash_table_dtor(glsl_type::array_types); glsl_type::array_types = NULL; @@ -495,6 +369,8 @@ _mesa_glsl_release_types(void) hash_table_dtor(glsl_type::record_types); glsl_type::record_types = NULL; } + + mtx_unlock(&glsl_type::mutex); } @@ -503,7 +379,7 @@ glsl_type::glsl_type(const glsl_type *array, unsigned length) : sampler_dimensionality(0), sampler_shadow(0), sampler_array(0), sampler_type(0), interface_packing(0), vector_elements(0), matrix_columns(0), - name(NULL), length(length) + length(length), name(NULL) { this->fields.array = array; /* Inherit the gl type of the base. The GL type is used for @@ -517,17 +393,95 @@ glsl_type::glsl_type(const glsl_type *array, unsigned length) : * NUL. */ const unsigned name_length = strlen(array->name) + 10 + 3; + + mtx_lock(&glsl_type::mutex); char *const n = (char *) ralloc_size(this->mem_ctx, name_length); + mtx_unlock(&glsl_type::mutex); if (length == 0) snprintf(n, name_length, "%s[]", array->name); - else - snprintf(n, name_length, "%s[%u]", array->name, length); + 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) +{ + if (components == 0 || components > 4) + return error_type; + + static const glsl_type *const ts[] = { + float_type, vec2_type, vec3_type, vec4_type + }; + return ts[components - 1]; +} + +const glsl_type * +glsl_type::dvec(unsigned components) +{ + if (components == 0 || components > 4) + return error_type; + + static const glsl_type *const ts[] = { + double_type, dvec2_type, dvec3_type, dvec4_type + }; + return ts[components - 1]; +} + +const glsl_type * +glsl_type::ivec(unsigned components) +{ + if (components == 0 || components > 4) + return error_type; + + static const glsl_type *const ts[] = { + int_type, ivec2_type, ivec3_type, ivec4_type + }; + return ts[components - 1]; +} + + +const glsl_type * +glsl_type::uvec(unsigned components) +{ + if (components == 0 || components > 4) + return error_type; + + static const glsl_type *const ts[] = { + uint_type, uvec2_type, uvec3_type, uvec4_type + }; + return ts[components - 1]; +} + + +const glsl_type * +glsl_type::bvec(unsigned components) +{ + if (components == 0 || components > 4) + return error_type; + + static const glsl_type *const ts[] = { + bool_type, bvec2_type, bvec3_type, bvec4_type + }; + return ts[components - 1]; +} + + const glsl_type * glsl_type::get_instance(unsigned base_type, unsigned rows, unsigned columns) { @@ -542,18 +496,20 @@ glsl_type::get_instance(unsigned base_type, unsigned rows, unsigned columns) if (columns == 1) { switch (base_type) { case GLSL_TYPE_UINT: - return uint_type + (rows - 1); + return uvec(rows); case GLSL_TYPE_INT: - return int_type + (rows - 1); + return ivec(rows); case GLSL_TYPE_FLOAT: - return float_type + (rows - 1); + return vec(rows); + case GLSL_TYPE_DOUBLE: + return dvec(rows); case GLSL_TYPE_BOOL: - return bool_type + (rows - 1); + return bvec(rows); default: return error_type; } } else { - if ((base_type != GLSL_TYPE_FLOAT) || (rows == 1)) + if ((base_type != GLSL_TYPE_FLOAT && base_type != GLSL_TYPE_DOUBLE) || (rows == 1)) return error_type; /* GLSL matrix types are named mat{COLUMNS}x{ROWS}. Only the following @@ -567,17 +523,32 @@ glsl_type::get_instance(unsigned base_type, unsigned rows, unsigned columns) */ #define IDX(c,r) (((c-1)*3) + (r-1)) - 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; + if (base_type == 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; + } + } else { + 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; + } } } @@ -585,16 +556,121 @@ glsl_type::get_instance(unsigned base_type, unsigned rows, unsigned columns) return error_type; } - const glsl_type * -glsl_type::get_array_instance(const glsl_type *base, unsigned array_size) +glsl_type::get_sampler_instance(enum glsl_sampler_dim dim, + bool shadow, + bool array, + glsl_base_type type) { - - if (array_types == NULL) { - array_types = hash_table_ctor(64, hash_table_string_hash, - hash_table_string_compare); + 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_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_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; + } + 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) +{ /* 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 @@ -603,9 +679,19 @@ glsl_type::get_array_instance(const glsl_type *base, unsigned array_size) char key[128]; snprintf(key, sizeof(key), "%p[%u]", (void *) base, array_size); + mtx_lock(&glsl_type::mutex); + + if (array_types == NULL) { + array_types = hash_table_ctor(64, hash_table_string_hash, + hash_table_string_compare); + } + const glsl_type *t = (glsl_type *) hash_table_find(array_types, key); + if (t == NULL) { + mtx_unlock(&glsl_type::mutex); t = new glsl_type(base, array_size); + mtx_lock(&glsl_type::mutex); hash_table_insert(array_types, (void *) t, ralloc_strdup(mem_ctx, key)); } @@ -614,10 +700,62 @@ glsl_type::get_array_instance(const glsl_type *base, unsigned array_size) assert(t->length == array_size); assert(t->fields.array == base); + mtx_unlock(&glsl_type::mutex); + return t; } +bool +glsl_type::record_compare(const glsl_type *b) const +{ + if (this->length != b->length) + return false; + + if (this->interface_packing != b->interface_packing) + 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). + * + * Note that we cannot force type name check when comparing unnamed + * structure types, these have a unique name assigned during parsing. + */ + if (!this->is_anonymous() && !b->is_anonymous()) + 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 (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 (this->fields.structure[i].location + != b->fields.structure[i].location) + 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; + } + + return true; +} + + int glsl_type::record_key_compare(const void *a, const void *b) { @@ -630,45 +768,31 @@ glsl_type::record_key_compare(const void *a, const void *b) if (strcmp(key1->name, key2->name) != 0) return 1; - if (key1->length != key2->length) - return 1; - - if (key1->interface_packing != key2->interface_packing) - return 1; - - for (unsigned i = 0; i < key1->length; i++) { - if (key1->fields.structure[i].type != key2->fields.structure[i].type) - return 1; - if (strcmp(key1->fields.structure[i].name, - key2->fields.structure[i].name) != 0) - return 1; - if (key1->fields.structure[i].row_major - != key2->fields.structure[i].row_major) - return 1; - } - - return 0; + return !key1->record_compare(key2); } +/** + * 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; - char hash_key[128]; - unsigned size = 0; - - size = snprintf(hash_key, sizeof(hash_key), "%08x", key->length); + uintptr_t hash = key->length; + unsigned retval; for (unsigned i = 0; i < key->length; i++) { - if (size >= sizeof(hash_key)) - break; - - size += snprintf(& hash_key[size], sizeof(hash_key) - size, - "%p", (void *) key->fields.structure[i].type); + /* casting pointer to uintptr_t */ + hash = (hash * 13 ) + (uintptr_t) key->fields.structure[i].type; } - return hash_table_string_hash(& hash_key); + if (sizeof(hash) == 8) + retval = (hash & 0xffffffff) ^ ((uint64_t) hash >> 32); + else + retval = hash; + + return retval; } @@ -679,13 +803,17 @@ glsl_type::get_record_instance(const glsl_struct_field *fields, { const glsl_type key(fields, num_fields, name); + mtx_lock(&glsl_type::mutex); + if (record_types == NULL) { record_types = hash_table_ctor(64, record_key_hash, record_key_compare); } const glsl_type *t = (glsl_type *) hash_table_find(record_types, & key); if (t == NULL) { + mtx_unlock(&glsl_type::mutex); t = new glsl_type(fields, num_fields, name); + mtx_lock(&glsl_type::mutex); hash_table_insert(record_types, (void *) t, t); } @@ -694,6 +822,8 @@ glsl_type::get_record_instance(const glsl_struct_field *fields, assert(t->length == num_fields); assert(strcmp(t->name, name) == 0); + mtx_unlock(&glsl_type::mutex); + return t; } @@ -702,9 +832,11 @@ const glsl_type * glsl_type::get_interface_instance(const glsl_struct_field *fields, unsigned num_fields, enum glsl_interface_packing packing, - const char *name) + const char *block_name) { - const glsl_type key(fields, num_fields, packing, name); + const glsl_type key(fields, num_fields, packing, block_name); + + mtx_lock(&glsl_type::mutex); if (interface_types == NULL) { interface_types = hash_table_ctor(64, record_key_hash, record_key_compare); @@ -712,19 +844,156 @@ glsl_type::get_interface_instance(const glsl_struct_field *fields, const glsl_type *t = (glsl_type *) hash_table_find(interface_types, & key); if (t == NULL) { - t = new glsl_type(fields, num_fields, packing, name); + mtx_unlock(&glsl_type::mutex); + t = new glsl_type(fields, num_fields, packing, block_name); + mtx_lock(&glsl_type::mutex); hash_table_insert(interface_types, (void *) t, t); } assert(t->base_type == GLSL_TYPE_INTERFACE); assert(t->length == num_fields); - assert(strcmp(t->name, name) == 0); + assert(strcmp(t->name, block_name) == 0); + + mtx_unlock(&glsl_type::mutex); return t; } +static int +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 1; + + return memcmp(key1->fields.parameters, key2->fields.parameters, + (key1->length + 1) * sizeof(*key1->fields.parameters)); +} + + +static unsigned +function_key_hash(const void *a) +{ + const glsl_type *const key = (glsl_type *) a; + char hash_key[128]; + unsigned size = 0; + + size = snprintf(hash_key, sizeof(hash_key), "%08x", key->length); + + for (unsigned i = 0; i < key->length; i++) { + if (size >= sizeof(hash_key)) + break; + + size += snprintf(& hash_key[size], sizeof(hash_key) - size, + "%p", (void *) key->fields.structure[i].type); + } + + return hash_table_string_hash(& hash_key); +} + +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::mutex); + + if (function_types == NULL) { + function_types = hash_table_ctor(64, function_key_hash, + function_key_compare); + } + + const glsl_type *t = (glsl_type *) hash_table_find(function_types, &key); + if (t == NULL) { + mtx_unlock(&glsl_type::mutex); + t = new glsl_type(return_type, params, num_params); + mtx_lock(&glsl_type::mutex); + + hash_table_insert(function_types, (void *) t, t); + } + + assert(t->base_type == GLSL_TYPE_FUNCTION); + assert(t->length == num_params); + + mtx_unlock(&glsl_type::mutex); + + return t; +} + + +const glsl_type * +glsl_type::get_mul_type(const glsl_type *type_a, const glsl_type *type_b) +{ + if (type_a == type_b) { + return type_a; + } else 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->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 { @@ -767,6 +1036,9 @@ glsl_type::component_slots() const case GLSL_TYPE_BOOL: return this->components(); + case GLSL_TYPE_DOUBLE: + return 2 * this->components(); + case GLSL_TYPE_STRUCT: case GLSL_TYPE_INTERFACE: { unsigned size = 0; @@ -780,7 +1052,12 @@ glsl_type::component_slots() const case GLSL_TYPE_ARRAY: return this->length * this->fields.array->component_slots(); + case GLSL_TYPE_IMAGE: + return 1; + + case GLSL_TYPE_FUNCTION: case GLSL_TYPE_SAMPLER: + case GLSL_TYPE_ATOMIC_UINT: case GLSL_TYPE_VOID: case GLSL_TYPE_ERROR: break; @@ -789,8 +1066,36 @@ glsl_type::component_slots() const return 0; } +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_DOUBLE: + case GLSL_TYPE_BOOL: + case GLSL_TYPE_SAMPLER: + case GLSL_TYPE_IMAGE: + 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; + } +} + bool -glsl_type::can_implicitly_convert_to(const glsl_type *desired) const +glsl_type::can_implicitly_convert_to(const glsl_type *desired, + _mesa_glsl_parse_state *state) const { if (this == desired) return true; @@ -799,15 +1104,42 @@ glsl_type::can_implicitly_convert_to(const glsl_type *desired) const 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. */ - return desired->is_float() - && this->is_integer() - && this->vector_elements == desired->vector_elements; + if (desired->is_float() && this->is_integer()) + return true; + + /* With GLSL 4.0 / ARB_gpu_shader5, 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->is_version(400, 0) || state->ARB_gpu_shader5_enable) && + 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()) + return true; + } + + return false; } unsigned glsl_type::std140_base_alignment(bool row_major) const { + unsigned N = is_double() ? 8 : 4; + /* (1) If the member is a scalar consuming basic machine units, the * base alignment is . * @@ -821,12 +1153,12 @@ glsl_type::std140_base_alignment(bool row_major) const if (this->is_scalar() || this->is_vector()) { switch (this->vector_elements) { case 1: - return 4; + return N; case 2: - return 8; + return 2 * N; case 3: case 4: - return 16; + return 4 * N; } } @@ -875,10 +1207,10 @@ glsl_type::std140_base_alignment(bool row_major) const int r = this->vector_elements; if (row_major) { - vec_type = get_instance(GLSL_TYPE_FLOAT, c, 1); + vec_type = get_instance(base_type, c, 1); array_type = glsl_type::get_array_instance(vec_type, r); } else { - vec_type = get_instance(GLSL_TYPE_FLOAT, r, 1); + vec_type = get_instance(base_type, r, 1); array_type = glsl_type::get_array_instance(vec_type, c); } @@ -900,9 +1232,18 @@ glsl_type::std140_base_alignment(bool row_major) const if (this->is_record()) { 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(row_major)); + field_type->std140_base_alignment(field_row_major)); } return base_alignment; } @@ -914,6 +1255,8 @@ glsl_type::std140_base_alignment(bool row_major) const unsigned glsl_type::std140_size(bool row_major) const { + unsigned N = is_double() ? 8 : 4; + /* (1) If the member is a scalar consuming basic machine units, the * base alignment is . * @@ -925,7 +1268,7 @@ glsl_type::std140_size(bool row_major) const * basic machine units, the base alignment is 4. */ if (this->is_scalar() || this->is_vector()) { - return this->vector_elements * 4; + return this->vector_elements * N; } /* (5) If the member is a column-major matrix with columns and @@ -946,8 +1289,7 @@ glsl_type::std140_size(bool row_major) const * and rows, the matrix is stored identically to a row of * * row vectors with components each, according to rule (4). */ - if (this->is_matrix() || (this->is_array() && - this->fields.array->is_matrix())) { + if (this->without_array()->is_matrix()) { const struct glsl_type *element_type; const struct glsl_type *vec_type; unsigned int array_len; @@ -961,11 +1303,12 @@ glsl_type::std140_size(bool row_major) const } if (row_major) { - vec_type = get_instance(GLSL_TYPE_FLOAT, - element_type->matrix_columns, 1); + vec_type = get_instance(element_type->base_type, + element_type->matrix_columns, 1); + array_len *= element_type->vector_elements; } else { - vec_type = get_instance(GLSL_TYPE_FLOAT, + vec_type = get_instance(element_type->base_type, element_type->vector_elements, 1); array_len *= element_type->matrix_columns; } @@ -1009,17 +1352,129 @@ glsl_type::std140_size(bool row_major) const */ if (this->is_record()) { 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(row_major); + unsigned align = field_type->std140_base_alignment(field_row_major); size = glsl_align(size, align); - size += field_type->std140_size(row_major); + size += field_type->std140_size(field_row_major); + + max_align = MAX2(align, max_align); + + if (field_type->is_record() && (i + 1 < this->length)) + size = glsl_align(size, 16); } - size = glsl_align(size, - this->fields.structure[0].type->std140_base_alignment(row_major)); + size = glsl_align(size, MAX2(max_align, 16)); return size; } assert(!"not reached"); return -1; } + + +unsigned +glsl_type::count_attribute_slots() 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. + */ + switch (this->base_type) { + case GLSL_TYPE_UINT: + case GLSL_TYPE_INT: + case GLSL_TYPE_FLOAT: + case GLSL_TYPE_BOOL: + case GLSL_TYPE_DOUBLE: + return this->matrix_columns; + + 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->count_attribute_slots(); + + return size; + } + + case GLSL_TYPE_ARRAY: + return this->length * this->fields.array->count_attribute_slots(); + + case GLSL_TYPE_FUNCTION: + case GLSL_TYPE_SAMPLER: + case GLSL_TYPE_IMAGE: + case GLSL_TYPE_ATOMIC_UINT: + case GLSL_TYPE_VOID: + case GLSL_TYPE_ERROR: + break; + } + + assert(!"Unexpected type in count_attribute_slots()"); + + return 0; +} + +int +glsl_type::coordinate_components() const +{ + int size; + + switch (sampler_dimensionality) { + case GLSL_SAMPLER_DIM_1D: + case GLSL_SAMPLER_DIM_BUF: + size = 1; + break; + case GLSL_SAMPLER_DIM_2D: + case GLSL_SAMPLER_DIM_RECT: + case GLSL_SAMPLER_DIM_MS: + case GLSL_SAMPLER_DIM_EXTERNAL: + size = 2; + break; + case GLSL_SAMPLER_DIM_3D: + case GLSL_SAMPLER_DIM_CUBE: + size = 3; + break; + default: + assert(!"Should not get here."); + size = 1; + break; + } + + /* 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 && + !(base_type == GLSL_TYPE_IMAGE && + sampler_dimensionality == GLSL_SAMPLER_DIM_CUBE)) + size += 1; + + return size; +}