From e05225406617d45ec9800671edd447c064279c63 Mon Sep 17 00:00:00 2001 From: Timothy Arceri Date: Wed, 6 Aug 2025 11:46:47 +1000 Subject: [PATCH] glsl: make use of u_range_remap for uniform remapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This will allow ubo buffers to have arrays containing millions of elements without excessive memory use on a remap table. Before this change using the max sized array on radeonsi would result in 1.3GB of memory being used for a remap table in a single shader. There is also a small functional change here, previously if the shader used more than GL_MAX_UNIFORM_BLOCK_SIZE mesa would ignore and allow this as the original ARB_uniform_buffer_object spec stated: "If the amount of storage required for a uniform block exceeds this limit, a program may fail to link." However in OpenGL 4.3 the text was clarified and the "may" was removed so with this change we enforce the max limit. Closes: https://gitlab.freedesktop.org/mesa/mesa/-/issues/9953 Acked-by: Marek Olšák Part-of: --- src/compiler/glsl/gl_nir_link_uniforms.c | 57 +++----- src/compiler/glsl/gl_nir_linker.c | 138 +++++++++++++------ src/compiler/glsl/linker_util.cpp | 46 +++++-- src/compiler/glsl/linker_util.h | 3 +- src/compiler/glsl/serialize.cpp | 75 +++++++++- src/compiler/glsl/standalone_scaffolding.cpp | 8 +- src/mesa/main/shader_types.h | 2 +- src/mesa/main/shaderobj.c | 16 ++- src/mesa/main/uniform_query.cpp | 50 ++++--- 9 files changed, 263 insertions(+), 132 deletions(-) diff --git a/src/compiler/glsl/gl_nir_link_uniforms.c b/src/compiler/glsl/gl_nir_link_uniforms.c index fb417e4525b..9f5e8c12af7 100644 --- a/src/compiler/glsl/gl_nir_link_uniforms.c +++ b/src/compiler/glsl/gl_nir_link_uniforms.c @@ -27,6 +27,7 @@ #include "linker_util.h" #include "util/u_dynarray.h" #include "util/u_math.h" +#include "util/u_range_remap.h" #include "main/consts_exts.h" #include "main/shader_types.h" @@ -280,17 +281,12 @@ setup_uniform_remap_tables(const struct gl_constants *consts, * that we can keep track of unused uniforms with explicit locations. */ assert(!prog->data->spirv || - (prog->data->spirv && !prog->UniformRemapTable)); - if (!prog->UniformRemapTable) { - prog->UniformRemapTable = rzalloc_array(prog, - struct gl_uniform_storage *, - prog->NumUniformRemapTable); - } + (prog->data->spirv && list_is_empty(prog->UniformRemapTable))); union gl_constant_value *data = rzalloc_array(prog->data, union gl_constant_value, prog->data->NumUniformDataSlots); - if (!prog->UniformRemapTable || !data) { + if (!data) { linker_error(prog, "Out of memory during linking.\n"); return; } @@ -321,19 +317,17 @@ setup_uniform_remap_tables(const struct gl_constants *consts, unsigned num_slots = glsl_get_component_slots(uniform->type); uniform->storage = &data[data_pos]; + data_pos += num_slots * entries; - /* Set remap table entries point to correct gl_uniform_storage. */ - for (unsigned j = 0; j < entries; j++) { - unsigned element_loc = uniform->remap_location + j; - prog->UniformRemapTable[element_loc] = uniform; - - data_pos += num_slots; - } + /* Set remap table entry to the correct gl_uniform_storage. */ + util_range_insert_remap(uniform->remap_location, + uniform->remap_location + entries - 1, + prog->UniformRemapTable, uniform); } /* Reserve locations for rest of the uniforms. */ if (prog->data->spirv) - link_util_update_empty_uniform_locations(prog); + link_util_update_empty_uniform_locations(consts, prog); for (unsigned i = 0; i < prog->data->NumUniformStorage; i++) { struct gl_uniform_storage *uniform = &prog->data->UniformStorage[i]; @@ -365,35 +359,24 @@ setup_uniform_remap_tables(const struct gl_constants *consts, unsigned location = link_util_find_empty_block(prog, &prog->data->UniformStorage[i]); - if (location == -1) { - location = prog->NumUniformRemapTable; + linker_error(prog, "Unable to find empty block for %u entries", + MAX2(1, prog->data->UniformStorage[i].array_elements)); + } - /* resize remap table to fit new entries */ - prog->UniformRemapTable = - reralloc(prog, - prog->UniformRemapTable, - struct gl_uniform_storage *, - prog->NumUniformRemapTable + entries); - prog->NumUniformRemapTable += entries; + unsigned num_slots = glsl_get_component_slots(uniform->type); + if (uniform->block_index == -1) { + uniform->storage = &data[data_pos]; + data_pos += num_slots * entries; } /* set the base location in remap table for the uniform */ uniform->remap_location = location; - unsigned num_slots = glsl_get_component_slots(uniform->type); - - if (uniform->block_index == -1) - uniform->storage = &data[data_pos]; - - /* Set remap table entries point to correct gl_uniform_storage. */ - for (unsigned j = 0; j < entries; j++) { - unsigned element_loc = uniform->remap_location + j; - prog->UniformRemapTable[element_loc] = uniform; - - if (uniform->block_index == -1) - data_pos += num_slots; - } + /* Set remap table entry to the correct gl_uniform_storage. */ + util_range_insert_remap(uniform->remap_location, + uniform->remap_location + entries - 1, + prog->UniformRemapTable, uniform); } /* Verify that total amount of entries for explicit and implicit locations diff --git a/src/compiler/glsl/gl_nir_linker.c b/src/compiler/glsl/gl_nir_linker.c index 1526a05e3dd..d6e154ce37f 100644 --- a/src/compiler/glsl/gl_nir_linker.c +++ b/src/compiler/glsl/gl_nir_linker.c @@ -34,6 +34,7 @@ #include "main/context.h" #include "main/shaderobj.h" #include "util/glheader.h" +#include "util/u_range_remap.h" #include "util/perf/cpu_trace.h" #include "pipe/p_screen.h" @@ -2769,48 +2770,68 @@ link_intrastage_shaders(void *mem_ctx, * Initializes explicit location slots to INACTIVE_UNIFORM_EXPLICIT_LOCATION * for a variable, checks for overlaps between other uniforms using explicit * locations. + * If return_zero bool is true zero will be returned if the uniform was + * already processed for a different stage. */ static int reserve_explicit_locations(struct gl_shader_program *prog, - struct string_to_uint_map *map, nir_variable *var) + struct string_to_uint_map *map, + const struct glsl_type *type, + int location, char **var_name, + size_t name_length, bool return_zero) { - unsigned slots = glsl_type_uniform_locations(var->type); - unsigned max_loc = var->data.location + slots - 1; - unsigned return_value = slots; + if (glsl_type_is_struct_or_ifc(type) || + (glsl_type_is_array(type) && + (glsl_type_is_array(glsl_get_array_element(type)) || + glsl_type_is_struct_or_ifc(glsl_get_array_element(type))))) { - /* Resize remap table if locations do not fit in the current one. */ - if (max_loc + 1 > prog->NumUniformRemapTable) { - prog->UniformRemapTable = - reralloc(prog, prog->UniformRemapTable, - struct gl_uniform_storage *, - max_loc + 1); + unsigned length = glsl_get_length(type); + if (glsl_type_is_unsized_array(type)) + length = 1; - if (!prog->UniformRemapTable) { - linker_error(prog, "Out of memory during linking.\n"); - return -1; - } + int location_count = 0; + for (unsigned i = 0; i < length; i++) { + const struct glsl_type *field_type; + size_t new_length = name_length; - /* Initialize allocated space. */ - for (unsigned i = prog->NumUniformRemapTable; i < max_loc + 1; i++) - prog->UniformRemapTable[i] = NULL; + if (glsl_type_is_struct_or_ifc(type)) { + field_type = glsl_get_struct_field(type, i); - prog->NumUniformRemapTable = max_loc + 1; - } + /* Append '.field' to the current variable name. */ + if (var_name) { + ralloc_asprintf_rewrite_tail(var_name, &new_length, ".%s", + glsl_get_struct_elem_name(type, i)); + } + } else { + field_type = glsl_get_array_element(type); - for (unsigned i = 0; i < slots; i++) { - unsigned loc = var->data.location + i; - - /* Check if location is already used. */ - if (prog->UniformRemapTable[loc] == INACTIVE_UNIFORM_EXPLICIT_LOCATION) { - - /* Possibly same uniform from a different stage, this is ok. */ - unsigned hash_loc; - if (string_to_uint_map_get(map, &hash_loc, var->name) && - hash_loc == loc - i) { - return_value = 0; - continue; + /* Append the subscript to the current variable name */ + if (var_name) + ralloc_asprintf_rewrite_tail(var_name, &new_length, "[%u]", i); } + int entries = reserve_explicit_locations(prog, map, field_type, + location + location_count, + var_name, new_length, false); + if (entries == -1) + return -1; + + location_count += entries; + } + + return location_count; + } + + unsigned slots = glsl_type_uniform_locations(type); + unsigned max_loc = location + slots - 1; + unsigned return_value = slots; + + struct range_entry *re = + util_range_remap(location, prog->UniformRemapTable); + if (!re) { + re = util_range_insert_remap(location, max_loc, + prog->UniformRemapTable, NULL); + if (!re) { /* ARB_explicit_uniform_location specification states: * * "No two default-block uniform variables in the program can have @@ -2820,18 +2841,42 @@ reserve_explicit_locations(struct gl_shader_program *prog, linker_error(prog, "location qualifier for uniform %s overlaps " "previously used location\n", - var->name); + *var_name); return -1; } - /* Initialize location as inactive before optimization - * rounds and location assignment. - */ - prog->UniformRemapTable[loc] = INACTIVE_UNIFORM_EXPLICIT_LOCATION; + prog->NumUniformRemapTable += slots; } + /* Check if location is already used. */ + if (re->ptr == INACTIVE_UNIFORM_EXPLICIT_LOCATION) { + /* Possibly same uniform from a different stage, this is ok. */ + unsigned hash_loc; + if (string_to_uint_map_get(map, &hash_loc, *var_name) && + hash_loc == location) { + return return_zero ? 0 : return_value; + } else { + /* ARB_explicit_uniform_location specification states: + * + * "No two default-block uniform variables in the program can have + * the same location, even if they are unused, otherwise a compiler + * or linker error will be generated." + */ + linker_error(prog, + "location qualifier for uniform %s overlaps " + "previously used location\n", + *var_name); + return -1; + } + } + + /* Initialize location as inactive before optimization + * rounds and location assignment. + */ + re->ptr = INACTIVE_UNIFORM_EXPLICIT_LOCATION; + /* Note, base location used for arrays. */ - string_to_uint_map_put(map, var->data.location, var->name); + string_to_uint_map_put(map, location, *var_name); return return_value; } @@ -2895,13 +2940,16 @@ reserve_subroutine_explicit_locations(struct gl_shader_program *prog, * inactive array elements that may get trimmed away. */ static void -check_explicit_uniform_locations(const struct gl_extensions *exts, +check_explicit_uniform_locations(const struct gl_constants *consts, + const struct gl_extensions *exts, struct gl_shader_program *prog) { prog->NumExplicitUniformLocations = 0; - if (!exts->ARB_explicit_uniform_location) + if (!exts->ARB_explicit_uniform_location) { + link_util_update_empty_uniform_locations(consts, prog); return; + } /* This map is used to detect if overlapping explicit locations * occur with the same uniform (from different stage) or a different one. @@ -2926,8 +2974,14 @@ check_explicit_uniform_locations(const struct gl_extensions *exts, if (glsl_type_is_subroutine(glsl_without_array(var->type))) ret = reserve_subroutine_explicit_locations(prog, p, var); else { + char *name_tmp = ralloc_strdup(NULL, var->name); int slots = reserve_explicit_locations(prog, uniform_map, - var); + var->type, + var->data.location, + &name_tmp, + strlen(name_tmp), true); + ralloc_free(name_tmp); + if (slots != -1) { ret = true; entries_total += slots; @@ -2941,7 +2995,7 @@ check_explicit_uniform_locations(const struct gl_extensions *exts, } } - link_util_update_empty_uniform_locations(prog); + link_util_update_empty_uniform_locations(consts, prog); string_to_uint_map_dtor(uniform_map); prog->NumExplicitUniformLocations = entries_total; @@ -3705,7 +3759,7 @@ gl_nir_link_glsl(struct gl_context *ctx, struct gl_shader_program *prog) if (!prog->data->LinkStatus) goto done; - check_explicit_uniform_locations(exts, prog); + check_explicit_uniform_locations(consts, exts, prog); link_assign_subroutine_types(prog); verify_subroutine_associated_funcs(prog); diff --git a/src/compiler/glsl/linker_util.cpp b/src/compiler/glsl/linker_util.cpp index 80f21081d2e..15e40134923 100644 --- a/src/compiler/glsl/linker_util.cpp +++ b/src/compiler/glsl/linker_util.cpp @@ -27,6 +27,7 @@ #include "linker_util.h" #include "util/bitscan.h" #include "util/set.h" +#include "util/u_range_remap.h" #include "main/consts_exts.h" void @@ -249,24 +250,41 @@ link_util_find_empty_block(struct gl_shader_program *prog, } void -link_util_update_empty_uniform_locations(struct gl_shader_program *prog) +link_util_update_empty_uniform_locations(const struct gl_constants *consts, + struct gl_shader_program *prog) { - struct empty_uniform_block *current_block = NULL; - - for (unsigned i = 0; i < prog->NumUniformRemapTable; i++) { - /* We found empty space in UniformRemapTable. */ - if (prog->UniformRemapTable[i] == NULL) { + int prev_end = -1; + list_for_each_entry_safe(struct range_entry, e, prog->UniformRemapTable, node) { + unsigned next_slot = prev_end + 1; + if (e->start > next_slot) { /* We've found the beginning of a new continous block of empty slots */ - if (!current_block || current_block->start + current_block->slots != i) { - current_block = rzalloc(prog, struct empty_uniform_block); - current_block->start = i; - ir_exec_list_push_tail(&prog->EmptyUniformLocations, + struct empty_uniform_block *current_block = + rzalloc(prog, struct empty_uniform_block); + current_block->start = next_slot; + current_block->slots = e->start - next_slot; + ir_exec_list_push_tail(&prog->EmptyUniformLocations, ¤t_block->link); - } - - /* The current block continues, so we simply increment its slots */ - current_block->slots++; } + + prev_end = e->end; + } + + /* Add the remaining continous block of empty slots */ + unsigned next_slot = prev_end + 1; + /* Some drivers assign a max assignable value greater than max block size + * so we work around this by taking the max of either to get the remaining + * empty slots. + */ + unsigned max_slot = MAX2(consts->MaxUniformBlockSize, + consts->MaxUserAssignableUniformLocations) - 1; + if (max_slot >= next_slot) { + struct empty_uniform_block *current_block = + rzalloc(prog, struct empty_uniform_block); + current_block->start = next_slot; + current_block->slots = max_slot + 1 - next_slot; + + ir_exec_list_push_tail(&prog->EmptyUniformLocations, + ¤t_block->link); } } diff --git a/src/compiler/glsl/linker_util.h b/src/compiler/glsl/linker_util.h index 716052f0e79..0a7d32ab9f0 100644 --- a/src/compiler/glsl/linker_util.h +++ b/src/compiler/glsl/linker_util.h @@ -116,7 +116,8 @@ link_util_find_empty_block(struct gl_shader_program *prog, struct gl_uniform_storage *uniform); void -link_util_update_empty_uniform_locations(struct gl_shader_program *prog); +link_util_update_empty_uniform_locations(const struct gl_constants *consts, + struct gl_shader_program *prog); void link_util_check_subroutine_resources(struct gl_shader_program *prog); diff --git a/src/compiler/glsl/serialize.cpp b/src/compiler/glsl/serialize.cpp index 75274d29a13..7b596d6e278 100644 --- a/src/compiler/glsl/serialize.cpp +++ b/src/compiler/glsl/serialize.cpp @@ -37,6 +37,7 @@ #include "program/program.h" #include "string_to_uint_map.h" #include "util/bitscan.h" +#include "util/u_range_remap.h" static void @@ -573,6 +574,33 @@ enum uniform_remap_type remap_type_uniform_offsets_equal, }; +static void +write_uniform_remap_list(struct blob *metadata, + unsigned num_uniform_remap_table, + gl_uniform_storage *uniform_storage, + struct list_head *uniform_remap_list) +{ + blob_write_uint32(metadata, num_uniform_remap_table); + blob_write_uint32(metadata, list_length(uniform_remap_list)); + + list_for_each_entry_safe(struct range_entry, entry, uniform_remap_list, node) { + gl_uniform_storage *u = (gl_uniform_storage *)entry->ptr; + uint32_t offset = u - uniform_storage; + + if (u == INACTIVE_UNIFORM_EXPLICIT_LOCATION) { + blob_write_uint32(metadata, remap_type_inactive_explicit_location); + } else if (u == NULL) { + blob_write_uint32(metadata, remap_type_null_ptr); + } else { + blob_write_uint32(metadata, remap_type_uniform_offset); + blob_write_uint32(metadata, offset); + } + + blob_write_uint32(metadata, entry->start); + blob_write_uint32(metadata, entry->end); + } +} + static void write_uniform_remap_table(struct blob *metadata, unsigned num_entries, @@ -618,9 +646,9 @@ static void write_uniform_remap_tables(struct blob *metadata, struct gl_shader_program *prog) { - write_uniform_remap_table(metadata, prog->NumUniformRemapTable, - prog->data->UniformStorage, - prog->UniformRemapTable); + write_uniform_remap_list(metadata, prog->NumUniformRemapTable, + prog->data->UniformStorage, + prog->UniformRemapTable); for (unsigned i = 0; i < MESA_SHADER_MESH_STAGES; i++) { struct gl_linked_shader *sh = prog->_LinkedShaders[i]; @@ -633,6 +661,38 @@ write_uniform_remap_tables(struct blob *metadata, } } +static void +read_uniform_remap_list(struct blob_reader *metadata, + struct gl_shader_program *prog, + unsigned *num_entries, + struct list_head *remap_list, + gl_uniform_storage *uniform_storage) +{ + unsigned num = blob_read_uint32(metadata); + *num_entries = num; + + unsigned num_list_entries = blob_read_uint32(metadata); + + for (unsigned i = 0; i < num_list_entries; i++) { + gl_uniform_storage *uniform; + enum uniform_remap_type type = + (enum uniform_remap_type) blob_read_uint32(metadata); + + if (type == remap_type_inactive_explicit_location) { + uniform = INACTIVE_UNIFORM_EXPLICIT_LOCATION; + } else if (type == remap_type_null_ptr) { + uniform = NULL; + } else { + uint32_t uni_offset = blob_read_uint32(metadata); + uniform = uniform_storage + uni_offset; + } + + unsigned start = blob_read_uint32(metadata); + unsigned end = blob_read_uint32(metadata); + util_range_insert_remap(start, end, remap_list, uniform); + } +} + static struct gl_uniform_storage ** read_uniform_remap_table(struct blob_reader *metadata, struct gl_shader_program *prog, @@ -673,9 +733,9 @@ static void read_uniform_remap_tables(struct blob_reader *metadata, struct gl_shader_program *prog) { - prog->UniformRemapTable = - read_uniform_remap_table(metadata, prog, &prog->NumUniformRemapTable, - prog->data->UniformStorage); + read_uniform_remap_list(metadata, prog, &prog->NumUniformRemapTable, + prog->UniformRemapTable, + prog->data->UniformStorage); for (unsigned i = 0; i < MESA_SHADER_MESH_STAGES; i++) { struct gl_linked_shader *sh = prog->_LinkedShaders[i]; @@ -949,7 +1009,8 @@ read_program_resource_data(struct blob_reader *metadata, if (type == uniform_not_remapped) { res->Data = &prog->data->UniformStorage[blob_read_uint32(metadata)]; } else { - res->Data = prog->UniformRemapTable[blob_read_uint32(metadata)]; + res->Data = util_range_remap(blob_read_uint32(metadata), + prog->UniformRemapTable)->ptr; } break; } diff --git a/src/compiler/glsl/standalone_scaffolding.cpp b/src/compiler/glsl/standalone_scaffolding.cpp index e9ed5dafbfa..48c1ba36d0c 100644 --- a/src/compiler/glsl/standalone_scaffolding.cpp +++ b/src/compiler/glsl/standalone_scaffolding.cpp @@ -34,6 +34,7 @@ #include #include "util/ralloc.h" #include "util/strtod.h" +#include "util/u_range_remap.h" #include "main/mtypes.h" #include "string_to_uint_map.h" #include "pipe/p_screen.h" @@ -161,7 +162,8 @@ _mesa_clear_shader_program_data(struct gl_context *ctx, shProg->data->NumUniformStorage = 0; shProg->data->UniformStorage = NULL; shProg->NumUniformRemapTable = 0; - shProg->UniformRemapTable = NULL; + shProg->UniformRemapTable = + util_reset_range_remap(shProg->UniformRemapTable); ralloc_free(shProg->data->InfoLog); shProg->data->InfoLog = ralloc_strdup(shProg->data, ""); @@ -284,6 +286,8 @@ void initialize_context_to_defaults(struct gl_context *ctx, gl_api api) ctx->Const.Program[MESA_SHADER_COMPUTE].MaxInputComponents = 0; /* not used */ ctx->Const.Program[MESA_SHADER_COMPUTE].MaxOutputComponents = 0; /* not used */ + ctx->Const.MaxUniformBlockSize = 16384; + ctx->Driver.NewProgram = standalone_new_program; } @@ -303,6 +307,7 @@ standalone_create_shader_program(void) whole_program->FragDataBindings = new string_to_uint_map; whole_program->FragDataIndexBindings = new string_to_uint_map; + whole_program->UniformRemapTable = util_create_range_remap(); ir_exec_list_make_empty(&whole_program->EmptyUniformLocations); return whole_program; @@ -327,6 +332,7 @@ standalone_destroy_shader_program(struct gl_shader_program *whole_program) delete whole_program->FragDataBindings; delete whole_program->FragDataIndexBindings; + ralloc_free(whole_program->UniformRemapTable); ralloc_free(whole_program); } diff --git a/src/mesa/main/shader_types.h b/src/mesa/main/shader_types.h index fea689d8a91..0148384dc7a 100644 --- a/src/mesa/main/shader_types.h +++ b/src/mesa/main/shader_types.h @@ -440,7 +440,7 @@ struct gl_shader_program * in the UniformRemapTable, all pointing to the same UniformStorage entry. */ unsigned NumUniformRemapTable; - struct gl_uniform_storage **UniformRemapTable; + struct list_head *UniformRemapTable; /** * Sometimes there are empty slots left over in UniformRemapTable after we diff --git a/src/mesa/main/shaderobj.c b/src/mesa/main/shaderobj.c index 01ec855f948..636c6ba6119 100644 --- a/src/mesa/main/shaderobj.c +++ b/src/mesa/main/shaderobj.c @@ -43,6 +43,7 @@ #include "program/prog_parameter.h" #include "util/ralloc.h" #include "util/u_atomic.h" +#include "util/u_range_remap.h" /**********************************************************************/ /*** Shader object functions ***/ @@ -291,8 +292,6 @@ init_shader_program(struct gl_shader_program *prog) prog->FragDataIndexBindings = string_to_uint_map_ctor(); prog->TransformFeedback.BufferMode = GL_INTERLEAVED_ATTRIBS; - - ir_exec_list_make_empty(&prog->EmptyUniformLocations); } /** @@ -330,11 +329,9 @@ _mesa_clear_shader_program_data(struct gl_context *ctx, } } - if (shProg->UniformRemapTable) { - ralloc_free(shProg->UniformRemapTable); - shProg->NumUniformRemapTable = 0; - shProg->UniformRemapTable = NULL; - } + shProg->UniformRemapTable = + util_reset_range_remap(shProg->UniformRemapTable); + ir_exec_list_make_empty(&shProg->EmptyUniformLocations); if (shProg->data) _mesa_program_resource_hash_destroy(shProg); @@ -358,6 +355,11 @@ _mesa_free_shader_program_data(struct gl_context *ctx, _mesa_clear_shader_program_data(ctx, shProg); + if (shProg->UniformRemapTable) { + ralloc_free(shProg->UniformRemapTable); + shProg->UniformRemapTable = NULL; + } + if (shProg->AttributeBindings) { string_to_uint_map_dtor(shProg->AttributeBindings); shProg->AttributeBindings = NULL; diff --git a/src/mesa/main/uniform_query.cpp b/src/mesa/main/uniform_query.cpp index 9e01d43ec42..54957c0d762 100644 --- a/src/mesa/main/uniform_query.cpp +++ b/src/mesa/main/uniform_query.cpp @@ -36,6 +36,7 @@ #include "compiler/glsl/ir.h" #include "compiler/glsl/glsl_parser_extras.h" #include "util/bitscan.h" +#include "util/u_range_remap.h" #include "state_tracker/st_context.h" @@ -200,11 +201,17 @@ validate_uniform_parameters(GLint location, GLsizei count, return NULL; } - /* Check that the given location is in bounds of uniform remap table. - * Unlinked programs will have NumUniformRemapTable == 0, so we can take - * the shProg->data->LinkStatus check out of the main path. - */ - if (unlikely(location >= (GLint) shProg->NumUniformRemapTable)) { + if (location == -1) { + if (!shProg->data->LinkStatus) + _mesa_error(ctx, GL_INVALID_OPERATION, "%s(program not linked)", + caller); + + return NULL; + } + + /* Check that the given location is in bounds of uniform remap table */ + if (unlikely(location >= 0 && + (shProg->UniformRemapTable == NULL || list_is_empty(shProg->UniformRemapTable)))) { if (!shProg->data->LinkStatus) _mesa_error(ctx, GL_INVALID_OPERATION, "%s(program not linked)", caller); @@ -215,14 +222,6 @@ validate_uniform_parameters(GLint location, GLsizei count, return NULL; } - if (location == -1) { - if (!shProg->data->LinkStatus) - _mesa_error(ctx, GL_INVALID_OPERATION, "%s(program not linked)", - caller); - - return NULL; - } - /* Page 82 (page 96 of the PDF) of the OpenGL 2.1 spec says: * * "If any of the following conditions occur, an INVALID_OPERATION @@ -236,7 +235,14 @@ validate_uniform_parameters(GLint location, GLsizei count, * - if count is greater than one, and the uniform declared in the * shader is not an array variable, */ - if (location < -1 || !shProg->UniformRemapTable[location]) { + struct gl_uniform_storage *uni = NULL; + if (location >= 0) { + struct range_entry *e = + util_range_remap(location, shProg->UniformRemapTable); + uni = e ? (struct gl_uniform_storage *)e->ptr : NULL; + } + + if (!uni) { _mesa_error(ctx, GL_INVALID_OPERATION, "%s(location=%d)", caller, location); return NULL; @@ -253,12 +259,9 @@ validate_uniform_parameters(GLint location, GLsizei count, * no error is generated." * */ - if (shProg->UniformRemapTable[location] == - INACTIVE_UNIFORM_EXPLICIT_LOCATION) + if (uni == INACTIVE_UNIFORM_EXPLICIT_LOCATION) return NULL; - struct gl_uniform_storage *const uni = shProg->UniformRemapTable[location]; - /* Even though no location is assigned to a built-in uniform and this * function should already have returned NULL, this test makes it explicit * that we are not allowing to update the value of a built-in. @@ -1449,10 +1452,10 @@ _mesa_uniform(GLint location, GLsizei count, const GLvoid *values, if (location == -1) return; - if (location >= (int)shProg->NumUniformRemapTable) - return; + struct range_entry *e = + util_range_remap(location, shProg->UniformRemapTable); + uni = e ? (struct gl_uniform_storage *)e->ptr : NULL; - uni = shProg->UniformRemapTable[location]; if (!uni || uni == INACTIVE_UNIFORM_EXPLICIT_LOCATION) return; @@ -2019,7 +2022,10 @@ _mesa_uniform_handle(GLint location, GLsizei count, const GLvoid *values, if (location == -1) return; - uni = shProg->UniformRemapTable[location]; + struct range_entry *e = + util_range_remap(location, shProg->UniformRemapTable); + uni = e ? (struct gl_uniform_storage *)e->ptr : NULL; + if (!uni || uni == INACTIVE_UNIFORM_EXPLICIT_LOCATION) return;