<div dir="ltr">Thank you for the review. You're absolutely right, I'll go ahead fix this.</div><div class="gmail_extra"><br><div class="gmail_quote">On Thu, Feb 11, 2016 at 6:39 PM, Ilia Mirkin <span dir="ltr"><<a href="mailto:imirkin@alum.mit.edu" target="_blank">imirkin@alum.mit.edu</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="HOEnZb"><div class="h5">On Thu, Feb 11, 2016 at 11:31 AM, Plamena Manolova<br>
<<a href="mailto:plamena.manolova@intel.com">plamena.manolova@intel.com</a>> wrote:<br>
> This patch moves the calculation of current uniforms to<br>
> link_uniforms, which makes use of UniformRemapTable which<br>
> stores all the reserved uniform locations.<br>
><br>
> Location assignment for implicit uniforms now tries to use<br>
> any gaps left in the table after the location assignment<br>
> for explicit uniforms. This gives us more space to store more<br>
> uniforms.<br>
><br>
> Patch is based on earlier patch with following changes/additions:<br>
><br>
>    1: Move the counting of explicit locations to<br>
>       check_explicit_uniform_locations and then pass<br>
>       the number to link_assign_uniform_locations.<br>
>    2: Count the number of empty slots in UniformRemapTable<br>
>       and store them in a list_head.<br>
>    3: Try to find an empty slot for implicit locations from<br>
>       the list, if that fails resize UniformRemapTable.<br>
><br>
> Fixes following CTS tests:<br>
>    ES31-CTS.explicit_uniform_location.uniform-loc-mix-with-implicit-max<br>
>    ES31-CTS.explicit_uniform_location.uniform-loc-mix-with-implicit-max-array<br>
><br>
> Signed-off-by: Tapani Pälli <<a href="mailto:tapani.palli@intel.com">tapani.palli@intel.com</a>><br>
> Signed-off-by: Plamena Manolova <<a href="mailto:plamena.manolova@intel.com">plamena.manolova@intel.com</a>><br>
> Bugzilla: <a href="https://bugs.freedesktop.org/show_bug.cgi?id=93696" rel="noreferrer" target="_blank">https://bugs.freedesktop.org/show_bug.cgi?id=93696</a><br>
> ---<br>
>  src/compiler/glsl/link_uniforms.cpp | 79 ++++++++++++++++++++++++++++++++-----<br>
>  src/compiler/glsl/linker.cpp        | 78 +++++++++++++++++++++++++-----------<br>
>  src/compiler/glsl/linker.h          | 17 +++++++-<br>
>  src/mesa/main/mtypes.h              |  8 ++++<br>
>  4 files changed, 147 insertions(+), 35 deletions(-)<br>
><br>
> diff --git a/src/compiler/glsl/link_uniforms.cpp b/src/compiler/glsl/link_uniforms.cpp<br>
> index 7072c16..8192c21 100644<br>
> --- a/src/compiler/glsl/link_uniforms.cpp<br>
> +++ b/src/compiler/glsl/link_uniforms.cpp<br>
> @@ -1038,9 +1038,36 @@ assign_hidden_uniform_slot_id(const char *name, unsigned hidden_id,<br>
>     uniform_size->map->put(hidden_uniform_start + hidden_id, name);<br>
>  }<br>
><br>
> +/**<br>
> + * Search through the list of empty blocks to find one that fits the current<br>
> + * uniform.<br>
> + */<br>
> +static int<br>
> +find_empty_block(struct gl_shader_program *prog,<br>
> +                 struct gl_uniform_storage *uniform)<br>
> +{<br>
> +   const unsigned entries = MAX2(1, uniform->array_elements);<br>
> +<br>
> +   list_for_each_entry_safe(struct empty_uniform_block, block,<br>
> +                            &prog->EmptyUniformLocations, link) {<br>
> +      /* Found a block with enough slots to fit the uniform */<br>
> +      if (block->slots == entries) {<br>
<br>
</div></div>I haven't fully absorbed this patch, but if you have a bunch of holes<br>
of 2 slots and then you try to allocate something needing 1 slot, then<br>
you'll never decide you have a free block right? I think this needs to<br>
be<br>
<br>
block->slots >= entries<br>
<br>
and then<br>
<br>
if (block->slots > entries) {<br>
  block->slots -= entries;<br>
  block->start += entries;<br>
} else {<br>
  list_del(&block->link);<br>
  ralloc_free(block);<br>
}<br>
<br>
Or am I misunderstanding something? This sort of greedy approach<br>
doesn't guarantee optimal packing, you could do something much fancier<br>
involving dynamic programming, but that hardly seems necessary.<br>
<div><div class="h5"><br>
> +         unsigned start = block->start;<br>
> +         list_del(&block->link);<br>
> +         ralloc_free(block);<br>
> +<br>
> +         return start;<br>
> +      }<br>
> +   }<br>
> +<br>
> +   return -1;<br>
> +}<br>
> +<br>
>  void<br>
>  link_assign_uniform_locations(struct gl_shader_program *prog,<br>
> -                              unsigned int boolean_true)<br>
> +                              unsigned int boolean_true,<br>
> +                              unsigned int num_explicit_uniform_locs,<br>
> +                              unsigned int max_uniform_locs)<br>
>  {<br>
>     ralloc_free(prog->UniformStorage);<br>
>     prog->UniformStorage = NULL;<br>
> @@ -1131,6 +1158,9 @@ link_assign_uniform_locations(struct gl_shader_program *prog,<br>
><br>
>     parcel_out_uniform_storage parcel(prog, prog->UniformHash, uniforms, data);<br>
><br>
> +   unsigned total_entries = num_explicit_uniform_locs;<br>
> +   unsigned empty_locs = prog->NumUniformRemapTable - num_explicit_uniform_locs;<br>
> +<br>
>     for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {<br>
>        if (prog->_LinkedShaders[i] == NULL)<br>
>          continue;<br>
> @@ -1194,21 +1224,43 @@ link_assign_uniform_locations(struct gl_shader_program *prog,<br>
>        /* how many new entries for this uniform? */<br>
>        const unsigned entries = MAX2(1, uniforms[i].array_elements);<br>
><br>
> -      /* resize remap table to fit new entries */<br>
> -      prog->UniformRemapTable =<br>
> -         reralloc(prog,<br>
> -                  prog->UniformRemapTable,<br>
> -                  gl_uniform_storage *,<br>
> -                  prog->NumUniformRemapTable + entries);<br>
> +      /* Find UniformRemapTable for empty blocks where we can fit this uniform. */<br>
> +      int chosen_location = -1;<br>
> +<br>
> +      if (empty_locs)<br>
> +         chosen_location = find_empty_block(prog, &uniforms[i]);<br>
> +<br>
> +      if (chosen_location != -1) {<br>
> +         empty_locs -= entries;<br>
> +      } else {<br>
> +         chosen_location = prog->NumUniformRemapTable;<br>
> +<br>
> +         /* Add new entries to the total amount of entries. */<br>
> +         total_entries += entries;<br>
> +<br>
> +         /* resize remap table to fit new entries */<br>
> +         prog->UniformRemapTable =<br>
> +            reralloc(prog,<br>
> +                     prog->UniformRemapTable,<br>
> +                     gl_uniform_storage *,<br>
> +                     prog->NumUniformRemapTable + entries);<br>
> +         prog->NumUniformRemapTable += entries;<br>
> +      }<br>
><br>
>        /* set pointers for this uniform */<br>
>        for (unsigned j = 0; j < entries; j++)<br>
> -         prog->UniformRemapTable[prog->NumUniformRemapTable+j] = &uniforms[i];<br>
> +         prog->UniformRemapTable[chosen_location + j] = &uniforms[i];<br>
><br>
>        /* set the base location in remap table for the uniform */<br>
> -      uniforms[i].remap_location = prog->NumUniformRemapTable;<br>
> +      uniforms[i].remap_location = chosen_location;<br>
> +   }<br>
><br>
> -      prog->NumUniformRemapTable += entries;<br>
> +   /* Verify that total amount of entries for explicit and implicit locations<br>
> +    * is less than MAX_UNIFORM_LOCATIONS.<br>
> +    */<br>
> +   if (total_entries >= max_uniform_locs) {<br>
> +      linker_error(prog, "count of uniform locations >= MAX_UNIFORM_LOCATIONS"<br>
> +                   "(%u >= %u)", total_entries, max_uniform_locs);<br>
>     }<br>
><br>
>     /* Reserve all the explicit locations of the active subroutine uniforms. */<br>
> @@ -1284,5 +1336,12 @@ link_assign_uniform_locations(struct gl_shader_program *prog,<br>
><br>
>     link_set_uniform_initializers(prog, boolean_true);<br>
><br>
> +   list_for_each_entry_safe(struct empty_uniform_block, block,<br>
> +                            &prog->EmptyUniformLocations, link) {<br>
> +      ralloc_free(block);<br>
> +   }<br>
> +<br>
> +   list_inithead(&prog->EmptyUniformLocations);<br>
> +<br>
>     return;<br>
>  }<br>
> diff --git a/src/compiler/glsl/linker.cpp b/src/compiler/glsl/linker.cpp<br>
> index bad1c17..cbbb6f1 100644<br>
> --- a/src/compiler/glsl/linker.cpp<br>
> +++ b/src/compiler/glsl/linker.cpp<br>
> @@ -3008,12 +3008,13 @@ check_image_resources(struct gl_context *ctx, struct gl_shader_program *prog)<br>
>   * for a variable, checks for overlaps between other uniforms using explicit<br>
>   * locations.<br>
>   */<br>
> -static bool<br>
> +static int<br>
>  reserve_explicit_locations(struct gl_shader_program *prog,<br>
>                             string_to_uint_map *map, ir_variable *var)<br>
>  {<br>
>     unsigned slots = var->type->uniform_locations();<br>
>     unsigned max_loc = var->data.location + slots - 1;<br>
> +   unsigned return_value = slots;<br>
><br>
>     /* Resize remap table if locations do not fit in the current one. */<br>
>     if (max_loc + 1 > prog->NumUniformRemapTable) {<br>
> @@ -3024,7 +3025,7 @@ reserve_explicit_locations(struct gl_shader_program *prog,<br>
><br>
>        if (!prog->UniformRemapTable) {<br>
>           linker_error(prog, "Out of memory during linking.\n");<br>
> -         return false;<br>
> +         return -1;<br>
>        }<br>
><br>
>        /* Initialize allocated space. */<br>
> @@ -3042,8 +3043,10 @@ reserve_explicit_locations(struct gl_shader_program *prog,<br>
><br>
>           /* Possibly same uniform from a different stage, this is ok. */<br>
>           unsigned hash_loc;<br>
> -         if (map->get(hash_loc, var->name) && hash_loc == loc - i)<br>
> -               continue;<br>
> +         if (map->get(hash_loc, var->name) && hash_loc == loc - i) {<br>
> +            return_value = 0;<br>
> +            continue;<br>
> +         }<br>
><br>
>           /* ARB_explicit_uniform_location specification states:<br>
>            *<br>
> @@ -3055,7 +3058,7 @@ reserve_explicit_locations(struct gl_shader_program *prog,<br>
>                        "location qualifier for uniform %s overlaps "<br>
>                        "previously used location\n",<br>
>                        var->name);<br>
> -         return false;<br>
> +         return -1;<br>
>        }<br>
><br>
>        /* Initialize location as inactive before optimization<br>
> @@ -3067,7 +3070,7 @@ reserve_explicit_locations(struct gl_shader_program *prog,<br>
>     /* Note, base location used for arrays. */<br>
>     map->put(var->data.location, var->name);<br>
><br>
> -   return true;<br>
> +   return return_value;<br>
>  }<br>
><br>
>  static bool<br>
> @@ -3128,12 +3131,12 @@ reserve_subroutine_explicit_locations(struct gl_shader_program *prog,<br>
>   * any optimizations happen to handle also inactive uniforms and<br>
>   * inactive array elements that may get trimmed away.<br>
>   */<br>
> -static void<br>
> +static int<br>
>  check_explicit_uniform_locations(struct gl_context *ctx,<br>
>                                   struct gl_shader_program *prog)<br>
>  {<br>
>     if (!ctx->Extensions.ARB_explicit_uniform_location)<br>
> -      return;<br>
> +      return -1;<br>
><br>
>     /* This map is used to detect if overlapping explicit locations<br>
>      * occur with the same uniform (from different stage) or a different one.<br>
> @@ -3142,7 +3145,7 @@ check_explicit_uniform_locations(struct gl_context *ctx,<br>
><br>
>     if (!uniform_map) {<br>
>        linker_error(prog, "Out of memory during linking.\n");<br>
> -      return;<br>
> +      return -1;<br>
>     }<br>
><br>
>     unsigned entries_total = 0;<br>
> @@ -3157,31 +3160,55 @@ check_explicit_uniform_locations(struct gl_context *ctx,<br>
>           if (!var || var->data.mode != ir_var_uniform)<br>
>              continue;<br>
><br>
> -         entries_total += var->type->uniform_locations();<br>
> -<br>
>           if (var->data.explicit_location) {<br>
> -            bool ret;<br>
> +            bool ret = false;<br>
>              if (var->type->without_array()->is_subroutine())<br>
>                 ret = reserve_subroutine_explicit_locations(prog, sh, var);<br>
> -            else<br>
> -               ret = reserve_explicit_locations(prog, uniform_map, var);<br>
> +            else {<br>
> +               int slots = reserve_explicit_locations(prog, uniform_map,<br>
> +                                                      var);<br>
> +               if (slots != -1) {<br>
> +                  ret = true;<br>
> +                  entries_total += slots;<br>
> +               }<br>
> +            }<br>
>              if (!ret) {<br>
>                 delete uniform_map;<br>
> -               return;<br>
> +               return -1;<br>
>              }<br>
>           }<br>
>        }<br>
>     }<br>
><br>
> -   /* Verify that total amount of entries for explicit and implicit locations<br>
> -    * is less than MAX_UNIFORM_LOCATIONS.<br>
> -    */<br>
> -   if (entries_total >= ctx->Const.MaxUserAssignableUniformLocations) {<br>
> -      linker_error(prog, "count of uniform locations >= MAX_UNIFORM_LOCATIONS"<br>
> -                   "(%u >= %u)", entries_total,<br>
> -                   ctx->Const.MaxUserAssignableUniformLocations);<br>
> +   if (entries_total > 0)<br>
> +      entries_total -= 1;<br>
> +<br>
> +   list_inithead(&prog->EmptyUniformLocations);<br>
> +<br>
> +   struct empty_uniform_block *current_block = NULL;<br>
> +   unsigned prev_location = -1;<br>
> +<br>
> +   for (unsigned i = 0; i < prog->NumUniformRemapTable; i++) {<br>
> +      /* We found empty space in UniformRemapTable. */<br>
> +      if (prog->UniformRemapTable[i] == NULL) {<br>
> +         /* We've found the beginning of new continous block of empty slots */<br>
> +         if ((i == 0) || !current_block || (i != prev_location + 1)) {<br>
> +            current_block = ralloc(NULL, struct empty_uniform_block);<br>
> +            current_block->start = i;<br>
> +            current_block->slots = 1;<br>
> +            list_addtail(&current_block->link, &prog->EmptyUniformLocations);<br>
> +            prev_location = i;<br>
> +            continue;<br>
> +         }<br>
> +<br>
> +         /* The current block continues, so we simply increment its slots */<br>
> +         current_block->slots++;<br>
> +         prev_location = i;<br>
> +      }<br>
>     }<br>
> +<br>
>     delete uniform_map;<br>
> +   return entries_total;<br>
>  }<br>
><br>
>  static bool<br>
> @@ -4129,6 +4156,7 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)<br>
><br>
>     tfeedback_decl *tfeedback_decls = NULL;<br>
>     unsigned num_tfeedback_decls = prog->TransformFeedback.NumVarying;<br>
> +   unsigned int num_explicit_uniform_locs = 0;<br>
><br>
>     void *mem_ctx = ralloc_context(NULL); // temporary linker context<br>
><br>
> @@ -4310,7 +4338,7 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)<br>
>        last = i;<br>
>     }<br>
><br>
> -   check_explicit_uniform_locations(ctx, prog);<br>
> +   num_explicit_uniform_locs = check_explicit_uniform_locations(ctx, prog);<br>
>     link_assign_subroutine_types(prog);<br>
><br>
>     if (!prog->LinkStatus)<br>
> @@ -4541,7 +4569,9 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)<br>
>        goto done;<br>
><br>
>     update_array_sizes(prog);<br>
> -   link_assign_uniform_locations(prog, ctx->Const.UniformBooleanTrue);<br>
> +   link_assign_uniform_locations(prog, ctx->Const.UniformBooleanTrue,<br>
> +                                 num_explicit_uniform_locs,<br>
> +                                 ctx->Const.MaxUserAssignableUniformLocations);<br>
>     link_assign_atomic_counter_resources(ctx, prog);<br>
>     store_fragdepth_layout(prog);<br>
><br>
> diff --git a/src/compiler/glsl/linker.h b/src/compiler/glsl/linker.h<br>
> index c80be1c..9f1fa3e 100644<br>
> --- a/src/compiler/glsl/linker.h<br>
> +++ b/src/compiler/glsl/linker.h<br>
> @@ -35,7 +35,9 @@ link_invalidate_variable_locations(exec_list *ir);<br>
><br>
>  extern void<br>
>  link_assign_uniform_locations(struct gl_shader_program *prog,<br>
> -                              unsigned int boolean_true);<br>
> +                              unsigned int boolean_true,<br>
> +                              unsigned int num_explicit_uniform_locs,<br>
> +                              unsigned int max_uniform_locs);<br>
><br>
>  extern void<br>
>  link_set_uniform_initializers(struct gl_shader_program *prog,<br>
> @@ -202,4 +204,17 @@ linker_error(gl_shader_program *prog, const char *fmt, ...);<br>
>  void<br>
>  linker_warning(gl_shader_program *prog, const char *fmt, ...);<br>
><br>
> +/**<br>
> + * Sometimes there are empty slots left over in UniformRemapTable after we<br>
> + * allocate slots to explicit locations. This struct represents a single<br>
> + * continouous block of empty slots in UniformRemapTable.<br>
> + */<br>
> +struct empty_uniform_block {<br>
> +   struct list_head link;<br>
> +   /* The start location of the block */<br>
> +   unsigned start;<br>
> +   /* The number of slots in the block */<br>
> +   unsigned slots;<br>
> +};<br>
> +<br>
>  #endif /* GLSL_LINKER_H */<br>
> diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h<br>
> index e987177..fcc9017 100644<br>
> --- a/src/mesa/main/mtypes.h<br>
> +++ b/src/mesa/main/mtypes.h<br>
> @@ -44,6 +44,7 @@<br>
>  #include "math/m_matrix.h"     /* GLmatrix */<br>
>  #include "compiler/shader_enums.h"<br>
>  #include "main/formats.h"       /* MESA_FORMAT_COUNT */<br>
> +#include "util/list.h"<br>
><br>
><br>
>  #ifdef __cplusplus<br>
> @@ -2764,6 +2765,13 @@ struct gl_shader_program<br>
>     struct gl_uniform_storage **UniformRemapTable;<br>
><br>
>     /**<br>
> +    * Sometimes there are empty slots left over in UniformRemapTable after we<br>
> +    * allocate slots to explicit locations. This list stores the blocks of<br>
> +    * continuous empty slots inside UniformRemapTable.<br>
> +    */<br>
> +   struct list_head EmptyUniformLocations;<br>
> +<br>
> +   /**<br>
>      * Size of the gl_ClipDistance array that is output from the last pipeline<br>
>      * stage before the fragment shader.<br>
>      */<br>
> --<br>
> 2.4.3<br>
><br>
> ---------------------------------------------------------------------<br>
> Intel Corporation (UK) Limited<br>
> Registered No. 1134945 (England)<br>
> Registered Office: Pipers Way, Swindon SN3 1RJ<br>
> VAT No: 860 2173 47<br>
><br>
> This e-mail and any attachments may contain confidential material for<br>
> the sole use of the intended recipient(s). Any review or distribution<br>
> by others is strictly prohibited. If you are not the intended<br>
> recipient, please contact the sender and delete all copies.<br>
</div></div>> _______________________________________________<br>
> mesa-dev mailing list<br>
> <a href="mailto:mesa-dev@lists.freedesktop.org">mesa-dev@lists.freedesktop.org</a><br>
> <a href="https://lists.freedesktop.org/mailman/listinfo/mesa-dev" rel="noreferrer" target="_blank">https://lists.freedesktop.org/mailman/listinfo/mesa-dev</a><br>
<div class="HOEnZb"><div class="h5">---------------------------------------------------------------------<br>
Intel Corporation (UK) Limited<br>
Registered No. 1134945 (England)<br>
Registered Office: Pipers Way, Swindon SN3 1RJ<br>
VAT No: 860 2173 47<br>
<br>
This e-mail and any attachments may contain confidential material for<br>
the sole use of the intended recipient(s). Any review or distribution<br>
by others is strictly prohibited. If you are not the intended<br>
recipient, please contact the sender and delete all copies.<br>
</div></div></blockquote></div><br></div>