glsl: fix spelling of derived
[mesa.git] / src / glsl / link_uniforms.cpp
index 4bd4034a0d6675ce11f2eb41d42c26a4b94c0d53..29dc0b1966c28d4257bcc02572b822c11ed01c6c 100644 (file)
@@ -75,7 +75,63 @@ program_resource_visitor::process(ir_variable *var)
     */
 
    /* Only strdup the name if we actually will need to modify it. */
-   if (t->is_record() || (t->is_array() && t->fields.array->is_record())) {
+   if (var->data.from_named_ifc_block_array) {
+      /* lower_named_interface_blocks created this variable by lowering an
+       * interface block array to an array variable.  For example if the
+       * original source code was:
+       *
+       *     out Blk { vec4 bar } foo[3];
+       *
+       * Then the variable is now:
+       *
+       *     out vec4 bar[3];
+       *
+       * We need to visit each array element using the names constructed like
+       * so:
+       *
+       *     Blk[0].bar
+       *     Blk[1].bar
+       *     Blk[2].bar
+       */
+      assert(t->is_array());
+      const glsl_type *ifc_type = var->get_interface_type();
+      char *name = ralloc_strdup(NULL, ifc_type->name);
+      size_t name_length = strlen(name);
+      for (unsigned i = 0; i < t->length; i++) {
+         size_t new_length = name_length;
+         ralloc_asprintf_rewrite_tail(&name, &new_length, "[%u].%s", i,
+                                      var->name);
+         /* Note: row_major is only meaningful for uniform blocks, and
+          * lowering is only applied to non-uniform interface blocks, so we
+          * can safely pass false for row_major.
+          */
+         recursion(var->type, &name, new_length, false, NULL);
+      }
+      ralloc_free(name);
+   } else if (var->data.from_named_ifc_block_nonarray) {
+      /* lower_named_interface_blocks created this variable by lowering a
+       * named interface block (non-array) to an ordinary variable.  For
+       * example if the original source code was:
+       *
+       *     out Blk { vec4 bar } foo;
+       *
+       * Then the variable is now:
+       *
+       *     out vec4 bar;
+       *
+       * We need to visit this variable using the name:
+       *
+       *     Blk.bar
+       */
+      const glsl_type *ifc_type = var->get_interface_type();
+      char *name = ralloc_asprintf(NULL, "%s.%s", ifc_type->name, var->name);
+      /* Note: row_major is only meaningful for uniform blocks, and lowering
+       * is only applied to non-uniform interface blocks, so we can safely
+       * pass false for row_major.
+       */
+      recursion(var->type, &name, strlen(name), false, NULL);
+      ralloc_free(name);
+   } else if (t->is_record() || (t->is_array() && t->fields.array->is_record())) {
       char *name = ralloc_strdup(NULL, var->name);
       recursion(var->type, &name, strlen(name), false, NULL);
       ralloc_free(name);
@@ -156,7 +212,7 @@ program_resource_visitor::recursion(const glsl_type *t, char **name,
 void
 program_resource_visitor::visit_field(const glsl_type *type, const char *name,
                                       bool row_major,
-                                      const glsl_type *record_type)
+                                      const glsl_type *)
 {
    visit_field(type, name, row_major);
 }
@@ -184,7 +240,8 @@ class count_uniform_size : public program_resource_visitor {
 public:
    count_uniform_size(struct string_to_uint_map *map)
       : num_active_uniforms(0), num_values(0), num_shader_samplers(0),
-       num_shader_uniform_components(0), is_ubo_var(false), map(map)
+        num_shader_images(0), num_shader_uniform_components(0),
+        is_ubo_var(false), map(map)
    {
       /* empty */
    }
@@ -192,6 +249,7 @@ public:
    void start_shader()
    {
       this->num_shader_samplers = 0;
+      this->num_shader_images = 0;
       this->num_shader_uniform_components = 0;
    }
 
@@ -220,6 +278,11 @@ public:
     */
    unsigned num_shader_samplers;
 
+   /**
+    * Number of images used
+    */
+   unsigned num_shader_images;
+
    /**
     * Number of uniforms used in the current shader
     */
@@ -247,6 +310,15 @@ private:
       if (type->contains_sampler()) {
         this->num_shader_samplers +=
            type->is_array() ? type->array_size() : 1;
+      } else if (type->contains_image()) {
+         this->num_shader_images += values;
+
+         /* As drivers are likely to represent image uniforms as
+          * scalar indices, count them against the limit of uniform
+          * components in the default block.  The spec allows image
+          * uniforms to use up no more than one scalar slot.
+          */
+         this->num_shader_uniform_components += values;
       } else {
         /* Accumulate the total number of uniform slots used by this shader.
          * Note that samplers do not count against this limit because they
@@ -300,14 +372,15 @@ public:
    {
    }
 
-   void start_shader(gl_shader_type shader_type)
+   void start_shader(gl_shader_stage shader_type)
    {
-      assert(shader_type < MESA_SHADER_TYPES);
+      assert(shader_type < MESA_SHADER_STAGES);
       this->shader_type = shader_type;
 
       this->shader_samplers_used = 0;
       this->shader_shadow_samplers = 0;
       this->next_sampler = 0;
+      this->next_image = 0;
       memset(this->targets, 0, sizeof(this->targets));
    }
 
@@ -352,10 +425,10 @@ public:
             const struct gl_uniform_block *const block =
                &prog->UniformBlocks[ubo_block_index];
 
-            assert(var->location != -1);
+            assert(var->data.location != -1);
 
             const struct gl_uniform_buffer_variable *const ubo_var =
-               &block->Uniforms[var->location];
+               &block->Uniforms[var->data.location];
 
             ubo_row_major = ubo_var->RowMajor;
             ubo_byte_offset = ubo_var->Offset;
@@ -373,7 +446,7 @@ public:
    int ubo_block_index;
    int ubo_byte_offset;
    bool ubo_row_major;
-   gl_shader_type shader_type;
+   gl_shader_stage shader_type;
 
 private:
    void handle_samplers(const glsl_type *base_type,
@@ -404,6 +477,24 @@ private:
       }
    }
 
+   void handle_images(const glsl_type *base_type,
+                      struct gl_uniform_storage *uniform)
+   {
+      if (base_type->is_image()) {
+         uniform->image[shader_type].index = this->next_image;
+         uniform->image[shader_type].active = true;
+
+         /* Increment the image index by 1 for non-arrays and by the
+          * number of array elements for arrays.
+          */
+         this->next_image += MAX2(1, uniform->array_elements);
+
+      } else {
+         uniform->image[shader_type].index = ~0;
+         uniform->image[shader_type].active = false;
+      }
+   }
+
    virtual void visit_field(const glsl_type *type, const char *name,
                             bool row_major)
    {
@@ -439,8 +530,9 @@ private:
         base_type = type;
       }
 
-      /* This assigns sampler uniforms to sampler units. */
+      /* This assigns uniform indices to sampler and image uniforms. */
       handle_samplers(base_type, &this->uniforms[id]);
+      handle_images(base_type, &this->uniforms[id]);
 
       /* If there is already storage associated with this uniform, it means
        * that it was set while processing an earlier shader stage.  For
@@ -457,6 +549,7 @@ private:
       this->uniforms[id].num_driver_storage = 0;
       this->uniforms[id].driver_storage = NULL;
       this->uniforms[id].storage = this->values;
+      this->uniforms[id].atomic_buffer_index = -1;
       if (this->ubo_block_index != -1) {
         this->uniforms[id].block_index = this->ubo_block_index;
 
@@ -497,6 +590,7 @@ private:
 
    struct gl_uniform_storage *uniforms;
    unsigned next_sampler;
+   unsigned next_image;
 
 public:
    union gl_constant_value *values;
@@ -580,10 +674,10 @@ link_update_uniform_buffer_variables(struct gl_shader *shader)
       if ((var == NULL) || !var->is_in_uniform_block())
         continue;
 
-      assert(var->mode == ir_var_uniform);
+      assert(var->data.mode == ir_var_uniform);
 
       if (var->is_interface_instance()) {
-         var->location = 0;
+         var->data.location = 0;
          continue;
       }
 
@@ -612,13 +706,13 @@ link_update_uniform_buffer_variables(struct gl_shader *shader)
 
                if (strncmp(var->name, begin, l) == 0) {
                   found = true;
-                  var->location = j;
+                  var->data.location = j;
                   break;
                }
             } else if (!strcmp(var->name,
                                shader->UniformBlocks[i].Uniforms[j].Name)) {
               found = true;
-              var->location = j;
+              var->data.location = j;
               break;
            }
         }
@@ -663,6 +757,41 @@ link_assign_uniform_block_offsets(struct gl_shader *shader)
    }
 }
 
+/**
+ * Scan the program for image uniforms and store image unit access
+ * information into the gl_shader data structure.
+ */
+static void
+link_set_image_access_qualifiers(struct gl_shader_program *prog)
+{
+   for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
+      gl_shader *sh = prog->_LinkedShaders[i];
+
+      if (sh == NULL)
+        continue;
+
+      foreach_list(node, sh->ir) {
+        ir_variable *var = ((ir_instruction *) node)->as_variable();
+
+         if (var && var->data.mode == ir_var_uniform &&
+             var->type->contains_image()) {
+            unsigned id = 0;
+            bool found = prog->UniformHash->get(id, var->name);
+            assert(found);
+            (void) found;
+            const gl_uniform_storage *storage = &prog->UniformStorage[id];
+            const unsigned index = storage->image[i].index;
+            const GLenum access = (var->data.image.read_only ? GL_READ_ONLY :
+                                   var->data.image.write_only ? GL_WRITE_ONLY :
+                                   GL_READ_WRITE);
+
+            for (unsigned j = 0; j < MAX2(1, storage->array_elements); ++j)
+               sh->ImageAccess[index + j] = access;
+         }
+      }
+   }
+}
+
 void
 link_assign_uniform_locations(struct gl_shader_program *prog)
 {
@@ -670,6 +799,10 @@ 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 {
@@ -684,7 +817,7 @@ link_assign_uniform_locations(struct gl_shader_program *prog)
     * glGetUniformLocation.
     */
    count_uniform_size uniform_size(prog->UniformHash);
-   for (unsigned i = 0; i < MESA_SHADER_TYPES; i++) {
+   for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
       struct gl_shader *sh = prog->_LinkedShaders[i];
 
       if (sh == NULL)
@@ -700,6 +833,7 @@ link_assign_uniform_locations(struct gl_shader_program *prog)
        *     types cannot have initializers."
        */
       memset(sh->SamplerUnits, 0, sizeof(sh->SamplerUnits));
+      memset(sh->ImageUnits, 0, sizeof(sh->ImageUnits));
 
       link_update_uniform_buffer_variables(sh);
 
@@ -710,7 +844,7 @@ link_assign_uniform_locations(struct gl_shader_program *prog)
       foreach_list(node, sh->ir) {
         ir_variable *const var = ((ir_instruction *) node)->as_variable();
 
-        if ((var == NULL) || (var->mode != ir_var_uniform))
+        if ((var == NULL) || (var->data.mode != ir_var_uniform))
            continue;
 
         /* FINISHME: Update code to process built-in uniforms!
@@ -725,6 +859,7 @@ link_assign_uniform_locations(struct gl_shader_program *prog)
       }
 
       sh->num_samplers = uniform_size.num_shader_samplers;
+      sh->NumImages = uniform_size.num_shader_images;
       sh->num_uniform_components = uniform_size.num_shader_uniform_components;
 
       sh->num_combined_uniform_components = sh->num_uniform_components;
@@ -752,16 +887,16 @@ link_assign_uniform_locations(struct gl_shader_program *prog)
 
    parcel_out_uniform_storage parcel(prog->UniformHash, uniforms, data);
 
-   for (unsigned i = 0; i < MESA_SHADER_TYPES; i++) {
+   for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
       if (prog->_LinkedShaders[i] == NULL)
         continue;
 
-      parcel.start_shader((gl_shader_type)i);
+      parcel.start_shader((gl_shader_stage)i);
 
       foreach_list(node, prog->_LinkedShaders[i]->ir) {
         ir_variable *const var = ((ir_instruction *) node)->as_variable();
 
-        if ((var == NULL) || (var->mode != ir_var_uniform))
+        if ((var == NULL) || (var->data.mode != ir_var_uniform))
            continue;
 
         /* FINISHME: Update code to process built-in uniforms!
@@ -780,19 +915,28 @@ link_assign_uniform_locations(struct gl_shader_program *prog)
              sizeof(prog->_LinkedShaders[i]->SamplerTargets));
    }
 
-   /* Determine the size of the largest uniform array queryable via
-    * glGetUniformLocation.  Using this as the location scale guarantees that
-    * there is enough "room" for the array index to be stored in the low order
-    * part of the uniform location.  It also makes the locations be more
-    * tightly packed.
-    */
-   unsigned max_array_size = 1;
+   /* Build the uniform remap table that is used to set/get uniform locations */
    for (unsigned i = 0; i < num_user_uniforms; i++) {
-      if (uniforms[i].array_elements > max_array_size)
-         max_array_size = uniforms[i].array_elements;
-   }
 
-   prog->UniformLocationBaseScale = max_array_size;
+      /* 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);
+
+      /* set pointers for this uniform */
+      for (unsigned j = 0; j < entries; j++)
+         prog->UniformRemapTable[prog->NumUniformRemapTable+j] = &uniforms[i];
+
+      /* set the base location in remap table for the uniform */
+      uniforms[i].remap_location = prog->NumUniformRemapTable;
+
+      prog->NumUniformRemapTable += entries;
+   }
 
 #ifndef NDEBUG
    for (unsigned i = 0; i < num_user_uniforms; i++) {
@@ -805,6 +949,7 @@ link_assign_uniform_locations(struct gl_shader_program *prog)
    prog->NumUserUniformStorage = num_user_uniforms;
    prog->UniformStorage = uniforms;
 
+   link_set_image_access_qualifiers(prog);
    link_set_uniform_initializers(prog);
 
    return;