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 "linker_util.h"
#include "util/u_dynarray.h" #include "util/u_dynarray.h"
#include "util/u_math.h" #include "util/u_math.h"
#include "util/u_range_remap.h"
#include "main/consts_exts.h" #include "main/consts_exts.h"
#include "main/shader_types.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. * that we can keep track of unused uniforms with explicit locations.
*/ */
assert(!prog->data->spirv || assert(!prog->data->spirv ||
(prog->data->spirv && !prog->UniformRemapTable)); (prog->data->spirv && list_is_empty(prog->UniformRemapTable)));
if (!prog->UniformRemapTable) {
prog->UniformRemapTable = rzalloc_array(prog,
struct gl_uniform_storage *,
prog->NumUniformRemapTable);
}
union gl_constant_value *data = union gl_constant_value *data =
rzalloc_array(prog->data, rzalloc_array(prog->data,
union gl_constant_value, prog->data->NumUniformDataSlots); union gl_constant_value, prog->data->NumUniformDataSlots);
if (!prog->UniformRemapTable || !data) { if (!data) {
linker_error(prog, "Out of memory during linking.\n"); linker_error(prog, "Out of memory during linking.\n");
return; return;
} }
@ -321,19 +317,17 @@ setup_uniform_remap_tables(const struct gl_constants *consts,
unsigned num_slots = glsl_get_component_slots(uniform->type); unsigned num_slots = glsl_get_component_slots(uniform->type);
uniform->storage = &data[data_pos]; uniform->storage = &data[data_pos];
data_pos += num_slots * entries;
/* Set remap table entries point to correct gl_uniform_storage. */ /* Set remap table entry to the correct gl_uniform_storage. */
for (unsigned j = 0; j < entries; j++) { util_range_insert_remap(uniform->remap_location,
unsigned element_loc = uniform->remap_location + j; uniform->remap_location + entries - 1,
prog->UniformRemapTable[element_loc] = uniform; prog->UniformRemapTable, uniform);
data_pos += num_slots;
}
} }
/* Reserve locations for rest of the uniforms. */ /* Reserve locations for rest of the uniforms. */
if (prog->data->spirv) 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++) { for (unsigned i = 0; i < prog->data->NumUniformStorage; i++) {
struct gl_uniform_storage *uniform = &prog->data->UniformStorage[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 = unsigned location =
link_util_find_empty_block(prog, &prog->data->UniformStorage[i]); link_util_find_empty_block(prog, &prog->data->UniformStorage[i]);
if (location == -1) { 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 */ unsigned num_slots = glsl_get_component_slots(uniform->type);
prog->UniformRemapTable = if (uniform->block_index == -1) {
reralloc(prog, uniform->storage = &data[data_pos];
prog->UniformRemapTable, data_pos += num_slots * entries;
struct gl_uniform_storage *,
prog->NumUniformRemapTable + entries);
prog->NumUniformRemapTable += entries;
} }
/* set the base location in remap table for the uniform */ /* set the base location in remap table for the uniform */
uniform->remap_location = location; uniform->remap_location = location;
unsigned num_slots = glsl_get_component_slots(uniform->type); /* Set remap table entry to the correct gl_uniform_storage. */
util_range_insert_remap(uniform->remap_location,
if (uniform->block_index == -1) uniform->remap_location + entries - 1,
uniform->storage = &data[data_pos]; prog->UniformRemapTable, uniform);
/* 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;
}
} }
/* Verify that total amount of entries for explicit and implicit locations /* Verify that total amount of entries for explicit and implicit locations

View file

@ -34,6 +34,7 @@
#include "main/context.h" #include "main/context.h"
#include "main/shaderobj.h" #include "main/shaderobj.h"
#include "util/glheader.h" #include "util/glheader.h"
#include "util/u_range_remap.h"
#include "util/perf/cpu_trace.h" #include "util/perf/cpu_trace.h"
#include "pipe/p_screen.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 * Initializes explicit location slots to INACTIVE_UNIFORM_EXPLICIT_LOCATION
* for a variable, checks for overlaps between other uniforms using explicit * for a variable, checks for overlaps between other uniforms using explicit
* locations. * locations.
* If return_zero bool is true zero will be returned if the uniform was
* already processed for a different stage.
*/ */
static int static int
reserve_explicit_locations(struct gl_shader_program *prog, 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); if (glsl_type_is_struct_or_ifc(type) ||
unsigned max_loc = var->data.location + slots - 1; (glsl_type_is_array(type) &&
unsigned return_value = slots; (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. */ unsigned length = glsl_get_length(type);
if (max_loc + 1 > prog->NumUniformRemapTable) { if (glsl_type_is_unsized_array(type))
prog->UniformRemapTable = length = 1;
reralloc(prog, prog->UniformRemapTable,
struct gl_uniform_storage *,
max_loc + 1);
if (!prog->UniformRemapTable) { int location_count = 0;
linker_error(prog, "Out of memory during linking.\n"); for (unsigned i = 0; i < length; i++) {
return -1; const struct glsl_type *field_type;
} size_t new_length = name_length;
/* Initialize allocated space. */ if (glsl_type_is_struct_or_ifc(type)) {
for (unsigned i = prog->NumUniformRemapTable; i < max_loc + 1; i++) field_type = glsl_get_struct_field(type, i);
prog->UniformRemapTable[i] = NULL;
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++) { /* Append the subscript to the current variable name */
unsigned loc = var->data.location + i; if (var_name)
ralloc_asprintf_rewrite_tail(var_name, &new_length, "[%u]", 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;
} }
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: /* ARB_explicit_uniform_location specification states:
* *
* "No two default-block uniform variables in the program can have * "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, linker_error(prog,
"location qualifier for uniform %s overlaps " "location qualifier for uniform %s overlaps "
"previously used location\n", "previously used location\n",
var->name); *var_name);
return -1; return -1;
} }
/* Initialize location as inactive before optimization prog->NumUniformRemapTable += slots;
* rounds and location assignment.
*/
prog->UniformRemapTable[loc] = INACTIVE_UNIFORM_EXPLICIT_LOCATION;
} }
/* 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. */ /* 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; return return_value;
} }
@ -2895,13 +2940,16 @@ reserve_subroutine_explicit_locations(struct gl_shader_program *prog,
* inactive array elements that may get trimmed away. * inactive array elements that may get trimmed away.
*/ */
static void 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) struct gl_shader_program *prog)
{ {
prog->NumExplicitUniformLocations = 0; prog->NumExplicitUniformLocations = 0;
if (!exts->ARB_explicit_uniform_location) if (!exts->ARB_explicit_uniform_location) {
link_util_update_empty_uniform_locations(consts, prog);
return; return;
}
/* This map is used to detect if overlapping explicit locations /* This map is used to detect if overlapping explicit locations
* occur with the same uniform (from different stage) or a different one. * 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))) if (glsl_type_is_subroutine(glsl_without_array(var->type)))
ret = reserve_subroutine_explicit_locations(prog, p, var); ret = reserve_subroutine_explicit_locations(prog, p, var);
else { else {
char *name_tmp = ralloc_strdup(NULL, var->name);
int slots = reserve_explicit_locations(prog, uniform_map, 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) { if (slots != -1) {
ret = true; ret = true;
entries_total += slots; 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); string_to_uint_map_dtor(uniform_map);
prog->NumExplicitUniformLocations = entries_total; 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) if (!prog->data->LinkStatus)
goto done; goto done;
check_explicit_uniform_locations(exts, prog); check_explicit_uniform_locations(consts, exts, prog);
link_assign_subroutine_types(prog); link_assign_subroutine_types(prog);
verify_subroutine_associated_funcs(prog); verify_subroutine_associated_funcs(prog);

View file

@ -27,6 +27,7 @@
#include "linker_util.h" #include "linker_util.h"
#include "util/bitscan.h" #include "util/bitscan.h"
#include "util/set.h" #include "util/set.h"
#include "util/u_range_remap.h"
#include "main/consts_exts.h" #include "main/consts_exts.h"
void void
@ -249,24 +250,41 @@ link_util_find_empty_block(struct gl_shader_program *prog,
} }
void 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; int prev_end = -1;
list_for_each_entry_safe(struct range_entry, e, prog->UniformRemapTable, node) {
for (unsigned i = 0; i < prog->NumUniformRemapTable; i++) { unsigned next_slot = prev_end + 1;
/* We found empty space in UniformRemapTable. */ if (e->start > next_slot) {
if (prog->UniformRemapTable[i] == NULL) {
/* We've found the beginning of a new continous block of empty slots */ /* We've found the beginning of a new continous block of empty slots */
if (!current_block || current_block->start + current_block->slots != i) { struct empty_uniform_block *current_block =
current_block = rzalloc(prog, struct empty_uniform_block); rzalloc(prog, struct empty_uniform_block);
current_block->start = i; current_block->start = next_slot;
ir_exec_list_push_tail(&prog->EmptyUniformLocations, current_block->slots = e->start - next_slot;
ir_exec_list_push_tail(&prog->EmptyUniformLocations,
&current_block->link); &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); struct gl_uniform_storage *uniform);
void 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 void
link_util_check_subroutine_resources(struct gl_shader_program *prog); link_util_check_subroutine_resources(struct gl_shader_program *prog);

View file

@ -37,6 +37,7 @@
#include "program/program.h" #include "program/program.h"
#include "string_to_uint_map.h" #include "string_to_uint_map.h"
#include "util/bitscan.h" #include "util/bitscan.h"
#include "util/u_range_remap.h"
static void static void
@ -573,6 +574,33 @@ enum uniform_remap_type
remap_type_uniform_offsets_equal, 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 static void
write_uniform_remap_table(struct blob *metadata, write_uniform_remap_table(struct blob *metadata,
unsigned num_entries, unsigned num_entries,
@ -618,9 +646,9 @@ static void
write_uniform_remap_tables(struct blob *metadata, write_uniform_remap_tables(struct blob *metadata,
struct gl_shader_program *prog) struct gl_shader_program *prog)
{ {
write_uniform_remap_table(metadata, prog->NumUniformRemapTable, write_uniform_remap_list(metadata, prog->NumUniformRemapTable,
prog->data->UniformStorage, prog->data->UniformStorage,
prog->UniformRemapTable); prog->UniformRemapTable);
for (unsigned i = 0; i < MESA_SHADER_MESH_STAGES; i++) { for (unsigned i = 0; i < MESA_SHADER_MESH_STAGES; i++) {
struct gl_linked_shader *sh = prog->_LinkedShaders[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 ** static struct gl_uniform_storage **
read_uniform_remap_table(struct blob_reader *metadata, read_uniform_remap_table(struct blob_reader *metadata,
struct gl_shader_program *prog, struct gl_shader_program *prog,
@ -673,9 +733,9 @@ static void
read_uniform_remap_tables(struct blob_reader *metadata, read_uniform_remap_tables(struct blob_reader *metadata,
struct gl_shader_program *prog) struct gl_shader_program *prog)
{ {
prog->UniformRemapTable = read_uniform_remap_list(metadata, prog, &prog->NumUniformRemapTable,
read_uniform_remap_table(metadata, prog, &prog->NumUniformRemapTable, prog->UniformRemapTable,
prog->data->UniformStorage); prog->data->UniformStorage);
for (unsigned i = 0; i < MESA_SHADER_MESH_STAGES; i++) { for (unsigned i = 0; i < MESA_SHADER_MESH_STAGES; i++) {
struct gl_linked_shader *sh = prog->_LinkedShaders[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) { if (type == uniform_not_remapped) {
res->Data = &prog->data->UniformStorage[blob_read_uint32(metadata)]; res->Data = &prog->data->UniformStorage[blob_read_uint32(metadata)];
} else { } else {
res->Data = prog->UniformRemapTable[blob_read_uint32(metadata)]; res->Data = util_range_remap(blob_read_uint32(metadata),
prog->UniformRemapTable)->ptr;
} }
break; break;
} }

View file

@ -34,6 +34,7 @@
#include <string.h> #include <string.h>
#include "util/ralloc.h" #include "util/ralloc.h"
#include "util/strtod.h" #include "util/strtod.h"
#include "util/u_range_remap.h"
#include "main/mtypes.h" #include "main/mtypes.h"
#include "string_to_uint_map.h" #include "string_to_uint_map.h"
#include "pipe/p_screen.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->NumUniformStorage = 0;
shProg->data->UniformStorage = NULL; shProg->data->UniformStorage = NULL;
shProg->NumUniformRemapTable = 0; shProg->NumUniformRemapTable = 0;
shProg->UniformRemapTable = NULL; shProg->UniformRemapTable =
util_reset_range_remap(shProg->UniformRemapTable);
ralloc_free(shProg->data->InfoLog); ralloc_free(shProg->data->InfoLog);
shProg->data->InfoLog = ralloc_strdup(shProg->data, ""); 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].MaxInputComponents = 0; /* not used */
ctx->Const.Program[MESA_SHADER_COMPUTE].MaxOutputComponents = 0; /* not used */ ctx->Const.Program[MESA_SHADER_COMPUTE].MaxOutputComponents = 0; /* not used */
ctx->Const.MaxUniformBlockSize = 16384;
ctx->Driver.NewProgram = standalone_new_program; 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->FragDataBindings = new string_to_uint_map;
whole_program->FragDataIndexBindings = 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); ir_exec_list_make_empty(&whole_program->EmptyUniformLocations);
return whole_program; return whole_program;
@ -327,6 +332,7 @@ standalone_destroy_shader_program(struct gl_shader_program *whole_program)
delete whole_program->FragDataBindings; delete whole_program->FragDataBindings;
delete whole_program->FragDataIndexBindings; delete whole_program->FragDataIndexBindings;
ralloc_free(whole_program->UniformRemapTable);
ralloc_free(whole_program); ralloc_free(whole_program);
} }

View file

@ -440,7 +440,7 @@ struct gl_shader_program
* in the UniformRemapTable, all pointing to the same UniformStorage entry. * in the UniformRemapTable, all pointing to the same UniformStorage entry.
*/ */
unsigned NumUniformRemapTable; unsigned NumUniformRemapTable;
struct gl_uniform_storage **UniformRemapTable; struct list_head *UniformRemapTable;
/** /**
* Sometimes there are empty slots left over in UniformRemapTable after we * Sometimes there are empty slots left over in UniformRemapTable after we

View file

@ -43,6 +43,7 @@
#include "program/prog_parameter.h" #include "program/prog_parameter.h"
#include "util/ralloc.h" #include "util/ralloc.h"
#include "util/u_atomic.h" #include "util/u_atomic.h"
#include "util/u_range_remap.h"
/**********************************************************************/ /**********************************************************************/
/*** Shader object functions ***/ /*** Shader object functions ***/
@ -291,8 +292,6 @@ init_shader_program(struct gl_shader_program *prog)
prog->FragDataIndexBindings = string_to_uint_map_ctor(); prog->FragDataIndexBindings = string_to_uint_map_ctor();
prog->TransformFeedback.BufferMode = GL_INTERLEAVED_ATTRIBS; 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) { shProg->UniformRemapTable =
ralloc_free(shProg->UniformRemapTable); util_reset_range_remap(shProg->UniformRemapTable);
shProg->NumUniformRemapTable = 0; ir_exec_list_make_empty(&shProg->EmptyUniformLocations);
shProg->UniformRemapTable = NULL;
}
if (shProg->data) if (shProg->data)
_mesa_program_resource_hash_destroy(shProg); _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); _mesa_clear_shader_program_data(ctx, shProg);
if (shProg->UniformRemapTable) {
ralloc_free(shProg->UniformRemapTable);
shProg->UniformRemapTable = NULL;
}
if (shProg->AttributeBindings) { if (shProg->AttributeBindings) {
string_to_uint_map_dtor(shProg->AttributeBindings); string_to_uint_map_dtor(shProg->AttributeBindings);
shProg->AttributeBindings = NULL; shProg->AttributeBindings = NULL;

View file

@ -36,6 +36,7 @@
#include "compiler/glsl/ir.h" #include "compiler/glsl/ir.h"
#include "compiler/glsl/glsl_parser_extras.h" #include "compiler/glsl/glsl_parser_extras.h"
#include "util/bitscan.h" #include "util/bitscan.h"
#include "util/u_range_remap.h"
#include "state_tracker/st_context.h" #include "state_tracker/st_context.h"
@ -200,11 +201,17 @@ validate_uniform_parameters(GLint location, GLsizei count,
return NULL; return NULL;
} }
/* Check that the given location is in bounds of uniform remap table. if (location == -1) {
* Unlinked programs will have NumUniformRemapTable == 0, so we can take if (!shProg->data->LinkStatus)
* the shProg->data->LinkStatus check out of the main path. _mesa_error(ctx, GL_INVALID_OPERATION, "%s(program not linked)",
*/ caller);
if (unlikely(location >= (GLint) shProg->NumUniformRemapTable)) {
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) if (!shProg->data->LinkStatus)
_mesa_error(ctx, GL_INVALID_OPERATION, "%s(program not linked)", _mesa_error(ctx, GL_INVALID_OPERATION, "%s(program not linked)",
caller); caller);
@ -215,14 +222,6 @@ validate_uniform_parameters(GLint location, GLsizei count,
return NULL; 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: /* Page 82 (page 96 of the PDF) of the OpenGL 2.1 spec says:
* *
* "If any of the following conditions occur, an INVALID_OPERATION * "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 * - if count is greater than one, and the uniform declared in the
* shader is not an array variable, * 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)", _mesa_error(ctx, GL_INVALID_OPERATION, "%s(location=%d)",
caller, location); caller, location);
return NULL; return NULL;
@ -253,12 +259,9 @@ validate_uniform_parameters(GLint location, GLsizei count,
* no error is generated." * no error is generated."
* *
*/ */
if (shProg->UniformRemapTable[location] == if (uni == INACTIVE_UNIFORM_EXPLICIT_LOCATION)
INACTIVE_UNIFORM_EXPLICIT_LOCATION)
return NULL; return NULL;
struct gl_uniform_storage *const uni = shProg->UniformRemapTable[location];
/* Even though no location is assigned to a built-in uniform and this /* Even though no location is assigned to a built-in uniform and this
* function should already have returned NULL, this test makes it explicit * function should already have returned NULL, this test makes it explicit
* that we are not allowing to update the value of a built-in. * 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) if (location == -1)
return; return;
if (location >= (int)shProg->NumUniformRemapTable) struct range_entry *e =
return; 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) if (!uni || uni == INACTIVE_UNIFORM_EXPLICIT_LOCATION)
return; return;
@ -2019,7 +2022,10 @@ _mesa_uniform_handle(GLint location, GLsizei count, const GLvoid *values,
if (location == -1) if (location == -1)
return; 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) if (!uni || uni == INACTIVE_UNIFORM_EXPLICIT_LOCATION)
return; return;