glsl: move uniform calculation to link_uniforms
authorTapani Pälli <tapani.palli@intel.com>
Fri, 15 Jan 2016 11:11:20 +0000 (13:11 +0200)
committerTapani Pälli <tapani.palli@intel.com>
Wed, 20 Jan 2016 05:24:39 +0000 (07:24 +0200)
Patch moves uniform calculation to happen during link_uniforms, this
is possible with help of UniformRemapTable that has all the reserved
locations.

Location assignment for implicit locations is changed so that we
utilize also the 'holes' that explicit uniform location assignment
might have left in UniformRemapTable, this makes it possible to fit
more uniforms as previously we were lazy here and wasting space.

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

v2: code cleanups, increment NumUniformRemapTable correctly, fix
    find_empty_block to work properly and add some more comments.

Signed-off-by: Tapani Pälli <tapani.palli@intel.com>
Reviewed-by: Marta Lofstedt <marta.lofstedt@intel.com>
src/glsl/link_uniforms.cpp
src/glsl/linker.cpp
src/glsl/linker.h

index 33b2d4c8646bd417a8fdd7524208b7b99f6e20ca..76ee70dd400a59562116bcc7f2fff4b9d6b35dad 100644 (file)
@@ -1057,9 +1057,40 @@ assign_hidden_uniform_slot_id(const char *name, unsigned hidden_id,
    uniform_size->map->put(hidden_uniform_start + hidden_id, name);
 }
 
+/**
+ * Search UniformRemapTable for empty block big enough to hold given uniform.
+ * TODO Optimize this algorithm later if it turns out to be a major bottleneck.
+ */
+static int
+find_empty_block(struct gl_shader_program *prog,
+                 struct gl_uniform_storage *uniform)
+{
+   const unsigned entries = MAX2(1, uniform->array_elements);
+   for (unsigned i = 0, j; i < prog->NumUniformRemapTable; i++) {
+      /* We found empty space in UniformRemapTable. */
+      if (prog->UniformRemapTable[i] == NULL) {
+         for (j = i; j < entries && j < prog->NumUniformRemapTable; j++) {
+            if (prog->UniformRemapTable[j] != NULL) {
+               /* Entries do not fit in this space, continue searching
+                * after this location.
+                */
+               i = j + 1;
+               break;
+            }
+         }
+         /* Entries fit, we can return this location. */
+         if (i != j + 1) {
+            return i;
+         }
+      }
+   }
+   return -1;
+}
+
 void
 link_assign_uniform_locations(struct gl_shader_program *prog,
-                              unsigned int boolean_true)
+                              unsigned int boolean_true,
+                              unsigned int max_locations)
 {
    ralloc_free(prog->UniformStorage);
    prog->UniformStorage = NULL;
@@ -1150,6 +1181,20 @@ link_assign_uniform_locations(struct gl_shader_program *prog,
 
    parcel_out_uniform_storage parcel(prog->UniformHash, uniforms, data);
 
+   unsigned total_entries = 0;
+
+   /* Calculate amount of 'holes' left after explicit locations were
+    * reserved from UniformRemapTable.
+    */
+   unsigned empty_locs = 0;
+   for (unsigned i = 0; i < prog->NumUniformRemapTable; i++)
+      if (prog->UniformRemapTable[i] == NULL)
+         empty_locs++;
+
+   /* Add all the reserved explicit locations - empty locations in remap table. */
+   if (prog->NumUniformRemapTable)
+      total_entries = (prog->NumUniformRemapTable - 1) - empty_locs;
+
    for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
       if (prog->_LinkedShaders[i] == NULL)
         continue;
@@ -1213,21 +1258,43 @@ 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]);
+
+      if (chosen_location != -1) {
+         empty_locs -= entries;
+      } else {
+         chosen_location = prog->NumUniformRemapTable;
+
+         /* Add new entries to the total amount of entries. */
+         total_entries += entries;
+
+         /* 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;
+   }
 
-      prog->NumUniformRemapTable += entries;
+    /* Verify that total amount of entries for explicit and implicit locations
+     * is less than MAX_UNIFORM_LOCATIONS.
+     */
+   if (total_entries >= max_locations) {
+      linker_error(prog, "count of uniform locations >= MAX_UNIFORM_LOCATIONS"
+                   "(%u >= %u)", total_entries, max_locations);
    }
 
    /* Reserve all the explicit locations of the active subroutine uniforms. */
index 6657777d74ca40a7bfc7184aec5e2d351bc4b177..5be8d9fc48f32edf657443b5dc0cbc2f963ba33a 100644 (file)
@@ -3146,7 +3146,6 @@ check_explicit_uniform_locations(struct gl_context *ctx,
       return;
    }
 
-   unsigned entries_total = 0;
    for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
       struct gl_shader *sh = prog->_LinkedShaders[i];
 
@@ -3158,8 +3157,6 @@ 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;
             if (var->type->without_array()->is_subroutine())
@@ -3173,15 +3170,6 @@ check_explicit_uniform_locations(struct gl_context *ctx,
          }
       }
    }
-
-   /* 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);
-   }
    delete uniform_map;
 }
 
@@ -4556,7 +4544,12 @@ 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,
+                                 ctx->Const.MaxUserAssignableUniformLocations);
+
+   if (!prog->LinkStatus)
+      goto done;
+
    link_assign_atomic_counter_resources(ctx, prog);
    store_fragdepth_layout(prog);
 
index c80be1c7e226df6671aee507b609ce8be5cee110..76f95c04704e2eed0f4718abeb67b401bcb834dd 100644 (file)
@@ -35,7 +35,8 @@ 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 max_locations);
 
 extern void
 link_set_uniform_initializers(struct gl_shader_program *prog,