glsl: make use of u_range_remap for uniform remapping

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 <marek.olsak@amd.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/36997>
This commit is contained in:
Timothy Arceri 2025-08-06 11:46:47 +10:00 committed by Marge Bot
parent bf946bccf2
commit e052254066
9 changed files with 263 additions and 132 deletions

View file

@ -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

View file

@ -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);

View file

@ -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,
&current_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,
&current_block->link);
}
}

View file

@ -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);

View file

@ -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;
}

View file

@ -34,6 +34,7 @@
#include <string.h>
#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);
}

View file

@ -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

View file

@ -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;

View file

@ -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;