glsl/linker: assign explicit uniform locations
authorTapani Pälli <tapani.palli@intel.com>
Thu, 13 Mar 2014 10:48:27 +0000 (12:48 +0200)
committerTapani Pälli <tapani.palli@intel.com>
Mon, 16 Jun 2014 03:49:59 +0000 (06:49 +0300)
Patch refactors the existing uniform processing so explicit locations
are taken in to account during variable processing. These locations
are temporarily stored in gl_uniform_storage before actual locations
are set.

UNMAPPED_UNIFORM_LOC marks unset location so that we can use 0 as a
valid explicit location.

When locations are set, UniformRemapTable is first populated with
uniforms that have explicit location set (inactive and active ones),
rest are put after explicit location slots.

v2: introduce define for locations that have not been set yet (Ian)

Signed-off-by: Tapani Pälli <tapani.palli@intel.com>
Reviewed-by: Ian Romanick <ian.d.romanick@intel.com>
src/glsl/link_uniforms.cpp

index ba66053ed2a5dac684a1d81eda67e0e19431588b..66f6d4db3a5e0bcc5da05994c0068d6627b210a6 100644 (file)
  * \author Ian Romanick <ian.d.romanick@intel.com>
  */
 
+/**
+ * Used by linker to indicate uniforms that have no location set.
+ */
+#define UNMAPPED_UNIFORM_LOC ~0u
+
 /**
  * Count the backing storage requirements for a type
  */
@@ -386,6 +391,9 @@ public:
    void set_and_process(struct gl_shader_program *prog,
                        ir_variable *var)
    {
+      current_var = var;
+      field_counter = 0;
+
       ubo_block_index = -1;
       if (var->is_in_uniform_block()) {
          if (var->is_interface_instance() && var->type->is_array()) {
@@ -542,6 +550,22 @@ private:
          return;
       }
 
+      /* Assign explicit locations. */
+      if (current_var->data.explicit_location) {
+         /* Set sequential locations for struct fields. */
+         if (record_type != NULL) {
+            const unsigned entries = MAX2(1, this->uniforms[id].array_elements);
+            this->uniforms[id].remap_location =
+               current_var->data.location + field_counter;
+            field_counter += entries;
+         } else {
+            this->uniforms[id].remap_location = current_var->data.location;
+         }
+      } else {
+         /* Initialize to to indicate that no location is set */
+         this->uniforms[id].remap_location = UNMAPPED_UNIFORM_LOC;
+      }
+
       this->uniforms[id].name = ralloc_strdup(this->uniforms, name);
       this->uniforms[id].type = base_type;
       this->uniforms[id].initialized = 0;
@@ -596,6 +620,17 @@ public:
 
    gl_texture_index targets[MAX_SAMPLERS];
 
+   /**
+    * Current variable being processed.
+    */
+   ir_variable *current_var;
+
+   /**
+    * Field counter is used to take care that uniform structures
+    * with explicit locations get sequential locations.
+    */
+   unsigned field_counter;
+
    /**
     * Mask of samplers used by the current shader stage.
     */
@@ -798,10 +833,6 @@ link_assign_uniform_locations(struct gl_shader_program *prog)
    prog->UniformStorage = NULL;
    prog->NumUserUniformStorage = 0;
 
-   ralloc_free(prog->UniformRemapTable);
-   prog->UniformRemapTable = NULL;
-   prog->NumUniformRemapTable = 0;
-
    if (prog->UniformHash != NULL) {
       prog->UniformHash->clear();
    } else {
@@ -914,8 +945,28 @@ link_assign_uniform_locations(struct gl_shader_program *prog)
              sizeof(prog->_LinkedShaders[i]->SamplerTargets));
    }
 
-   /* Build the uniform remap table that is used to set/get uniform locations */
+   /* Reserve all the explicit locations of the active uniforms. */
    for (unsigned i = 0; i < num_user_uniforms; i++) {
+      if (uniforms[i].remap_location != UNMAPPED_UNIFORM_LOC) {
+         /* How many new entries for this uniform? */
+         const unsigned entries = MAX2(1, uniforms[i].array_elements);
+
+         /* Set remap table entries point to correct gl_uniform_storage. */
+         for (unsigned j = 0; j < entries; j++) {
+            unsigned element_loc = uniforms[i].remap_location + j;
+            assert(prog->UniformRemapTable[element_loc] ==
+                   INACTIVE_UNIFORM_EXPLICIT_LOCATION);
+            prog->UniformRemapTable[element_loc] = &uniforms[i];
+         }
+      }
+   }
+
+   /* Reserve locations for rest of the uniforms. */
+   for (unsigned i = 0; i < num_user_uniforms; i++) {
+
+      /* Explicit ones have been set already. */
+      if (uniforms[i].remap_location != UNMAPPED_UNIFORM_LOC)
+         continue;
 
       /* how many new entries for this uniform? */
       const unsigned entries = MAX2(1, uniforms[i].array_elements);