nir: add nir_var_shader_storage
[mesa.git] / src / glsl / nir / nir_lower_samplers.cpp
index e10456db2302d6b9896cb6a0c35f3c7e39498eec..7a0b0a09ffeb7dad0b11e8fc7d53a96cd22ba4e9 100644 (file)
@@ -36,102 +36,106 @@ extern "C" {
 }
 
 static unsigned
-get_deref_name_offset(nir_deref_var *deref_var,
-                      gl_shader_program *shader_program, char **name,
-                      void *mem_ctx)
+get_sampler_index(const struct gl_shader_program *shader_program,
+                  gl_shader_stage stage, const char *name)
 {
-   nir_deref *deref = &deref_var->deref;
-   nir_deref_array *deref_array;
-   nir_deref_struct *deref_struct;
-
-   *name = ralloc_strdup(mem_ctx, deref_var->var->name);
-
-   while (deref->child != NULL) {
-      deref = deref->child;
-      switch (deref->deref_type) {
-         case nir_deref_type_array:
-            deref_array = nir_deref_as_array(deref);
-            if (deref_array->has_indirect) {
-               /* GLSL 1.10 and 1.20 allowed variable sampler array indices,
-                * while GLSL 1.30 requires that the array indices be
-                * constant integer expressions.  We don't expect any driver
-                * to actually work with a really variable array index, so
-                * all that would work would be an unrolled loop counter that
-                * ends up being constant.
-                */
-               ralloc_strcat(&shader_program->InfoLog,
-                           "warning: Variable sampler array index unsupported.\n"
-                           "This feature of the language was removed in GLSL 1.20 "
-                           "and is unlikely to be supported for 1.10 in Mesa.\n");
-            }
-            if (deref->child == NULL) {
-               return deref_array->base_offset;
-            }
-            ralloc_asprintf_append(name, "[%u]", deref_array->base_offset);
-            break;
-
-         case nir_deref_type_struct:
-            deref_struct = nir_deref_as_struct(deref);
-            ralloc_asprintf_append(name, ".%s", deref_struct->elem);
-            break;
-
-         default:
-            assert(0);
-            break;
-      }
-   }
-
-   return 0;
-}
-
-static unsigned
-get_sampler_index(nir_deref_var *sampler,
-                  struct gl_shader_program *shader_program,
-                  const struct gl_program *prog)
-{
-   void *mem_ctx = ralloc_context(NULL);
-   char *name;
-   unsigned offset = get_deref_name_offset(sampler, shader_program, &name,
-                                           mem_ctx);
-
-   GLuint shader = _mesa_program_enum_to_shader_stage(prog->Target);
-
    unsigned location;
    if (!shader_program->UniformHash->get(location, name)) {
-      linker_error(shader_program,
-                   "failed to find sampler named %s.\n", name);
+      assert(!"failed to find sampler");
       return 0;
    }
 
-   if (!shader_program->UniformStorage[location].sampler[shader].active) {
-      assert(0 && "cannot return a sampler");
-      linker_error(shader_program,
-                   "cannot return a sampler named %s, because it is not "
-                   "used in this shader stage. This is a driver bug.\n",
-                   name);
+   if (!shader_program->UniformStorage[location].sampler[stage].active) {
+      assert(!"cannot return a sampler");
       return 0;
    }
 
-   ralloc_free(mem_ctx);
-
-   return shader_program->UniformStorage[location].sampler[shader].index +
-          offset;
+   return shader_program->UniformStorage[location].sampler[stage].index;
 }
 
 static void
-lower_sampler(nir_tex_instr *instr, struct gl_shader_program *shader_program,
-              const struct gl_program *prog)
+lower_sampler(nir_tex_instr *instr, const struct gl_shader_program *shader_program,
+              gl_shader_stage stage, void *mem_ctx)
 {
-   if (instr->sampler) {
-      instr->sampler_index = get_sampler_index(instr->sampler, shader_program,
-                                             prog);
-      instr->sampler = NULL;
+   if (instr->sampler == NULL)
+      return;
+
+   /* Get the name and the offset */
+   instr->sampler_index = 0;
+   char *name = ralloc_strdup(mem_ctx, instr->sampler->var->name);
+
+   for (nir_deref *deref = &instr->sampler->deref;
+        deref->child; deref = deref->child) {
+      switch (deref->child->deref_type) {
+      case nir_deref_type_array: {
+         nir_deref_array *deref_array = nir_deref_as_array(deref->child);
+
+         assert(deref_array->deref_array_type != nir_deref_array_type_wildcard);
+
+         if (deref_array->deref.child) {
+            ralloc_asprintf_append(&name, "[%u]",
+               deref_array->deref_array_type == nir_deref_array_type_direct ?
+                  deref_array->base_offset : 0);
+         } else {
+            assert(deref->child->type->base_type == GLSL_TYPE_SAMPLER);
+            instr->sampler_index = deref_array->base_offset;
+         }
+
+         /* XXX: We're assuming here that the indirect is the last array
+          * thing we have.  This should be ok for now as we don't support
+          * arrays_of_arrays yet.
+          */
+         if (deref_array->deref_array_type == nir_deref_array_type_indirect) {
+            /* First, we have to resize the array of texture sources */
+            nir_tex_src *new_srcs = rzalloc_array(instr, nir_tex_src,
+                                                  instr->num_srcs + 1);
+
+            for (unsigned i = 0; i < instr->num_srcs; i++) {
+               new_srcs[i].src_type = instr->src[i].src_type;
+               nir_instr_move_src(&instr->instr, &new_srcs[i].src,
+                                  &instr->src[i].src);
+            }
+
+            ralloc_free(instr->src);
+            instr->src = new_srcs;
+
+            /* Now we can go ahead and move the source over to being a
+             * first-class texture source.
+             */
+            instr->src[instr->num_srcs].src_type = nir_tex_src_sampler_offset;
+            instr->num_srcs++;
+            nir_instr_move_src(&instr->instr,
+                               &instr->src[instr->num_srcs - 1].src,
+                               &deref_array->indirect);
+
+            instr->sampler_array_size = glsl_get_length(deref->type);
+         }
+         break;
+      }
+
+      case nir_deref_type_struct: {
+         nir_deref_struct *deref_struct = nir_deref_as_struct(deref->child);
+         const char *field = glsl_get_struct_elem_name(deref->type,
+                                                       deref_struct->index);
+         ralloc_asprintf_append(&name, ".%s", field);
+         break;
+      }
+
+      default:
+         unreachable("Invalid deref type");
+         break;
+      }
    }
+
+   instr->sampler_index += get_sampler_index(shader_program, stage, name);
+
+   instr->sampler = NULL;
 }
 
 typedef struct {
-   struct gl_shader_program *shader_program;
-   struct gl_program *prog;
+   void *mem_ctx;
+   const struct gl_shader_program *shader_program;
+   gl_shader_stage stage;
 } lower_state;
 
 static bool
@@ -140,9 +144,10 @@ lower_block_cb(nir_block *block, void *_state)
    lower_state *state = (lower_state *) _state;
 
    nir_foreach_instr(block, instr) {
-      if (instr->type == nir_instr_type_texture) {
-         nir_tex_instr *tex_instr = nir_instr_as_texture(instr);
-         lower_sampler(tex_instr, state->shader_program, state->prog);
+      if (instr->type == nir_instr_type_tex) {
+         nir_tex_instr *tex_instr = nir_instr_as_tex(instr);
+         lower_sampler(tex_instr, state->shader_program, state->stage,
+                       state->mem_ctx);
       }
    }
 
@@ -150,21 +155,24 @@ lower_block_cb(nir_block *block, void *_state)
 }
 
 static void
-lower_impl(nir_function_impl *impl, struct gl_shader_program *shader_program,
-           struct gl_program *prog)
+lower_impl(nir_function_impl *impl, const struct gl_shader_program *shader_program,
+           gl_shader_stage stage)
 {
    lower_state state;
+
+   state.mem_ctx = ralloc_parent(impl);
    state.shader_program = shader_program;
-   state.prog = prog;
+   state.stage = stage;
+
    nir_foreach_block(impl, lower_block_cb, &state);
 }
 
 extern "C" void
-nir_lower_samplers(nir_shader *shader, struct gl_shader_program *shader_program,
-                   struct gl_program *prog)
+nir_lower_samplers(nir_shader *shader, const struct gl_shader_program *shader_program,
+                   gl_shader_stage stage)
 {
    nir_foreach_overload(shader, overload) {
       if (overload->impl)
-         lower_impl(overload->impl, shader_program, prog);
+         lower_impl(overload->impl, shader_program, stage);
    }
 }