diff options
Diffstat (limited to 'src/mesa/main/shader_query.cpp')
-rw-r--r-- | src/mesa/main/shader_query.cpp | 385 |
1 files changed, 302 insertions, 83 deletions
diff --git a/src/mesa/main/shader_query.cpp b/src/mesa/main/shader_query.cpp index 00f9d423670..aec39fb145c 100644 --- a/src/mesa/main/shader_query.cpp +++ b/src/mesa/main/shader_query.cpp @@ -35,9 +35,11 @@ #include "main/uniforms.h" #include "compiler/glsl/glsl_symbol_table.h" #include "compiler/glsl/ir.h" -#include "compiler/glsl/program.h" +#include "compiler/glsl/linker_util.h" #include "compiler/glsl/string_to_uint_map.h" #include "util/mesa-sha1.h" +#include "c99_alloca.h" +#include "api_exec_decl.h" static GLint program_resource_location(struct gl_program_resource *res, @@ -62,8 +64,11 @@ DECL_RESOURCE_FUNC(XFB, gl_transform_feedback_buffer); DECL_RESOURCE_FUNC(SUB, gl_subroutine_function); static GLenum -mediump_to_highp_type(GLenum type) +mediump_to_highp_type(struct gl_shader_program *shProg, GLenum type) { + if (!shProg->IsES) + return type; + switch (type) { case GL_FLOAT16_NV: return GL_FLOAT; @@ -195,7 +200,7 @@ _mesa_GetActiveAttrib(GLuint program, GLuint desired_index, const gl_shader_variable *const var = RESOURCE_VAR(res); - const char *var_name = var->name; + const char *var_name = var->name.string; _mesa_copy_string(name, maxLength, length, var_name); @@ -286,8 +291,7 @@ _mesa_longest_attribute_name_length(struct gl_shader_program *shProg) * returned. If no active attributes exist, zero is returned. If * no name reflection information is available, one is returned." */ - const size_t length = RESOURCE_VAR(res)->name != NULL ? - strlen(RESOURCE_VAR(res)->name) : 0; + const size_t length = RESOURCE_VAR(res)->name.length; if (length >= longest) longest = length + 1; @@ -460,35 +464,113 @@ _mesa_program_resource_name(struct gl_program_resource *res) switch (res->Type) { case GL_UNIFORM_BLOCK: case GL_SHADER_STORAGE_BLOCK: - return RESOURCE_UBO(res)->Name; + return RESOURCE_UBO(res)->name.string; case GL_TRANSFORM_FEEDBACK_VARYING: - return RESOURCE_XFV(res)->Name; + return RESOURCE_XFV(res)->name.string; case GL_PROGRAM_INPUT: case GL_PROGRAM_OUTPUT: - return RESOURCE_VAR(res)->name; + return RESOURCE_VAR(res)->name.string; case GL_UNIFORM: case GL_BUFFER_VARIABLE: - return RESOURCE_UNI(res)->name; + return RESOURCE_UNI(res)->name.string; case GL_VERTEX_SUBROUTINE_UNIFORM: case GL_GEOMETRY_SUBROUTINE_UNIFORM: case GL_FRAGMENT_SUBROUTINE_UNIFORM: case GL_COMPUTE_SUBROUTINE_UNIFORM: case GL_TESS_CONTROL_SUBROUTINE_UNIFORM: case GL_TESS_EVALUATION_SUBROUTINE_UNIFORM: - return RESOURCE_UNI(res)->name + MESA_SUBROUTINE_PREFIX_LEN; + return RESOURCE_UNI(res)->name.string + MESA_SUBROUTINE_PREFIX_LEN; case GL_VERTEX_SUBROUTINE: case GL_GEOMETRY_SUBROUTINE: case GL_FRAGMENT_SUBROUTINE: case GL_COMPUTE_SUBROUTINE: case GL_TESS_CONTROL_SUBROUTINE: case GL_TESS_EVALUATION_SUBROUTINE: - return RESOURCE_SUB(res)->name; + return RESOURCE_SUB(res)->name.string; default: break; } return NULL; } +int +_mesa_program_resource_name_length(struct gl_program_resource *res) +{ + switch (res->Type) { + case GL_UNIFORM_BLOCK: + case GL_SHADER_STORAGE_BLOCK: + return RESOURCE_UBO(res)->name.length; + case GL_TRANSFORM_FEEDBACK_VARYING: + return RESOURCE_XFV(res)->name.length; + case GL_PROGRAM_INPUT: + case GL_PROGRAM_OUTPUT: + return RESOURCE_VAR(res)->name.length; + case GL_UNIFORM: + case GL_BUFFER_VARIABLE: + return RESOURCE_UNI(res)->name.length; + case GL_VERTEX_SUBROUTINE_UNIFORM: + case GL_GEOMETRY_SUBROUTINE_UNIFORM: + case GL_FRAGMENT_SUBROUTINE_UNIFORM: + case GL_COMPUTE_SUBROUTINE_UNIFORM: + case GL_TESS_CONTROL_SUBROUTINE_UNIFORM: + case GL_TESS_EVALUATION_SUBROUTINE_UNIFORM: + return RESOURCE_UNI(res)->name.length - MESA_SUBROUTINE_PREFIX_LEN; + case GL_VERTEX_SUBROUTINE: + case GL_GEOMETRY_SUBROUTINE: + case GL_FRAGMENT_SUBROUTINE: + case GL_COMPUTE_SUBROUTINE: + case GL_TESS_CONTROL_SUBROUTINE: + case GL_TESS_EVALUATION_SUBROUTINE: + return RESOURCE_SUB(res)->name.length; + default: + break; + } + return 0; +} + +bool +_mesa_program_get_resource_name(struct gl_program_resource *res, + struct gl_resource_name *out) +{ + switch (res->Type) { + case GL_UNIFORM_BLOCK: + case GL_SHADER_STORAGE_BLOCK: + *out = RESOURCE_UBO(res)->name; + return out->string != NULL; + case GL_TRANSFORM_FEEDBACK_VARYING: + *out = RESOURCE_XFV(res)->name; + return out->string != NULL; + case GL_PROGRAM_INPUT: + case GL_PROGRAM_OUTPUT: + *out = RESOURCE_VAR(res)->name; + return out->string != NULL; + case GL_UNIFORM: + case GL_BUFFER_VARIABLE: + *out = RESOURCE_UNI(res)->name; + return out->string != NULL; + case GL_VERTEX_SUBROUTINE_UNIFORM: + case GL_GEOMETRY_SUBROUTINE_UNIFORM: + case GL_FRAGMENT_SUBROUTINE_UNIFORM: + case GL_COMPUTE_SUBROUTINE_UNIFORM: + case GL_TESS_CONTROL_SUBROUTINE_UNIFORM: + case GL_TESS_EVALUATION_SUBROUTINE_UNIFORM: + *out = RESOURCE_UNI(res)->name; + out->string += MESA_SUBROUTINE_PREFIX_LEN; + out->length -= MESA_SUBROUTINE_PREFIX_LEN; + assert(out->string); /* always non-NULL */ + return true; + case GL_VERTEX_SUBROUTINE: + case GL_GEOMETRY_SUBROUTINE: + case GL_FRAGMENT_SUBROUTINE: + case GL_COMPUTE_SUBROUTINE: + case GL_TESS_CONTROL_SUBROUTINE: + case GL_TESS_EVALUATION_SUBROUTINE: + *out = RESOURCE_SUB(res)->name; + return out->string != NULL; + default: + return false; + } +} unsigned _mesa_program_resource_array_size(struct gl_program_resource *res) @@ -535,12 +617,12 @@ _mesa_program_resource_array_size(struct gl_program_resource *res) * Checks if array subscript is valid and if so sets array_index. */ static bool -valid_array_index(const GLchar *name, unsigned *array_index) +valid_array_index(const GLchar *name, int len, unsigned *array_index) { long idx = 0; const GLchar *out_base_name_end; - idx = parse_program_resource_name(name, strlen(name), &out_base_name_end); + idx = link_util_parse_program_resource_name(name, len, &out_base_name_end); if (idx < 0) return false; @@ -550,25 +632,24 @@ valid_array_index(const GLchar *name, unsigned *array_index) return true; } -static uint32_t -compute_resource_key(GLenum programInterface, const char *name, size_t len) -{ - return _mesa_hash_data_with_seed(name, len, programInterface + len); -} - static struct gl_program_resource * search_resource_hash(struct gl_shader_program *shProg, - GLenum programInterface, const char *name, + GLenum programInterface, const char *name, int len, unsigned *array_index) { + unsigned type = GET_PROGRAM_RESOURCE_TYPE_FROM_GLENUM(programInterface); + assert(type < ARRAY_SIZE(shProg->data->ProgramResourceHash)); + + if (!shProg->data->ProgramResourceHash[type]) + return NULL; + const char *base_name_end; - size_t len = strlen(name); - long index = parse_program_resource_name(name, len, &base_name_end); + long index = link_util_parse_program_resource_name(name, len, &base_name_end); char *name_copy; /* If dealing with array, we need to get the basename. */ if (index >= 0) { - name_copy = (char *) malloc(base_name_end - name + 1); + name_copy = (char *) alloca(base_name_end - name + 1); memcpy(name_copy, name, base_name_end - name); name_copy[base_name_end - name] = '\0'; len = base_name_end - name; @@ -576,17 +657,17 @@ search_resource_hash(struct gl_shader_program *shProg, name_copy = (char*) name; } - uint32_t key = compute_resource_key(programInterface, name_copy, len); - struct gl_program_resource *res = (struct gl_program_resource *) - _mesa_hash_table_u64_search(shProg->data->ProgramResourceHash, key); - - if (name_copy != name) - free(name_copy); + uint32_t hash = _mesa_hash_string_with_length(name_copy, len); + struct hash_entry *entry = + _mesa_hash_table_search_pre_hashed(shProg->data->ProgramResourceHash[type], + hash, name_copy); + if (!entry) + return NULL; - if (res && array_index) + if (array_index) *array_index = index >= 0 ? index : 0; - return res; + return (struct gl_program_resource *)entry->data; } /* Find a program resource with specific name in given interface. @@ -596,14 +677,14 @@ _mesa_program_resource_find_name(struct gl_shader_program *shProg, GLenum programInterface, const char *name, unsigned *array_index) { - struct gl_program_resource *res = NULL; - if (name == NULL) return NULL; + int len = strlen(name); + /* If we have a name, try the ProgramResourceHash first. */ - if (shProg->data->ProgramResourceHash) - res = search_resource_hash(shProg, programInterface, name, array_index); + struct gl_program_resource *res = + search_resource_hash(shProg, programInterface, name, len, array_index); if (res) return res; @@ -613,18 +694,14 @@ _mesa_program_resource_find_name(struct gl_shader_program *shProg, if (res->Type != programInterface) continue; - /* Resource basename. */ - const char *rname = _mesa_program_resource_name(res); + struct gl_resource_name rname; /* Since ARB_gl_spirv lack of name reflections is a possibility */ - if (rname == NULL) + if (!_mesa_program_get_resource_name(res, &rname)) continue; - unsigned baselen = strlen(rname); - unsigned baselen_without_array_index = baselen; - const char *rname_last_square_bracket = strrchr(rname, '['); bool found = false; - bool rname_has_array_index_zero = false; + /* From ARB_program_interface_query spec: * * "uint GetProgramResourceIndex(uint program, enum programInterface, @@ -650,17 +727,15 @@ _mesa_program_resource_find_name(struct gl_shader_program *shProg, * array's index is zero and the resulting string length is the same * than the provided name's length. */ - if (rname_last_square_bracket) { - baselen_without_array_index -= strlen(rname_last_square_bracket); - rname_has_array_index_zero = - (strcmp(rname_last_square_bracket, "[0]") == 0) && - (baselen_without_array_index == strlen(name)); - } + int length_without_array_index = + rname.last_square_bracket >= 0 ? rname.last_square_bracket : rname.length; + bool rname_has_array_index_zero = rname.suffix_is_zero_square_bracketed && + rname.last_square_bracket == len; - if (strncmp(rname, name, baselen) == 0) + if (len >= rname.length && strncmp(rname.string, name, rname.length) == 0) found = true; else if (rname_has_array_index_zero && - strncmp(rname, name, baselen_without_array_index) == 0) + strncmp(rname.string, name, length_without_array_index) == 0) found = true; if (found) { @@ -669,9 +744,9 @@ _mesa_program_resource_find_name(struct gl_shader_program *shProg, case GL_SHADER_STORAGE_BLOCK: /* Basename match, check if array or struct. */ if (rname_has_array_index_zero || - name[baselen] == '\0' || - name[baselen] == '[' || - name[baselen] == '.') { + name[rname.length] == '\0' || + name[rname.length] == '[' || + name[rname.length] == '.') { return res; } break; @@ -690,16 +765,16 @@ _mesa_program_resource_find_name(struct gl_shader_program *shProg, case GL_COMPUTE_SUBROUTINE: case GL_TESS_CONTROL_SUBROUTINE: case GL_TESS_EVALUATION_SUBROUTINE: - if (name[baselen] == '.') { + if (name[rname.length] == '.') { return res; } FALLTHROUGH; case GL_PROGRAM_INPUT: case GL_PROGRAM_OUTPUT: - if (name[baselen] == '\0') { + if (name[rname.length] == '\0') { return res; - } else if (name[baselen] == '[' && - valid_array_index(name, array_index)) { + } else if (name[rname.length] == '[' && + valid_array_index(name, len, array_index)) { return res; } break; @@ -962,17 +1037,16 @@ add_index_to_name(struct gl_program_resource *res) * base name + 3 for '[0]' if resource is an array. */ extern unsigned -_mesa_program_resource_name_len(struct gl_program_resource *res) +_mesa_program_resource_name_length_array(struct gl_program_resource *res) { - const char* name = _mesa_program_resource_name(res); + int length = _mesa_program_resource_name_length(res); /* For shaders constructed from SPIR-V binaries, variables may not * have names associated with them. */ - if (!name) + if (!length) return 0; - unsigned length = strlen(name); if (_mesa_program_resource_array_size(res) && add_index_to_name(res)) length += 3; return length; @@ -1051,7 +1125,7 @@ program_resource_location(struct gl_program_resource *res, unsigned array_index) return -1; } return var->location + - (array_index * var->type->without_array()->matrix_columns); + (array_index * glsl_without_array(var->type)->matrix_columns); } case GL_PROGRAM_OUTPUT: if (RESOURCE_VAR(res)->location == -1) @@ -1073,7 +1147,7 @@ program_resource_location(struct gl_program_resource *res, unsigned array_index) * "A valid name cannot be a structure, an array of structures, or any * portion of a single vector or a matrix." */ - if (RESOURCE_UNI(res)->type->without_array()->is_struct()) + if (glsl_type_is_struct(glsl_without_array(RESOURCE_UNI(res)->type))) return -1; /* From the GL_ARB_uniform_buffer_object spec: @@ -1387,7 +1461,7 @@ _mesa_program_resource_prop(struct gl_shader_program *shProg, goto invalid_operation; default: /* Resource name length + terminator. */ - *val = _mesa_program_resource_name_len(res) + 1; + *val = _mesa_program_resource_name_length_array(res) + 1; } return 1; case GL_TYPE: @@ -1395,16 +1469,16 @@ _mesa_program_resource_prop(struct gl_shader_program *shProg, case GL_UNIFORM: case GL_BUFFER_VARIABLE: *val = RESOURCE_UNI(res)->type->gl_type; - *val = mediump_to_highp_type(*val); + *val = mediump_to_highp_type(shProg, *val); return 1; case GL_PROGRAM_INPUT: case GL_PROGRAM_OUTPUT: *val = RESOURCE_VAR(res)->type->gl_type; - *val = mediump_to_highp_type(*val); + *val = mediump_to_highp_type(shProg, *val); return 1; case GL_TRANSFORM_FEEDBACK_VARYING: *val = RESOURCE_XFV(res)->Type; - *val = mediump_to_highp_type(*val); + *val = mediump_to_highp_type(shProg, *val); return 1; default: goto invalid_operation; @@ -1668,6 +1742,135 @@ _mesa_get_program_resourceiv(struct gl_shader_program *shProg, *length = amount; } +extern void +_mesa_get_program_interfaceiv(struct gl_shader_program *shProg, + GLenum programInterface, GLenum pname, + GLint *params) +{ + GET_CURRENT_CONTEXT(ctx); + unsigned i; + + /* Validate pname against interface. */ + switch(pname) { + case GL_ACTIVE_RESOURCES: + for (i = 0, *params = 0; i < shProg->data->NumProgramResourceList; i++) + if (shProg->data->ProgramResourceList[i].Type == programInterface) + (*params)++; + break; + case GL_MAX_NAME_LENGTH: + if (programInterface == GL_ATOMIC_COUNTER_BUFFER || + programInterface == GL_TRANSFORM_FEEDBACK_BUFFER) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetProgramInterfaceiv(%s pname %s)", + _mesa_enum_to_string(programInterface), + _mesa_enum_to_string(pname)); + return; + } + /* Name length consists of base name, 3 additional chars '[0]' if + * resource is an array and finally 1 char for string terminator. + */ + for (i = 0, *params = 0; i < shProg->data->NumProgramResourceList; i++) { + if (shProg->data->ProgramResourceList[i].Type != programInterface) + continue; + unsigned len = + _mesa_program_resource_name_length_array(&shProg->data->ProgramResourceList[i]); + *params = MAX2((unsigned)*params, len + 1); + } + break; + case GL_MAX_NUM_ACTIVE_VARIABLES: + switch (programInterface) { + case GL_UNIFORM_BLOCK: + for (i = 0, *params = 0; i < shProg->data->NumProgramResourceList; i++) { + if (shProg->data->ProgramResourceList[i].Type == programInterface) { + struct gl_uniform_block *block = + (struct gl_uniform_block *) + shProg->data->ProgramResourceList[i].Data; + *params = MAX2((unsigned)*params, block->NumUniforms); + } + } + break; + case GL_SHADER_STORAGE_BLOCK: + for (i = 0, *params = 0; i < shProg->data->NumProgramResourceList; i++) { + if (shProg->data->ProgramResourceList[i].Type == programInterface) { + struct gl_uniform_block *block = + (struct gl_uniform_block *) + shProg->data->ProgramResourceList[i].Data; + GLint block_params = 0; + for (unsigned j = 0; j < block->NumUniforms; j++) { + struct gl_program_resource *uni = + _mesa_program_resource_find_active_variable( + shProg, + GL_BUFFER_VARIABLE, + block, + j); + if (!uni) + continue; + block_params++; + } + *params = MAX2(*params, block_params); + } + } + break; + case GL_ATOMIC_COUNTER_BUFFER: + for (i = 0, *params = 0; i < shProg->data->NumProgramResourceList; i++) { + if (shProg->data->ProgramResourceList[i].Type == programInterface) { + struct gl_active_atomic_buffer *buffer = + (struct gl_active_atomic_buffer *) + shProg->data->ProgramResourceList[i].Data; + *params = MAX2((unsigned)*params, buffer->NumUniforms); + } + } + break; + case GL_TRANSFORM_FEEDBACK_BUFFER: + for (i = 0, *params = 0; i < shProg->data->NumProgramResourceList; i++) { + if (shProg->data->ProgramResourceList[i].Type == programInterface) { + struct gl_transform_feedback_buffer *buffer = + (struct gl_transform_feedback_buffer *) + shProg->data->ProgramResourceList[i].Data; + *params = MAX2((unsigned)*params, buffer->NumVaryings); + } + } + break; + default: + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetProgramInterfaceiv(%s pname %s)", + _mesa_enum_to_string(programInterface), + _mesa_enum_to_string(pname)); + } + break; + case GL_MAX_NUM_COMPATIBLE_SUBROUTINES: + switch (programInterface) { + case GL_VERTEX_SUBROUTINE_UNIFORM: + case GL_FRAGMENT_SUBROUTINE_UNIFORM: + case GL_GEOMETRY_SUBROUTINE_UNIFORM: + case GL_COMPUTE_SUBROUTINE_UNIFORM: + case GL_TESS_CONTROL_SUBROUTINE_UNIFORM: + case GL_TESS_EVALUATION_SUBROUTINE_UNIFORM: { + for (i = 0, *params = 0; i < shProg->data->NumProgramResourceList; i++) { + if (shProg->data->ProgramResourceList[i].Type == programInterface) { + struct gl_uniform_storage *uni = + (struct gl_uniform_storage *) + shProg->data->ProgramResourceList[i].Data; + *params = MAX2((unsigned)*params, uni->num_compatible_subroutines); + } + } + break; + } + + default: + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetProgramInterfaceiv(%s pname %s)", + _mesa_enum_to_string(programInterface), + _mesa_enum_to_string(pname)); + } + break; + default: + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetProgramInterfaceiv(pname %s)", + _mesa_enum_to_string(pname)); + } +} + static bool validate_io(struct gl_program *producer, struct gl_program *consumer) { @@ -1721,7 +1924,7 @@ validate_io(struct gl_program *producer, struct gl_program *consumer) * * Built-in inputs or outputs do not affect interface matching. */ - if (is_gl_identifier(var->name)) + if (is_gl_identifier(var->name.string)) continue; outputs[num_outputs++] = var; @@ -1738,7 +1941,7 @@ validate_io(struct gl_program *producer, struct gl_program *consumer) gl_shader_variable const *const consumer_var = RESOURCE_VAR(res); gl_shader_variable const *producer_var = NULL; - if (is_gl_identifier(consumer_var->name)) + if (is_gl_identifier(consumer_var->name.string)) continue; /* Inputs with explicit locations match other outputs with explicit @@ -1760,7 +1963,7 @@ validate_io(struct gl_program *producer, struct gl_program *consumer) const gl_shader_variable *const var = outputs[j]; if (!var->explicit_location && - strcmp(consumer_var->name, var->name) == 0) { + strcmp(consumer_var->name.string, var->name.string) == 0) { producer_var = var; match_index = j; break; @@ -1813,10 +2016,10 @@ validate_io(struct gl_program *producer, struct gl_program *consumer) if (consumer_is_array_stage) { if (consumer_interface_type) { /* the interface is the array; the underlying types should match */ - if (consumer_interface_type->is_array() && !consumer_var->patch) + if (glsl_type_is_array(consumer_interface_type) && !consumer_var->patch) consumer_interface_type = consumer_interface_type->fields.array; } else { - if (consumer_type->is_array() && !consumer_var->patch) + if (glsl_type_is_array(consumer_type) && !consumer_var->patch) consumer_type = consumer_type->fields.array; } } @@ -1824,10 +2027,10 @@ validate_io(struct gl_program *producer, struct gl_program *consumer) if (producer_is_array_stage) { if (producer_interface_type) { /* the interface is the array; the underlying types should match */ - if (producer_interface_type->is_array() && !producer_var->patch) + if (glsl_type_is_array(producer_interface_type) && !producer_var->patch) producer_interface_type = producer_interface_type->fields.array; } else { - if (producer_type->is_array() && !producer_var->patch) + if (glsl_type_is_array(producer_type) && !producer_var->patch) producer_type = producer_type->fields.array; } } @@ -1935,21 +2138,37 @@ _mesa_validate_pipeline_io(struct gl_pipeline_object *pipeline) } extern "C" void +_mesa_program_resource_hash_destroy(struct gl_shader_program *shProg) +{ + for (unsigned i = 0; i < ARRAY_SIZE(shProg->data->ProgramResourceHash); i++) { + if (shProg->data->ProgramResourceHash[i]) { + _mesa_hash_table_destroy(shProg->data->ProgramResourceHash[i], NULL); + shProg->data->ProgramResourceHash[i] = NULL; + } + } +} + +extern "C" void _mesa_create_program_resource_hash(struct gl_shader_program *shProg) { /* Rebuild resource hash. */ - if (shProg->data->ProgramResourceHash) - _mesa_hash_table_u64_destroy(shProg->data->ProgramResourceHash); - - shProg->data->ProgramResourceHash = _mesa_hash_table_u64_create(shProg); + _mesa_program_resource_hash_destroy(shProg); struct gl_program_resource *res = shProg->data->ProgramResourceList; for (unsigned i = 0; i < shProg->data->NumProgramResourceList; i++, res++) { - const char *name = _mesa_program_resource_name(res); - if (name) { - uint32_t key = compute_resource_key(res->Type, name, strlen(name)); - _mesa_hash_table_u64_insert(shProg->data->ProgramResourceHash, key, - res); + struct gl_resource_name name; + if (_mesa_program_get_resource_name(res, &name)) { + unsigned type = GET_PROGRAM_RESOURCE_TYPE_FROM_GLENUM(res->Type); + assert(type < ARRAY_SIZE(shProg->data->ProgramResourceHash)); + + if (!shProg->data->ProgramResourceHash[type]) { + shProg->data->ProgramResourceHash[type] = + _mesa_hash_table_create(shProg, _mesa_hash_string, + _mesa_key_string_equal); + } + + _mesa_hash_table_insert(shProg->data->ProgramResourceHash[type], + name.string, res); } } } |