From f60956d002909e30bd96f0e62c5789f6be21c06a Mon Sep 17 00:00:00 2001 From: Timothy Arceri Date: Wed, 27 Mar 2024 09:15:07 +1100 Subject: [PATCH] glsl: move check_explicit_uniform_locations() to NIR linker MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Acked-by: Marek Olšák Part-of: --- src/compiler/glsl/gl_nir_linker.c | 185 +++++++++++++++++++++++++++++ src/compiler/glsl/ir_uniform.h | 2 +- src/compiler/glsl/linker.cpp | 187 ------------------------------ 3 files changed, 186 insertions(+), 188 deletions(-) diff --git a/src/compiler/glsl/gl_nir_linker.c b/src/compiler/glsl/gl_nir_linker.c index dbc98a4531e..1d56fcf5c9c 100644 --- a/src/compiler/glsl/gl_nir_linker.c +++ b/src/compiler/glsl/gl_nir_linker.c @@ -28,6 +28,7 @@ #include "gl_nir_linker.h" #include "gl_nir_link_varyings.h" #include "linker_util.h" +#include "string_to_uint_map.h" #include "main/shader_types.h" #include "main/consts_exts.h" #include "main/shaderobj.h" @@ -1466,6 +1467,188 @@ gl_nir_link_spirv(const struct gl_constants *consts, return true; } +/** + * Initializes explicit location slots to INACTIVE_UNIFORM_EXPLICIT_LOCATION + * for a variable, checks for overlaps between other uniforms using explicit + * locations. + */ +static int +reserve_explicit_locations(struct gl_shader_program *prog, + struct string_to_uint_map *map, nir_variable *var) +{ + unsigned slots = glsl_type_uniform_locations(var->type); + unsigned max_loc = var->data.location + slots - 1; + unsigned return_value = slots; + + /* 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); + + if (!prog->UniformRemapTable) { + linker_error(prog, "Out of memory during linking.\n"); + return -1; + } + + /* Initialize allocated space. */ + for (unsigned i = prog->NumUniformRemapTable; i < max_loc + 1; i++) + prog->UniformRemapTable[i] = NULL; + + prog->NumUniformRemapTable = max_loc + 1; + } + + 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; + } + + /* 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. + */ + prog->UniformRemapTable[loc] = INACTIVE_UNIFORM_EXPLICIT_LOCATION; + } + + /* Note, base location used for arrays. */ + string_to_uint_map_put(map, var->data.location, var->name); + + return return_value; +} + +static bool +reserve_subroutine_explicit_locations(struct gl_shader_program *prog, + struct gl_program *p, + nir_variable *var) +{ + unsigned slots = glsl_type_uniform_locations(var->type); + unsigned max_loc = var->data.location + slots - 1; + + /* Resize remap table if locations do not fit in the current one. */ + if (max_loc + 1 > p->sh.NumSubroutineUniformRemapTable) { + p->sh.SubroutineUniformRemapTable = + reralloc(p, p->sh.SubroutineUniformRemapTable, + struct gl_uniform_storage *, + max_loc + 1); + + if (!p->sh.SubroutineUniformRemapTable) { + linker_error(prog, "Out of memory during linking.\n"); + return false; + } + + /* Initialize allocated space. */ + for (unsigned i = p->sh.NumSubroutineUniformRemapTable; i < max_loc + 1; i++) + p->sh.SubroutineUniformRemapTable[i] = NULL; + + p->sh.NumSubroutineUniformRemapTable = max_loc + 1; + } + + for (unsigned i = 0; i < slots; i++) { + unsigned loc = var->data.location + i; + + /* Check if location is already used. */ + if (p->sh.SubroutineUniformRemapTable[loc] == INACTIVE_UNIFORM_EXPLICIT_LOCATION) { + + /* ARB_explicit_uniform_location specification states: + * "No two subroutine uniform variables can have the same location + * in the same shader stage, 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 false; + } + + /* Initialize location as inactive before optimization + * rounds and location assignment. + */ + p->sh.SubroutineUniformRemapTable[loc] = INACTIVE_UNIFORM_EXPLICIT_LOCATION; + } + + return true; +} +/** + * Check and reserve all explicit uniform locations, called before + * any optimizations happen to handle also inactive uniforms and + * inactive array elements that may get trimmed away. + */ +static void +check_explicit_uniform_locations(const struct gl_extensions *exts, + struct gl_shader_program *prog) +{ + prog->NumExplicitUniformLocations = 0; + + if (!exts->ARB_explicit_uniform_location) + return; + + /* This map is used to detect if overlapping explicit locations + * occur with the same uniform (from different stage) or a different one. + */ + struct string_to_uint_map *uniform_map = string_to_uint_map_ctor(); + + if (!uniform_map) { + linker_error(prog, "Out of memory during linking.\n"); + return; + } + + unsigned entries_total = 0; + unsigned mask = prog->data->linked_stages; + while (mask) { + const int i = u_bit_scan(&mask); + struct gl_program *p = prog->_LinkedShaders[i]->Program; + + unsigned modes = nir_var_uniform | nir_var_mem_ubo | nir_var_image; + nir_foreach_variable_with_modes(var, p->nir, modes) { + if (var->data.explicit_location) { + bool ret = false; + if (glsl_type_is_subroutine(glsl_without_array(var->type))) + ret = reserve_subroutine_explicit_locations(prog, p, var); + else { + int slots = reserve_explicit_locations(prog, uniform_map, + var); + if (slots != -1) { + ret = true; + entries_total += slots; + } + } + if (!ret) { + string_to_uint_map_dtor(uniform_map); + return; + } + } + } + } + + link_util_update_empty_uniform_locations(prog); + + string_to_uint_map_dtor(uniform_map); + prog->NumExplicitUniformLocations = entries_total; +} + static void link_assign_subroutine_types(struct gl_shader_program *prog) { @@ -1790,6 +1973,8 @@ gl_nir_link_glsl(const struct gl_constants *consts, MESA_TRACE_FUNC(); + check_explicit_uniform_locations(exts, prog); + link_assign_subroutine_types(prog); verify_subroutine_associated_funcs(prog); if (!prog->data->LinkStatus) diff --git a/src/compiler/glsl/ir_uniform.h b/src/compiler/glsl/ir_uniform.h index f44b8e3f4f2..42c8bf0a803 100644 --- a/src/compiler/glsl/ir_uniform.h +++ b/src/compiler/glsl/ir_uniform.h @@ -35,7 +35,7 @@ * Used by GL_ARB_explicit_uniform_location extension code in the linker * and glUniform* functions to identify inactive explicit uniform locations. */ -#define INACTIVE_UNIFORM_EXPLICIT_LOCATION ((gl_uniform_storage *) -1) +#define INACTIVE_UNIFORM_EXPLICIT_LOCATION ((struct gl_uniform_storage *) -1) #ifdef __cplusplus extern "C" { diff --git a/src/compiler/glsl/linker.cpp b/src/compiler/glsl/linker.cpp index 1cc6d83505d..720b0f10003 100644 --- a/src/compiler/glsl/linker.cpp +++ b/src/compiler/glsl/linker.cpp @@ -2190,191 +2190,6 @@ link_intrastage_shaders(void *mem_ctx, return linked; } - -/** - * Initializes explicit location slots to INACTIVE_UNIFORM_EXPLICIT_LOCATION - * for a variable, checks for overlaps between other uniforms using explicit - * locations. - */ -static int -reserve_explicit_locations(struct gl_shader_program *prog, - string_to_uint_map *map, ir_variable *var) -{ - unsigned slots = glsl_type_uniform_locations(var->type); - unsigned max_loc = var->data.location + slots - 1; - unsigned return_value = slots; - - /* Resize remap table if locations do not fit in the current one. */ - if (max_loc + 1 > prog->NumUniformRemapTable) { - prog->UniformRemapTable = - reralloc(prog, prog->UniformRemapTable, - gl_uniform_storage *, - max_loc + 1); - - if (!prog->UniformRemapTable) { - linker_error(prog, "Out of memory during linking.\n"); - return -1; - } - - /* Initialize allocated space. */ - for (unsigned i = prog->NumUniformRemapTable; i < max_loc + 1; i++) - prog->UniformRemapTable[i] = NULL; - - prog->NumUniformRemapTable = max_loc + 1; - } - - 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 (map->get(hash_loc, var->name) && hash_loc == loc - i) { - return_value = 0; - continue; - } - - /* 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. - */ - prog->UniformRemapTable[loc] = INACTIVE_UNIFORM_EXPLICIT_LOCATION; - } - - /* Note, base location used for arrays. */ - map->put(var->data.location, var->name); - - return return_value; -} - -static bool -reserve_subroutine_explicit_locations(struct gl_shader_program *prog, - struct gl_program *p, - ir_variable *var) -{ - unsigned slots = glsl_type_uniform_locations(var->type); - unsigned max_loc = var->data.location + slots - 1; - - /* Resize remap table if locations do not fit in the current one. */ - if (max_loc + 1 > p->sh.NumSubroutineUniformRemapTable) { - p->sh.SubroutineUniformRemapTable = - reralloc(p, p->sh.SubroutineUniformRemapTable, - gl_uniform_storage *, - max_loc + 1); - - if (!p->sh.SubroutineUniformRemapTable) { - linker_error(prog, "Out of memory during linking.\n"); - return false; - } - - /* Initialize allocated space. */ - for (unsigned i = p->sh.NumSubroutineUniformRemapTable; i < max_loc + 1; i++) - p->sh.SubroutineUniformRemapTable[i] = NULL; - - p->sh.NumSubroutineUniformRemapTable = max_loc + 1; - } - - for (unsigned i = 0; i < slots; i++) { - unsigned loc = var->data.location + i; - - /* Check if location is already used. */ - if (p->sh.SubroutineUniformRemapTable[loc] == INACTIVE_UNIFORM_EXPLICIT_LOCATION) { - - /* ARB_explicit_uniform_location specification states: - * "No two subroutine uniform variables can have the same location - * in the same shader stage, 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 false; - } - - /* Initialize location as inactive before optimization - * rounds and location assignment. - */ - p->sh.SubroutineUniformRemapTable[loc] = INACTIVE_UNIFORM_EXPLICIT_LOCATION; - } - - return true; -} -/** - * Check and reserve all explicit uniform locations, called before - * any optimizations happen to handle also inactive uniforms and - * inactive array elements that may get trimmed away. - */ -static void -check_explicit_uniform_locations(const struct gl_extensions *exts, - struct gl_shader_program *prog) -{ - prog->NumExplicitUniformLocations = 0; - - if (!exts->ARB_explicit_uniform_location) - return; - - /* This map is used to detect if overlapping explicit locations - * occur with the same uniform (from different stage) or a different one. - */ - string_to_uint_map *uniform_map = new string_to_uint_map; - - if (!uniform_map) { - linker_error(prog, "Out of memory during linking.\n"); - return; - } - - unsigned entries_total = 0; - unsigned mask = prog->data->linked_stages; - while (mask) { - const int i = u_bit_scan(&mask); - struct gl_program *p = prog->_LinkedShaders[i]->Program; - - foreach_in_list(ir_instruction, node, prog->_LinkedShaders[i]->ir) { - ir_variable *var = node->as_variable(); - if (!var || var->data.mode != ir_var_uniform) - continue; - - if (var->data.explicit_location) { - bool ret = false; - if (glsl_type_is_subroutine(glsl_without_array(var->type))) - ret = reserve_subroutine_explicit_locations(prog, p, var); - else { - int slots = reserve_explicit_locations(prog, uniform_map, - var); - if (slots != -1) { - ret = true; - entries_total += slots; - } - } - if (!ret) { - delete uniform_map; - return; - } - } - } - } - - link_util_update_empty_uniform_locations(prog); - - delete uniform_map; - prog->NumExplicitUniformLocations = entries_total; -} - void link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) { @@ -2571,8 +2386,6 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) if (!prog->data->LinkStatus) goto done; - check_explicit_uniform_locations(&ctx->Extensions, prog); - done: for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) { free(shader_list[i]);