From 65dfb3048e8291675ca33581aeff8921f7ea509d Mon Sep 17 00:00:00 2001 From: Plamena Manolova Date: Thu, 11 Feb 2016 15:00:02 +0200 Subject: [PATCH] compiler/glsl: Fix uniform location counting. MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit This patch moves the calculation of current uniforms to link_uniforms, which makes use of UniformRemapTable which stores all the reserved uniform locations. Location assignment for implicit uniforms now tries to use any gaps left in the table after the location assignment for explicit uniforms. This gives us more space to store more uniforms. Patch is based on earlier patch with following changes/additions: 1: Move the counting of explicit locations to check_explicit_uniform_locations and then pass the number to link_assign_uniform_locations. 2: Count the number of empty slots in UniformRemapTable and store them in a list_head. 3: Try to find an empty slot for implicit locations from the list, if that fails resize UniformRemapTable. Fixes following CTS tests: ES31-CTS.explicit_uniform_location.uniform-loc-mix-with-implicit-max ES31-CTS.explicit_uniform_location.uniform-loc-mix-with-implicit-max-array Signed-off-by: Tapani Pälli Signed-off-by: Plamena Manolova Reviewed-by: Ilia Mirkin Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=93696 --- src/compiler/glsl/link_uniforms.cpp | 80 +++++++++++++++++++++++++---- src/compiler/glsl/linker.cpp | 70 ++++++++++++++++--------- src/compiler/glsl/linker.h | 17 +++++- src/mesa/main/mtypes.h | 8 +++ 4 files changed, 140 insertions(+), 35 deletions(-) diff --git a/src/compiler/glsl/link_uniforms.cpp b/src/compiler/glsl/link_uniforms.cpp index d18a2f2a1bc..deaba94df1c 100644 --- a/src/compiler/glsl/link_uniforms.cpp +++ b/src/compiler/glsl/link_uniforms.cpp @@ -1038,9 +1038,43 @@ assign_hidden_uniform_slot_id(const char *name, unsigned hidden_id, uniform_size->map->put(hidden_uniform_start + hidden_id, name); } +/** + * Search through the list of empty blocks to find one that fits the current + * uniform. + */ +static int +find_empty_block(struct gl_shader_program *prog, + struct gl_uniform_storage *uniform) +{ + const unsigned entries = MAX2(1, uniform->array_elements); + + foreach_list_typed(struct empty_uniform_block, block, link, + &prog->EmptyUniformLocations) { + /* Found a block with enough slots to fit the uniform */ + if (block->slots == entries) { + unsigned start = block->start; + exec_node_remove(&block->link); + ralloc_free(block); + + return start; + /* Found a block with more slots than needed. It can still be used. */ + } else if (block->slots > entries) { + unsigned start = block->start; + block->start += entries; + block->slots -= entries; + + return start; + } + } + + return -1; +} + void link_assign_uniform_locations(struct gl_shader_program *prog, - unsigned int boolean_true) + unsigned int boolean_true, + unsigned int num_explicit_uniform_locs, + unsigned int max_uniform_locs) { ralloc_free(prog->UniformStorage); prog->UniformStorage = NULL; @@ -1131,6 +1165,9 @@ link_assign_uniform_locations(struct gl_shader_program *prog, parcel_out_uniform_storage parcel(prog, prog->UniformHash, uniforms, data); + unsigned total_entries = num_explicit_uniform_locs; + unsigned empty_locs = prog->NumUniformRemapTable - num_explicit_uniform_locs; + for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) { if (prog->_LinkedShaders[i] == NULL) continue; @@ -1194,21 +1231,44 @@ link_assign_uniform_locations(struct gl_shader_program *prog, /* how many new entries for this uniform? */ const unsigned entries = MAX2(1, uniforms[i].array_elements); - /* resize remap table to fit new entries */ - prog->UniformRemapTable = - reralloc(prog, - prog->UniformRemapTable, - gl_uniform_storage *, - prog->NumUniformRemapTable + entries); + /* Find UniformRemapTable for empty blocks where we can fit this uniform. */ + int chosen_location = -1; + + if (empty_locs) + chosen_location = find_empty_block(prog, &uniforms[i]); + + /* Add new entries to the total amount of entries. */ + total_entries += entries; + + if (chosen_location != -1) { + empty_locs -= entries; + } else { + chosen_location = prog->NumUniformRemapTable; + + /* resize remap table to fit new entries */ + prog->UniformRemapTable = + reralloc(prog, + prog->UniformRemapTable, + gl_uniform_storage *, + prog->NumUniformRemapTable + entries); + prog->NumUniformRemapTable += entries; + } /* set pointers for this uniform */ for (unsigned j = 0; j < entries; j++) - prog->UniformRemapTable[prog->NumUniformRemapTable+j] = &uniforms[i]; + prog->UniformRemapTable[chosen_location + j] = &uniforms[i]; /* set the base location in remap table for the uniform */ - uniforms[i].remap_location = prog->NumUniformRemapTable; + uniforms[i].remap_location = chosen_location; + } + + /* Verify that total amount of entries for explicit and implicit locations + * is less than MAX_UNIFORM_LOCATIONS. + */ - prog->NumUniformRemapTable += entries; + if (total_entries > max_uniform_locs) { + linker_error(prog, "count of uniform locations > MAX_UNIFORM_LOCATIONS" + "(%u > %u)", total_entries, max_uniform_locs); } /* Reserve all the explicit locations of the active subroutine uniforms. */ diff --git a/src/compiler/glsl/linker.cpp b/src/compiler/glsl/linker.cpp index bad1c1742b7..5326bfd4d68 100644 --- a/src/compiler/glsl/linker.cpp +++ b/src/compiler/glsl/linker.cpp @@ -3008,12 +3008,13 @@ check_image_resources(struct gl_context *ctx, struct gl_shader_program *prog) * for a variable, checks for overlaps between other uniforms using explicit * locations. */ -static bool +static int reserve_explicit_locations(struct gl_shader_program *prog, string_to_uint_map *map, ir_variable *var) { unsigned slots = var->type->uniform_locations(); 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) { @@ -3024,7 +3025,7 @@ reserve_explicit_locations(struct gl_shader_program *prog, if (!prog->UniformRemapTable) { linker_error(prog, "Out of memory during linking.\n"); - return false; + return -1; } /* Initialize allocated space. */ @@ -3042,8 +3043,10 @@ reserve_explicit_locations(struct gl_shader_program *prog, /* Possibly same uniform from a different stage, this is ok. */ unsigned hash_loc; - if (map->get(hash_loc, var->name) && hash_loc == loc - i) - continue; + if (map->get(hash_loc, var->name) && hash_loc == loc - i) { + return_value = 0; + continue; + } /* ARB_explicit_uniform_location specification states: * @@ -3055,7 +3058,7 @@ reserve_explicit_locations(struct gl_shader_program *prog, "location qualifier for uniform %s overlaps " "previously used location\n", var->name); - return false; + return -1; } /* Initialize location as inactive before optimization @@ -3067,7 +3070,7 @@ reserve_explicit_locations(struct gl_shader_program *prog, /* Note, base location used for arrays. */ map->put(var->data.location, var->name); - return true; + return return_value; } static bool @@ -3128,12 +3131,12 @@ reserve_subroutine_explicit_locations(struct gl_shader_program *prog, * any optimizations happen to handle also inactive uniforms and * inactive array elements that may get trimmed away. */ -static void +static int check_explicit_uniform_locations(struct gl_context *ctx, struct gl_shader_program *prog) { if (!ctx->Extensions.ARB_explicit_uniform_location) - return; + return -1; /* This map is used to detect if overlapping explicit locations * occur with the same uniform (from different stage) or a different one. @@ -3142,7 +3145,7 @@ check_explicit_uniform_locations(struct gl_context *ctx, if (!uniform_map) { linker_error(prog, "Out of memory during linking.\n"); - return; + return -1; } unsigned entries_total = 0; @@ -3157,31 +3160,47 @@ check_explicit_uniform_locations(struct gl_context *ctx, if (!var || var->data.mode != ir_var_uniform) continue; - entries_total += var->type->uniform_locations(); - if (var->data.explicit_location) { - bool ret; + bool ret = false; if (var->type->without_array()->is_subroutine()) ret = reserve_subroutine_explicit_locations(prog, sh, var); - else - ret = reserve_explicit_locations(prog, uniform_map, 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; + return -1; } } } } - /* Verify that total amount of entries for explicit and implicit locations - * is less than MAX_UNIFORM_LOCATIONS. - */ - if (entries_total >= ctx->Const.MaxUserAssignableUniformLocations) { - linker_error(prog, "count of uniform locations >= MAX_UNIFORM_LOCATIONS" - "(%u >= %u)", entries_total, - ctx->Const.MaxUserAssignableUniformLocations); + exec_list_make_empty(&prog->EmptyUniformLocations); + 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) { + /* 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; + exec_list_push_tail(&prog->EmptyUniformLocations, + ¤t_block->link); + } + + /* The current block continues, so we simply increment its slots */ + current_block->slots++; + } } + delete uniform_map; + return entries_total; } static bool @@ -4129,6 +4148,7 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) tfeedback_decl *tfeedback_decls = NULL; unsigned num_tfeedback_decls = prog->TransformFeedback.NumVarying; + unsigned int num_explicit_uniform_locs = 0; void *mem_ctx = ralloc_context(NULL); // temporary linker context @@ -4310,7 +4330,7 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) last = i; } - check_explicit_uniform_locations(ctx, prog); + num_explicit_uniform_locs = check_explicit_uniform_locations(ctx, prog); link_assign_subroutine_types(prog); if (!prog->LinkStatus) @@ -4541,7 +4561,9 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) goto done; update_array_sizes(prog); - link_assign_uniform_locations(prog, ctx->Const.UniformBooleanTrue); + link_assign_uniform_locations(prog, ctx->Const.UniformBooleanTrue, + num_explicit_uniform_locs, + ctx->Const.MaxUserAssignableUniformLocations); link_assign_atomic_counter_resources(ctx, prog); store_fragdepth_layout(prog); diff --git a/src/compiler/glsl/linker.h b/src/compiler/glsl/linker.h index c80be1c7e22..a60bb6ed087 100644 --- a/src/compiler/glsl/linker.h +++ b/src/compiler/glsl/linker.h @@ -35,7 +35,9 @@ link_invalidate_variable_locations(exec_list *ir); extern void link_assign_uniform_locations(struct gl_shader_program *prog, - unsigned int boolean_true); + unsigned int boolean_true, + unsigned int num_explicit_uniform_locs, + unsigned int max_uniform_locs); extern void link_set_uniform_initializers(struct gl_shader_program *prog, @@ -202,4 +204,17 @@ linker_error(gl_shader_program *prog, const char *fmt, ...); void linker_warning(gl_shader_program *prog, const char *fmt, ...); +/** + * Sometimes there are empty slots left over in UniformRemapTable after we + * allocate slots to explicit locations. This struct represents a single + * continouous block of empty slots in UniformRemapTable. + */ +struct empty_uniform_block { + struct exec_node link; + /* The start location of the block */ + unsigned start; + /* The number of slots in the block */ + unsigned slots; +}; + #endif /* GLSL_LINKER_H */ diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h index e5f2da0b3c4..12d3863719b 100644 --- a/src/mesa/main/mtypes.h +++ b/src/mesa/main/mtypes.h @@ -44,6 +44,7 @@ #include "math/m_matrix.h" /* GLmatrix */ #include "compiler/shader_enums.h" #include "main/formats.h" /* MESA_FORMAT_COUNT */ +#include "compiler/glsl/list.h" #ifdef __cplusplus @@ -2770,6 +2771,13 @@ struct gl_shader_program unsigned NumUniformRemapTable; struct gl_uniform_storage **UniformRemapTable; + /** + * Sometimes there are empty slots left over in UniformRemapTable after we + * allocate slots to explicit locations. This list stores the blocks of + * continuous empty slots inside UniformRemapTable. + */ + struct exec_list EmptyUniformLocations; + /** * Size of the gl_ClipDistance array that is output from the last pipeline * stage before the fragment shader. -- 2.30.2