nir: Return progress from nir_lower_io().
[mesa.git] / src / compiler / glsl / link_uniforms.cpp
index 40347ac0777609ddb447fdbf6c82087b76687e4b..c29fbed743590d1f05183f49e0954c10fd5635d8 100644 (file)
@@ -28,7 +28,7 @@
 #include "glsl_symbol_table.h"
 #include "program.h"
 #include "util/string_to_uint_map.h"
-#include "ir_variable_refcount.h"
+#include "ir_array_refcount.h"
 
 /**
  * \file link_uniforms.cpp
@@ -45,7 +45,7 @@
 /**
  * Count the backing storage requirements for a type
  */
-static unsigned
+unsigned
 values_for_type(const glsl_type *type)
 {
    if (type->is_sampler()) {
@@ -194,8 +194,10 @@ program_resource_visitor::recursion(const glsl_type *t, char **name,
          record_type = t->fields.array;
 
       unsigned length = t->length;
+
       /* Shader storage block unsized arrays: add subscript [0] to variable
-       * names */
+       * names.
+       */
       if (t->is_unsized_array())
          length = 1;
 
@@ -454,9 +456,9 @@ public:
       buffer_block_index = -1;
       if (var->is_in_buffer_block()) {
          struct gl_uniform_block *blks = var->is_in_shader_storage_block() ?
-            prog->ShaderStorageBlocks : prog->UniformBlocks;
+            prog->data->ShaderStorageBlocks : prog->data->UniformBlocks;
          unsigned num_blks = var->is_in_shader_storage_block() ?
-            prog->NumShaderStorageBlocks : prog->NumUniformBlocks;
+            prog->data->NumShaderStorageBlocks : prog->data->NumUniformBlocks;
 
          if (var->is_interface_instance() && var->type->is_array()) {
             unsigned l = strlen(var->get_interface_type()->name);
@@ -470,8 +472,7 @@ public:
             }
          } else {
             for (unsigned i = 0; i < num_blks; i++) {
-               if (strcmp(var->get_interface_type()->name, blks[i].Name) ==
-                   0) {
+               if (strcmp(var->get_interface_type()->name, blks[i].Name) == 0) {
                   buffer_block_index = i;
                   break;
                }
@@ -534,7 +535,7 @@ private:
             const char *str_end;
             while((str_start = strchr(name_copy, '[')) &&
                   (str_end = strchr(name_copy, ']'))) {
-               memmove(str_start, str_end + 1, 1 + strlen(str_end));
+               memmove(str_start, str_end + 1, 1 + strlen(str_end + 1));
             }
 
             unsigned index = 0;
@@ -612,7 +613,7 @@ private:
          this->next_image += MAX2(1, uniform->array_elements);
 
          for (unsigned i = first; i < MIN2(next_image, MAX_IMAGE_UNIFORMS); i++)
-            prog->_LinkedShaders[shader_type]->ImageAccess[i] = access;
+            prog->_LinkedShaders[shader_type]->Program->sh.ImageAccess[i] = access;
       }
    }
 
@@ -623,6 +624,8 @@ private:
          uniform->opaque[shader_type].index = this->next_subroutine;
          uniform->opaque[shader_type].active = true;
 
+         prog->_LinkedShaders[shader_type]->Program->sh.NumSubroutineUniforms++;
+
          /* Increment the subroutine index by 1 for non-arrays and by the
           * number of array elements for arrays.
           */
@@ -866,11 +869,11 @@ public:
 };
 
 static bool
-variable_is_referenced(ir_variable_refcount_visitor &v, ir_variable *var)
+variable_is_referenced(ir_array_refcount_visitor &v, ir_variable *var)
 {
-   ir_variable_refcount_entry *const entry = v.get_variable_entry(var);
+   ir_array_refcount_entry *const entry = v.get_variable_entry(var);
 
-   return entry->referenced_count > 0;
+   return entry->is_referenced;
 
 }
 
@@ -884,7 +887,7 @@ static void
 link_update_uniform_buffer_variables(struct gl_linked_shader *shader,
                                      unsigned stage)
 {
-   ir_variable_refcount_visitor v;
+   ir_array_refcount_visitor v;
 
    v.run(shader->ir);
 
@@ -898,12 +901,15 @@ link_update_uniform_buffer_variables(struct gl_linked_shader *shader,
              var->data.mode == ir_var_shader_storage);
 
       unsigned num_blocks = var->data.mode == ir_var_uniform ?
-         shader->NumUniformBlocks : shader->NumShaderStorageBlocks;
+         shader->Program->info.num_ubos : shader->Program->info.num_ssbos;
       struct gl_uniform_block **blks = var->data.mode == ir_var_uniform ?
-         shader->UniformBlocks : shader->ShaderStorageBlocks;
+         shader->Program->sh.UniformBlocks :
+         shader->Program->sh.ShaderStorageBlocks;
 
       if (var->is_interface_instance()) {
-         if (variable_is_referenced(v, var)) {
+         const ir_array_refcount_entry *const entry = v.get_variable_entry(var);
+
+         if (entry->is_referenced) {
             /* Since this is an interface instance, the instance type will be
              * same as the array-stripped variable type.  If the variable type
              * is an array, then the block names will be suffixed with [0]
@@ -929,7 +935,9 @@ link_update_uniform_buffer_variables(struct gl_linked_shader *shader,
                 * be an array of instances, and all elements of the array need
                 * to be marked as referenced.
                 */
-               if (strncmp(begin, var->get_interface_type()->name, len) == 0) {
+               if (strncmp(begin, var->get_interface_type()->name, len) == 0 &&
+                   (!var->type->is_array() ||
+                    entry->is_linearized_index_referenced(blks[i]->linearized_array_index))) {
                   blks[i]->stageref |= 1U << stage;
                }
             }
@@ -1034,57 +1042,59 @@ find_empty_block(struct gl_shader_program *prog,
 
 static void
 link_setup_uniform_remap_tables(struct gl_context *ctx,
-                                struct gl_shader_program *prog,
-                                unsigned num_explicit_uniform_locs)
+                                struct gl_shader_program *prog)
 {
-   unsigned total_entries = num_explicit_uniform_locs;
-   unsigned empty_locs =
-      prog->NumUniformRemapTable - num_explicit_uniform_locs;
+   unsigned total_entries = prog->NumExplicitUniformLocations;
+   unsigned empty_locs = prog->NumUniformRemapTable - total_entries;
 
    /* Reserve all the explicit locations of the active uniforms. */
-   for (unsigned i = 0; i < prog->NumUniformStorage; i++) {
-      if (prog->UniformStorage[i].type->is_subroutine() ||
-          prog->UniformStorage[i].is_shader_storage)
+   for (unsigned i = 0; i < prog->data->NumUniformStorage; i++) {
+      if (prog->data->UniformStorage[i].type->is_subroutine() ||
+          prog->data->UniformStorage[i].is_shader_storage)
          continue;
 
-      if (prog->UniformStorage[i].remap_location != UNMAPPED_UNIFORM_LOC) {
+      if (prog->data->UniformStorage[i].remap_location !=
+          UNMAPPED_UNIFORM_LOC) {
          /* How many new entries for this uniform? */
          const unsigned entries =
-            MAX2(1, prog->UniformStorage[i].array_elements);
+            MAX2(1, prog->data->UniformStorage[i].array_elements);
 
          /* Set remap table entries point to correct gl_uniform_storage. */
          for (unsigned j = 0; j < entries; j++) {
-            unsigned element_loc = prog->UniformStorage[i].remap_location + j;
+            unsigned element_loc =
+               prog->data->UniformStorage[i].remap_location + j;
             assert(prog->UniformRemapTable[element_loc] ==
                    INACTIVE_UNIFORM_EXPLICIT_LOCATION);
-            prog->UniformRemapTable[element_loc] = &prog->UniformStorage[i];
+            prog->UniformRemapTable[element_loc] =
+               &prog->data->UniformStorage[i];
          }
       }
    }
 
    /* Reserve locations for rest of the uniforms. */
-   for (unsigned i = 0; i < prog->NumUniformStorage; i++) {
+   for (unsigned i = 0; i < prog->data->NumUniformStorage; i++) {
 
-      if (prog->UniformStorage[i].type->is_subroutine() ||
-          prog->UniformStorage[i].is_shader_storage)
+      if (prog->data->UniformStorage[i].type->is_subroutine() ||
+          prog->data->UniformStorage[i].is_shader_storage)
          continue;
 
       /* Built-in uniforms should not get any location. */
-      if (prog->UniformStorage[i].builtin)
+      if (prog->data->UniformStorage[i].builtin)
          continue;
 
       /* Explicit ones have been set already. */
-      if (prog->UniformStorage[i].remap_location != UNMAPPED_UNIFORM_LOC)
+      if (prog->data->UniformStorage[i].remap_location != UNMAPPED_UNIFORM_LOC)
          continue;
 
       /* how many new entries for this uniform? */
-      const unsigned entries = MAX2(1, prog->UniformStorage[i].array_elements);
+      const unsigned entries =
+         MAX2(1, prog->data->UniformStorage[i].array_elements);
 
       /* Find UniformRemapTable for empty blocks where we can fit this uniform. */
       int chosen_location = -1;
 
       if (empty_locs)
-         chosen_location = find_empty_block(prog, &prog->UniformStorage[i]);
+         chosen_location = find_empty_block(prog, &prog->data->UniformStorage[i]);
 
       /* Add new entries to the total amount of entries. */
       total_entries += entries;
@@ -1106,10 +1116,10 @@ link_setup_uniform_remap_tables(struct gl_context *ctx,
       /* set pointers for this uniform */
       for (unsigned j = 0; j < entries; j++)
          prog->UniformRemapTable[chosen_location + j] =
-            &prog->UniformStorage[i];
+            &prog->data->UniformStorage[i];
 
       /* set the base location in remap table for the uniform */
-      prog->UniformStorage[i].remap_location = chosen_location;
+      prog->data->UniformStorage[i].remap_location = chosen_location;
    }
 
    /* Verify that total amount of entries for explicit and implicit locations
@@ -1123,66 +1133,70 @@ link_setup_uniform_remap_tables(struct gl_context *ctx,
    }
 
    /* Reserve all the explicit locations of the active subroutine uniforms. */
-   for (unsigned i = 0; i < prog->NumUniformStorage; i++) {
-      if (!prog->UniformStorage[i].type->is_subroutine())
+   for (unsigned i = 0; i < prog->data->NumUniformStorage; i++) {
+      if (!prog->data->UniformStorage[i].type->is_subroutine())
          continue;
 
-      if (prog->UniformStorage[i].remap_location == UNMAPPED_UNIFORM_LOC)
+      if (prog->data->UniformStorage[i].remap_location == UNMAPPED_UNIFORM_LOC)
          continue;
 
-      for (unsigned j = 0; j < MESA_SHADER_STAGES; j++) {
-         struct gl_linked_shader *sh = prog->_LinkedShaders[j];
-         if (!sh)
-            continue;
+      /* How many new entries for this uniform? */
+      const unsigned entries =
+         MAX2(1, prog->data->UniformStorage[i].array_elements);
 
-         if (!prog->UniformStorage[i].opaque[j].active)
-            continue;
+      unsigned mask = prog->data->linked_stages;
+      while (mask) {
+         const int j = u_bit_scan(&mask);
+         struct gl_program *p = prog->_LinkedShaders[j]->Program;
 
-         /* How many new entries for this uniform? */
-         const unsigned entries =
-            MAX2(1, prog->UniformStorage[i].array_elements);
+         if (!prog->data->UniformStorage[i].opaque[j].active)
+            continue;
 
          /* Set remap table entries point to correct gl_uniform_storage. */
          for (unsigned k = 0; k < entries; k++) {
-            unsigned element_loc = prog->UniformStorage[i].remap_location + k;
-            assert(sh->SubroutineUniformRemapTable[element_loc] ==
+            unsigned element_loc =
+               prog->data->UniformStorage[i].remap_location + k;
+            assert(p->sh.SubroutineUniformRemapTable[element_loc] ==
                    INACTIVE_UNIFORM_EXPLICIT_LOCATION);
-            sh->SubroutineUniformRemapTable[element_loc] =
-               &prog->UniformStorage[i];
+            p->sh.SubroutineUniformRemapTable[element_loc] =
+               &prog->data->UniformStorage[i];
          }
       }
    }
 
    /* reserve subroutine locations */
-   for (unsigned i = 0; i < prog->NumUniformStorage; i++) {
-
-      if (!prog->UniformStorage[i].type->is_subroutine())
+   for (unsigned i = 0; i < prog->data->NumUniformStorage; i++) {
+      if (!prog->data->UniformStorage[i].type->is_subroutine())
          continue;
-      const unsigned entries = MAX2(1, prog->UniformStorage[i].array_elements);
 
-      if (prog->UniformStorage[i].remap_location != UNMAPPED_UNIFORM_LOC)
+      if (prog->data->UniformStorage[i].remap_location !=
+          UNMAPPED_UNIFORM_LOC)
          continue;
-      for (unsigned j = 0; j < MESA_SHADER_STAGES; j++) {
-         struct gl_linked_shader *sh = prog->_LinkedShaders[j];
-         if (!sh)
-            continue;
 
-         if (!prog->UniformStorage[i].opaque[j].active)
+      const unsigned entries =
+         MAX2(1, prog->data->UniformStorage[i].array_elements);
+
+      unsigned mask = prog->data->linked_stages;
+      while (mask) {
+         const int j = u_bit_scan(&mask);
+         struct gl_program *p = prog->_LinkedShaders[j]->Program;
+
+         if (!prog->data->UniformStorage[i].opaque[j].active)
             continue;
 
-         sh->SubroutineUniformRemapTable =
-            reralloc(sh,
-                     sh->SubroutineUniformRemapTable,
+         p->sh.SubroutineUniformRemapTable =
+            reralloc(p,
+                     p->sh.SubroutineUniformRemapTable,
                      gl_uniform_storage *,
-                     sh->NumSubroutineUniformRemapTable + entries);
+                     p->sh.NumSubroutineUniformRemapTable + entries);
 
          for (unsigned k = 0; k < entries; k++) {
-            sh->SubroutineUniformRemapTable[sh->NumSubroutineUniformRemapTable + k] =
-               &prog->UniformStorage[i];
+            p->sh.SubroutineUniformRemapTable[p->sh.NumSubroutineUniformRemapTable + k] =
+               &prog->data->UniformStorage[i];
          }
-         prog->UniformStorage[i].remap_location =
-            sh->NumSubroutineUniformRemapTable;
-         sh->NumSubroutineUniformRemapTable += entries;
+         prog->data->UniformStorage[i].remap_location =
+            p->sh.NumSubroutineUniformRemapTable;
+         p->sh.NumSubroutineUniformRemapTable += entries;
       }
    }
 }
@@ -1190,27 +1204,32 @@ link_setup_uniform_remap_tables(struct gl_context *ctx,
 static void
 link_assign_uniform_storage(struct gl_context *ctx,
                             struct gl_shader_program *prog,
-                            const unsigned num_data_slots,
-                            unsigned num_explicit_uniform_locs)
+                            const unsigned num_data_slots)
 {
    /* On the outside chance that there were no uniforms, bail out.
     */
-   if (prog->NumUniformStorage == 0)
+   if (prog->data->NumUniformStorage == 0)
       return;
 
    unsigned int boolean_true = ctx->Const.UniformBooleanTrue;
 
-   prog->UniformStorage = rzalloc_array(prog, struct gl_uniform_storage,
-                                        prog->NumUniformStorage);
-   union gl_constant_value *data = rzalloc_array(prog->UniformStorage,
-                                                 union gl_constant_value,
-                                                 num_data_slots);
+   union gl_constant_value *data;
+   if (prog->data->UniformStorage == NULL) {
+      prog->data->UniformStorage = rzalloc_array(prog,
+                                                 struct gl_uniform_storage,
+                                                 prog->data->NumUniformStorage);
+      data = rzalloc_array(prog->data->UniformStorage,
+                           union gl_constant_value, num_data_slots);
+   } else {
+      data = prog->data->UniformDataSlots;
+   }
+
 #ifndef NDEBUG
    union gl_constant_value *data_end = &data[num_data_slots];
 #endif
 
    parcel_out_uniform_storage parcel(prog, prog->UniformHash,
-                                     prog->UniformStorage, data);
+                                     prog->data->UniformStorage, data);
 
    for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
       if (prog->_LinkedShaders[i] == NULL)
@@ -1228,39 +1247,53 @@ link_assign_uniform_storage(struct gl_context *ctx,
          parcel.set_and_process(var);
       }
 
-      prog->_LinkedShaders[i]->active_samplers = parcel.shader_samplers_used;
+      prog->_LinkedShaders[i]->Program->SamplersUsed =
+         parcel.shader_samplers_used;
       prog->_LinkedShaders[i]->shadow_samplers = parcel.shader_shadow_samplers;
 
-      STATIC_ASSERT(sizeof(prog->_LinkedShaders[i]->SamplerTargets) ==
+      STATIC_ASSERT(sizeof(prog->_LinkedShaders[i]->Program->sh.SamplerTargets) ==
                     sizeof(parcel.targets));
-      memcpy(prog->_LinkedShaders[i]->SamplerTargets, parcel.targets,
-             sizeof(prog->_LinkedShaders[i]->SamplerTargets));
+      memcpy(prog->_LinkedShaders[i]->Program->sh.SamplerTargets,
+             parcel.targets,
+             sizeof(prog->_LinkedShaders[i]->Program->sh.SamplerTargets));
    }
 
+   /* If this is a fallback compile for a cache miss we already have the
+    * correct uniform mappings and we don't want to reinitialise uniforms so
+    * just return now.
+    */
+   if (prog->data->cache_fallback)
+      return;
+
 #ifndef NDEBUG
-   for (unsigned i = 0; i < prog->NumUniformStorage; i++) {
-      assert(prog->UniformStorage[i].storage != NULL ||
-             prog->UniformStorage[i].builtin ||
-             prog->UniformStorage[i].is_shader_storage ||
-             prog->UniformStorage[i].block_index != -1);
+   for (unsigned i = 0; i < prog->data->NumUniformStorage; i++) {
+      assert(prog->data->UniformStorage[i].storage != NULL ||
+             prog->data->UniformStorage[i].builtin ||
+             prog->data->UniformStorage[i].is_shader_storage ||
+             prog->data->UniformStorage[i].block_index != -1);
    }
 
    assert(parcel.values == data_end);
 #endif
 
-   link_setup_uniform_remap_tables(ctx, prog, num_explicit_uniform_locs);
+   link_setup_uniform_remap_tables(ctx, prog);
+
+   /* Set shader cache fields */
+   prog->data->NumUniformDataSlots = num_data_slots;
+   prog->data->UniformDataSlots = data;
 
    link_set_uniform_initializers(prog, boolean_true);
 }
 
 void
 link_assign_uniform_locations(struct gl_shader_program *prog,
-                              struct gl_context *ctx,
-                              unsigned int num_explicit_uniform_locs)
+                              struct gl_context *ctx)
 {
-   ralloc_free(prog->UniformStorage);
-   prog->UniformStorage = NULL;
-   prog->NumUniformStorage = 0;
+   if (!prog->data->cache_fallback) {
+      ralloc_free(prog->data->UniformStorage);
+      prog->data->UniformStorage = NULL;
+      prog->data->NumUniformStorage = 0;
+   }
 
    if (prog->UniformHash != NULL) {
       prog->UniformHash->clear();
@@ -1283,18 +1316,6 @@ link_assign_uniform_locations(struct gl_shader_program *prog,
       if (sh == NULL)
          continue;
 
-      /* Uniforms that lack an initializer in the shader code have an initial
-       * value of zero.  This includes sampler uniforms.
-       *
-       * Page 24 (page 30 of the PDF) of the GLSL 1.20 spec says:
-       *
-       *     "The link time initial value is either the value of the variable's
-       *     initializer, if present, or 0 if no initializer is present. Sampler
-       *     types cannot have initializers."
-       */
-      memset(sh->SamplerUnits, 0, sizeof(sh->SamplerUnits));
-      memset(sh->ImageUnits, 0, sizeof(sh->ImageUnits));
-
       link_update_uniform_buffer_variables(sh, i);
 
       /* Reset various per-shader target counts.
@@ -1311,24 +1332,23 @@ link_assign_uniform_locations(struct gl_shader_program *prog,
          uniform_size.process(var);
       }
 
-      sh->num_samplers = uniform_size.num_shader_samplers;
-      sh->NumImages = uniform_size.num_shader_images;
+      sh->Program->info.num_textures = uniform_size.num_shader_samplers;
+      sh->Program->info.num_images = uniform_size.num_shader_images;
       sh->num_uniform_components = uniform_size.num_shader_uniform_components;
       sh->num_combined_uniform_components = sh->num_uniform_components;
 
-      for (unsigned i = 0; i < sh->NumUniformBlocks; i++) {
+      for (unsigned i = 0; i < sh->Program->info.num_ubos; i++) {
          sh->num_combined_uniform_components +=
-            sh->UniformBlocks[i]->UniformBufferSize / 4;
+            sh->Program->sh.UniformBlocks[i]->UniformBufferSize / 4;
       }
    }
 
-   prog->NumUniformStorage = uniform_size.num_active_uniforms;
-   prog->NumHiddenUniforms = uniform_size.num_hidden_uniforms;
+   prog->data->NumUniformStorage = uniform_size.num_active_uniforms;
+   prog->data->NumHiddenUniforms = uniform_size.num_hidden_uniforms;
 
    /* assign hidden uniforms a slot id */
    hiddenUniforms->iterate(assign_hidden_uniform_slot_id, &uniform_size);
    delete hiddenUniforms;
 
-   link_assign_uniform_storage(ctx, prog, uniform_size.num_values,
-                               num_explicit_uniform_locs);
+   link_assign_uniform_storage(ctx, prog, uniform_size.num_values);
 }