nir/vtn: Use return type rather than image type for tex ops
[mesa.git] / src / compiler / glsl / gl_nir_linker.c
index 4503231c6c21d708a9e9b5e708a1e1593b28fa52..aa8f0f3083be039cebe4edaf1b0c65336dacc004 100644 (file)
  */
 
 #include "nir.h"
+#include "gl_nir.h"
 #include "gl_nir_linker.h"
 #include "linker_util.h"
 #include "main/mtypes.h"
+#include "main/shaderobj.h"
 #include "ir_uniform.h" /* for gl_uniform_storage */
 
-/* This file included general link methods, using NIR, instead of IR as
+/**
+ * This file included general link methods, using NIR, instead of IR as
  * the counter-part glsl/linker.cpp
- *
- * Also note that this is tailored for ARB_gl_spirv needs and particularities
  */
 
 static bool
-add_interface_variables(const struct gl_context *cts,
-                        struct gl_shader_program *prog,
-                        struct set *resource_set,
-                        unsigned stage, GLenum programInterface)
+can_remove_uniform(nir_variable *var)
 {
-   const struct exec_list *var_list = NULL;
+   /* Section 2.11.6 (Uniform Variables) of the OpenGL ES 3.0.3 spec
+    * says:
+    *
+    *     "All members of a named uniform block declared with a shared or
+    *     std140 layout qualifier are considered active, even if they are not
+    *     referenced in any shader in the program. The uniform block itself is
+    *     also considered active, even if no member of the block is
+    *     referenced."
+    *
+    * Although the spec doesn't state it std430 layouts are expect to behave
+    * the same way. If the variable is in a uniform block with one of those
+    * layouts, do not eliminate it.
+    */
+   if (nir_variable_is_in_block(var) &&
+       (glsl_get_ifc_packing(var->interface_type) !=
+        GLSL_INTERFACE_PACKING_PACKED))
+      return false;
 
-   struct gl_linked_shader *sh = prog->_LinkedShaders[stage];
-   if (!sh)
+   if (glsl_get_base_type(glsl_without_array(var->type)) ==
+       GLSL_TYPE_SUBROUTINE)
+      return false;
+
+   /* Uniform initializers could get used by another stage */
+   if (var->constant_initializer)
+      return false;
+
+   return true;
+}
+
+/**
+ * Built-in / reserved GL variables names start with "gl_"
+ */
+static inline bool
+is_gl_identifier(const char *s)
+{
+   return s && s[0] == 'g' && s[1] == 'l' && s[2] == '_';
+}
+
+static bool
+inout_has_same_location(const nir_variable *var, unsigned stage)
+{
+   if (!var->data.patch &&
+       ((var->data.mode == nir_var_shader_out &&
+         stage == MESA_SHADER_TESS_CTRL) ||
+        (var->data.mode == nir_var_shader_in &&
+         (stage == MESA_SHADER_TESS_CTRL || stage == MESA_SHADER_TESS_EVAL ||
+          stage == MESA_SHADER_GEOMETRY))))
       return true;
+   else
+      return false;
+}
 
-   nir_shader *nir = sh->Program->nir;
-   assert(nir);
+/**
+ * Create gl_shader_variable from nir_variable.
+ */
+static struct gl_shader_variable *
+create_shader_variable(struct gl_shader_program *shProg,
+                       const nir_variable *in,
+                       const char *name, const struct glsl_type *type,
+                       const struct glsl_type *interface_type,
+                       bool use_implicit_location, int location,
+                       const struct glsl_type *outermost_struct_type)
+{
+   /* Allocate zero-initialized memory to ensure that bitfield padding
+    * is zero.
+    */
+   struct gl_shader_variable *out = rzalloc(shProg,
+                                            struct gl_shader_variable);
+   if (!out)
+      return NULL;
 
-   switch (programInterface) {
-   case GL_PROGRAM_INPUT:
-      var_list = &nir->inputs;
-      break;
-   case GL_PROGRAM_OUTPUT:
-      var_list = &nir->outputs;
-      break;
-   default:
-      assert("!Should not get here");
-      break;
+   /* Since gl_VertexID may be lowered to gl_VertexIDMESA, but applications
+    * expect to see gl_VertexID in the program resource list.  Pretend.
+    */
+   if (in->data.mode == nir_var_system_value &&
+       in->data.location == SYSTEM_VALUE_VERTEX_ID_ZERO_BASE) {
+      out->name = ralloc_strdup(shProg, "gl_VertexID");
+   } else if ((in->data.mode == nir_var_shader_out &&
+               in->data.location == VARYING_SLOT_TESS_LEVEL_OUTER) ||
+              (in->data.mode == nir_var_system_value &&
+               in->data.location == SYSTEM_VALUE_TESS_LEVEL_OUTER)) {
+      out->name = ralloc_strdup(shProg, "gl_TessLevelOuter");
+      type = glsl_array_type(glsl_float_type(), 4, 0);
+   } else if ((in->data.mode == nir_var_shader_out &&
+               in->data.location == VARYING_SLOT_TESS_LEVEL_INNER) ||
+              (in->data.mode == nir_var_system_value &&
+               in->data.location == SYSTEM_VALUE_TESS_LEVEL_INNER)) {
+      out->name = ralloc_strdup(shProg, "gl_TessLevelInner");
+      type = glsl_array_type(glsl_float_type(), 2, 0);
+   } else {
+      out->name = ralloc_strdup(shProg, name);
    }
 
-   nir_foreach_variable(var, var_list) {
+   if (!out->name)
+      return NULL;
+
+   /* The ARB_program_interface_query spec says:
+    *
+    *     "Not all active variables are assigned valid locations; the
+    *     following variables will have an effective location of -1:
+    *
+    *      * uniforms declared as atomic counters;
+    *
+    *      * members of a uniform block;
+    *
+    *      * built-in inputs, outputs, and uniforms (starting with "gl_"); and
+    *
+    *      * inputs or outputs not declared with a "location" layout
+    *        qualifier, except for vertex shader inputs and fragment shader
+    *        outputs."
+    */
+   if (glsl_get_base_type(in->type) == GLSL_TYPE_ATOMIC_UINT ||
+       is_gl_identifier(in->name) ||
+       !(in->data.explicit_location || use_implicit_location)) {
+      out->location = -1;
+   } else {
+      out->location = location;
+   }
+
+   out->type = type;
+   out->outermost_struct_type = outermost_struct_type;
+   out->interface_type = interface_type;
+   out->component = in->data.location_frac;
+   out->index = in->data.index;
+   out->patch = in->data.patch;
+   out->mode = in->data.mode;
+   out->interpolation = in->data.interpolation;
+   out->precision = in->data.precision;
+   out->explicit_location = in->data.explicit_location;
+
+   return out;
+}
+
+static bool
+add_shader_variable(const struct gl_context *ctx,
+                    struct gl_shader_program *shProg,
+                    struct set *resource_set,
+                    unsigned stage_mask,
+                    GLenum programInterface, nir_variable *var,
+                    const char *name, const struct glsl_type *type,
+                    bool use_implicit_location, int location,
+                    bool inouts_share_location,
+                    const struct glsl_type *outermost_struct_type)
+{
+   const struct glsl_type *interface_type = var->interface_type;
+
+   if (outermost_struct_type == NULL) {
+      if (var->data.from_named_ifc_block) {
+         const char *interface_name = glsl_get_type_name(interface_type);
+
+         if (glsl_type_is_array(interface_type)) {
+            /* Issue #16 of the ARB_program_interface_query spec says:
+             *
+             * "* If a variable is a member of an interface block without an
+             *    instance name, it is enumerated using just the variable name.
+             *
+             *  * If a variable is a member of an interface block with an
+             *    instance name, it is enumerated as "BlockName.Member", where
+             *    "BlockName" is the name of the interface block (not the
+             *    instance name) and "Member" is the name of the variable."
+             *
+             * In particular, it indicates that it should be "BlockName",
+             * not "BlockName[array length]".  The conformance suite and
+             * dEQP both require this behavior.
+             *
+             * Here, we unwrap the extra array level added by named interface
+             * block array lowering so we have the correct variable type.  We
+             * also unwrap the interface type when constructing the name.
+             *
+             * We leave interface_type the same so that ES 3.x SSO pipeline
+             * validation can enforce the rules requiring array length to
+             * match on interface blocks.
+             */
+            type = glsl_get_array_element(type);
+
+            interface_name =
+               glsl_get_type_name(glsl_get_array_element(interface_type));
+         }
+
+         name = ralloc_asprintf(shProg, "%s.%s", interface_name, name);
+      }
+   }
+
+   switch (glsl_get_base_type(type)) {
+   case GLSL_TYPE_STRUCT: {
+      /* The ARB_program_interface_query spec says:
+       *
+       *     "For an active variable declared as a structure, a separate entry
+       *     will be generated for each active structure member.  The name of
+       *     each entry is formed by concatenating the name of the structure,
+       *     the "."  character, and the name of the structure member.  If a
+       *     structure member to enumerate is itself a structure or array,
+       *     these enumeration rules are applied recursively."
+       */
+      if (outermost_struct_type == NULL)
+         outermost_struct_type = type;
+
+      unsigned field_location = location;
+      for (unsigned i = 0; i < glsl_get_length(type); i++) {
+         const struct glsl_type *field_type = glsl_get_struct_field(type, i);
+         const struct glsl_struct_field *field =
+            glsl_get_struct_field_data(type, i);
+
+         char *field_name = ralloc_asprintf(shProg, "%s.%s", name, field->name);
+         if (!add_shader_variable(ctx, shProg, resource_set,
+                                  stage_mask, programInterface,
+                                  var, field_name, field_type,
+                                  use_implicit_location, field_location,
+                                  false, outermost_struct_type))
+            return false;
+
+         field_location += glsl_count_attribute_slots(field_type, false);
+      }
+      return true;
+   }
+
+   case GLSL_TYPE_ARRAY: {
+      /* The ARB_program_interface_query spec says:
+       *
+       *     "For an active variable declared as an array of basic types, a
+       *      single entry will be generated, with its name string formed by
+       *      concatenating the name of the array and the string "[0]"."
+       *
+       *     "For an active variable declared as an array of an aggregate data
+       *      type (structures or arrays), a separate entry will be generated
+       *      for each active array element, unless noted immediately below.
+       *      The name of each entry is formed by concatenating the name of
+       *      the array, the "[" character, an integer identifying the element
+       *      number, and the "]" character.  These enumeration rules are
+       *      applied recursively, treating each enumerated array element as a
+       *      separate active variable."
+       */
+      const struct glsl_type *array_type = glsl_get_array_element(type);
+      if (glsl_get_base_type(array_type) == GLSL_TYPE_STRUCT ||
+          glsl_get_base_type(array_type) == GLSL_TYPE_ARRAY) {
+         unsigned elem_location = location;
+         unsigned stride = inouts_share_location ? 0 :
+                           glsl_count_attribute_slots(array_type, false);
+         for (unsigned i = 0; i < glsl_get_length(type); i++) {
+            char *elem = ralloc_asprintf(shProg, "%s[%d]", name, i);
+            if (!add_shader_variable(ctx, shProg, resource_set,
+                                     stage_mask, programInterface,
+                                     var, elem, array_type,
+                                     use_implicit_location, elem_location,
+                                     false, outermost_struct_type))
+               return false;
+            elem_location += stride;
+         }
+         return true;
+      }
+   }
+   /* fallthrough */
+
+   default: {
+      /* The ARB_program_interface_query spec says:
+       *
+       *     "For an active variable declared as a single instance of a basic
+       *     type, a single entry will be generated, using the variable name
+       *     from the shader source."
+       */
+      struct gl_shader_variable *sha_v =
+         create_shader_variable(shProg, var, name, type, interface_type,
+                                use_implicit_location, location,
+                                outermost_struct_type);
+      if (!sha_v)
+         return false;
+
+      return link_util_add_program_resource(shProg, resource_set,
+                                            programInterface, sha_v, stage_mask);
+   }
+   }
+}
+
+static bool
+add_vars_with_modes(const struct gl_context *ctx,
+                    struct gl_shader_program *prog, struct set *resource_set,
+                    nir_shader *nir, nir_variable_mode modes,
+                    unsigned stage, GLenum programInterface)
+{
+   nir_foreach_variable_with_modes(var, nir, modes) {
       if (var->data.how_declared == nir_var_hidden)
          continue;
 
@@ -86,38 +342,96 @@ add_interface_variables(const struct gl_context *cts,
       if (var->data.patch)
          loc_bias = VARYING_SLOT_PATCH0;
 
-      struct gl_shader_variable *sh_var =
-         rzalloc(prog, struct gl_shader_variable);
+      if (prog->data->spirv) {
+         struct gl_shader_variable *sh_var =
+            rzalloc(prog, struct gl_shader_variable);
 
-      /* In the ARB_gl_spirv spec, names are considered optional debug info, so
-       * the linker needs to work without them. Returning them is optional.
-       * For simplicity, we ignore names.
-       */
-      sh_var->name = NULL;
-      sh_var->type = var->type;
-      sh_var->location = var->data.location - loc_bias;
-      sh_var->index = var->data.index;
-
-      if (!link_util_add_program_resource(prog, resource_set,
-                                          programInterface,
-                                          sh_var, 1 << stage)) {
-         return false;
+         /* In the ARB_gl_spirv spec, names are considered optional debug info, so
+          * the linker needs to work without them. Returning them is optional.
+          * For simplicity, we ignore names.
+          */
+         sh_var->name = NULL;
+         sh_var->type = var->type;
+         sh_var->location = var->data.location - loc_bias;
+         sh_var->index = var->data.index;
+
+         if (!link_util_add_program_resource(prog, resource_set,
+                                             programInterface,
+                                             sh_var, 1 << stage)) {
+           return false;
+         }
+      } else {
+         /* Skip packed varyings, packed varyings are handled separately
+          * by add_packed_varyings in the GLSL IR
+          * build_program_resource_list() call.
+          * TODO: handle packed varyings here instead. We likely want a NIR
+          * based packing pass first.
+          */
+         if (strncmp(var->name, "packed:", 7) == 0)
+            continue;
+
+         const bool vs_input_or_fs_output =
+            (stage == MESA_SHADER_VERTEX &&
+             var->data.mode == nir_var_shader_in) ||
+            (stage == MESA_SHADER_FRAGMENT &&
+             var->data.mode == nir_var_shader_out);
+
+         if (!add_shader_variable(ctx, prog, resource_set,
+                                  1 << stage, programInterface,
+                                  var, var->name, var->type,
+                                  vs_input_or_fs_output,
+                                  var->data.location - loc_bias,
+                                  inout_has_same_location(var, stage),
+                                  NULL))
+            return false;
       }
    }
 
    return true;
 }
 
+static bool
+add_interface_variables(const struct gl_context *ctx,
+                        struct gl_shader_program *prog,
+                        struct set *resource_set,
+                        unsigned stage, GLenum programInterface)
+{
+   struct gl_linked_shader *sh = prog->_LinkedShaders[stage];
+   if (!sh)
+      return true;
+
+   nir_shader *nir = sh->Program->nir;
+   assert(nir);
+
+   switch (programInterface) {
+   case GL_PROGRAM_INPUT: {
+      return add_vars_with_modes(ctx, prog, resource_set,
+                                 nir, nir_var_shader_in | nir_var_system_value,
+                                 stage, programInterface);
+   }
+   case GL_PROGRAM_OUTPUT:
+      return add_vars_with_modes(ctx, prog, resource_set,
+                                 nir, nir_var_shader_out,
+                                 stage, programInterface);
+   default:
+      assert("!Should not get here");
+      break;
+   }
+
+   return false;
+}
+
 /* TODO: as we keep adding features, this method is becoming more and more
  * similar to its GLSL counterpart at linker.cpp. Eventually it would be good
  * to check if they could be refactored, and reduce code duplication somehow
  */
 void
 nir_build_program_resource_list(struct gl_context *ctx,
-                                struct gl_shader_program *prog)
+                                struct gl_shader_program *prog,
+                                bool rebuild_resourse_list)
 {
    /* Rebuild resource list. */
-   if (prog->data->ProgramResourceList) {
+   if (prog->data->ProgramResourceList && rebuild_resourse_list) {
       ralloc_free(prog->data->ProgramResourceList);
       prog->data->ProgramResourceList = NULL;
       prog->data->NumProgramResourceList = 0;
@@ -193,9 +507,22 @@ nir_build_program_resource_list(struct gl_context *ctx,
    for (unsigned i = 0; i < prog->data->NumUniformStorage; i++) {
       struct gl_uniform_storage *uniform = &prog->data->UniformStorage[i];
 
-      /* Do not add uniforms internally used by Mesa. */
-      if (uniform->hidden)
+      if (uniform->hidden) {
+         for (int j = MESA_SHADER_VERTEX; j < MESA_SHADER_STAGES; j++) {
+            if (!uniform->opaque[j].active ||
+                glsl_get_base_type(uniform->type) != GLSL_TYPE_SUBROUTINE)
+               continue;
+
+            GLenum type =
+               _mesa_shader_stage_to_subroutine_uniform((gl_shader_stage)j);
+            /* add shader subroutines */
+            if (!link_util_add_program_resource(prog, resource_set,
+                                                type, uniform, 0))
+               return;
+         }
+
          continue;
+      }
 
       if (!link_util_should_add_buffer_variable(prog, uniform,
                                                 top_level_array_base_offset,
@@ -251,5 +578,109 @@ nir_build_program_resource_list(struct gl_context *ctx,
          return;
    }
 
+   unsigned mask = prog->data->linked_stages;
+   while (mask) {
+      const int i = u_bit_scan(&mask);
+      struct gl_program *p = prog->_LinkedShaders[i]->Program;
+
+      GLuint type = _mesa_shader_stage_to_subroutine((gl_shader_stage)i);
+      for (unsigned j = 0; j < p->sh.NumSubroutineFunctions; j++) {
+         if (!link_util_add_program_resource(prog, resource_set,
+                                             type,
+                                             &p->sh.SubroutineFunctions[j],
+                                             0))
+            return;
+      }
+   }
+
    _mesa_set_destroy(resource_set, NULL);
 }
+
+bool
+gl_nir_link_spirv(struct gl_context *ctx, struct gl_shader_program *prog,
+                  const struct gl_nir_linker_options *options)
+{
+   for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
+      struct gl_linked_shader *shader = prog->_LinkedShaders[i];
+      if (shader) {
+         nir_remove_dead_variables(shader->Program->nir, nir_var_uniform,
+                                   &can_remove_uniform);
+      }
+   }
+
+   if (!gl_nir_link_uniform_blocks(ctx, prog))
+      return false;
+
+   if (!gl_nir_link_uniforms(ctx, prog, options->fill_parameters))
+      return false;
+
+   gl_nir_link_assign_atomic_counter_resources(ctx, prog);
+   gl_nir_link_assign_xfb_resources(ctx, prog);
+
+   return true;
+}
+
+/**
+ * Validate shader image resources.
+ */
+static void
+check_image_resources(struct gl_context *ctx, struct gl_shader_program *prog)
+{
+   unsigned total_image_units = 0;
+   unsigned fragment_outputs = 0;
+   unsigned total_shader_storage_blocks = 0;
+
+   if (!ctx->Extensions.ARB_shader_image_load_store)
+      return;
+
+   for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
+      struct gl_linked_shader *sh = prog->_LinkedShaders[i];
+      if (!sh)
+         continue;
+
+      total_image_units += sh->Program->info.num_images;
+      total_shader_storage_blocks += sh->Program->info.num_ssbos;
+   }
+
+   if (total_image_units > ctx->Const.MaxCombinedImageUniforms)
+      linker_error(prog, "Too many combined image uniforms\n");
+
+   struct gl_linked_shader *frag_sh =
+      prog->_LinkedShaders[MESA_SHADER_FRAGMENT];
+   if (frag_sh) {
+      uint64_t frag_outputs_written = frag_sh->Program->info.outputs_written;
+      fragment_outputs = util_bitcount64(frag_outputs_written);
+   }
+
+   if (total_image_units + fragment_outputs + total_shader_storage_blocks >
+       ctx->Const.MaxCombinedShaderOutputResources)
+      linker_error(prog, "Too many combined image uniforms, shader storage "
+                         " buffers and fragment outputs\n");
+}
+
+bool
+gl_nir_link_glsl(struct gl_context *ctx, struct gl_shader_program *prog)
+{
+   for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
+      struct gl_linked_shader *shader = prog->_LinkedShaders[i];
+      if (shader) {
+         nir_remove_dead_variables(shader->Program->nir, nir_var_uniform,
+                                   &can_remove_uniform);
+      }
+   }
+
+   if (!gl_nir_link_uniforms(ctx, prog, true))
+      return false;
+
+   link_util_calculate_subroutine_compat(prog);
+   link_util_check_uniform_resources(ctx, prog);
+   link_util_check_subroutine_resources(prog);
+   check_image_resources(ctx, prog);
+   gl_nir_link_assign_atomic_counter_resources(ctx, prog);
+   gl_nir_link_check_atomic_counter_resources(ctx, prog);
+
+   if (prog->data->LinkStatus == LINKING_FAILURE)
+      return false;
+
+   return true;
+}