nir/linker: Add inputs/outputs to the program resource list
authorAntia Puentes <apuentes@igalia.com>
Wed, 8 Aug 2018 12:29:38 +0000 (14:29 +0200)
committerAlejandro Piñeiro <apinheiro@igalia.com>
Fri, 12 Jul 2019 21:42:41 +0000 (23:42 +0200)
v2: added TODO comment hinting possible future refactoring of
    nir_build_program_resource_list and build_program_resource_list,
    to avoid code duplication (Alejandro, to explicitly reflect a
    valid concern from Timothy during the review).

Reviewed-by: Timothy Arceri <tarceri@itsqueeze.com>
src/compiler/glsl/gl_nir_linker.c

index 49ba950..13d4e83 100644 (file)
  * 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)
+{
+   const struct exec_list *var_list = NULL;
+
+   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:
+      var_list = &nir->inputs;
+      break;
+   case GL_PROGRAM_OUTPUT:
+      var_list = &nir->outputs;
+      break;
+   default:
+      assert("!Should not get here");
+      break;
+   }
+
+   nir_foreach_variable(var, var_list) {
+      if (var->data.how_declared == nir_var_hidden)
+         continue;
+
+      int loc_bias = 0;
+      switch(var->data.mode) {
+      case nir_var_system_value:
+      case nir_var_shader_in:
+         if (programInterface != GL_PROGRAM_INPUT)
+            continue;
+         loc_bias = (stage == MESA_SHADER_VERTEX) ? VERT_ATTRIB_GENERIC0
+                                                  : VARYING_SLOT_VAR0;
+         break;
+      case nir_var_shader_out:
+         if (programInterface != GL_PROGRAM_OUTPUT)
+            continue;
+         loc_bias = (stage == MESA_SHADER_FRAGMENT) ? FRAG_RESULT_DATA0
+                                                    : VARYING_SLOT_VAR0;
+         break;
+      default:
+         continue;
+      }
+
+      if (var->data.patch)
+         loc_bias = VARYING_SLOT_PATCH0;
+
+      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;
+      }
+   }
+
+   return true;
+}
+
+/* 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)
@@ -44,8 +123,37 @@ nir_build_program_resource_list(struct gl_context *ctx,
       prog->data->NumProgramResourceList = 0;
    }
 
+   int input_stage = MESA_SHADER_STAGES, output_stage = 0;
+
+   /* Determine first input and final output stage. These are used to
+    * detect which variables should be enumerated in the resource list
+    * for GL_PROGRAM_INPUT and GL_PROGRAM_OUTPUT.
+    */
+   for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
+      if (!prog->_LinkedShaders[i])
+         continue;
+      if (input_stage == MESA_SHADER_STAGES)
+         input_stage = i;
+      output_stage = i;
+   }
+
+   /* Empty shader, no resources. */
+   if (input_stage == MESA_SHADER_STAGES && output_stage == 0)
+      return;
+
    struct set *resource_set = _mesa_pointer_set_create(NULL);
 
+   /* Add inputs and outputs to the resource list. */
+   if (!add_interface_variables(ctx, prog, resource_set, input_stage,
+                                GL_PROGRAM_INPUT)) {
+      return;
+   }
+
+   if (!add_interface_variables(ctx, prog, resource_set, output_stage,
+                                GL_PROGRAM_OUTPUT)) {
+      return;
+   }
+
    /* Add uniforms
     *
     * Here, it is expected that nir_link_uniforms() has already been