Mesa (master): st/glsl_to_nir: enable NIR link time opts

Timothy Arceri tarceri at kemper.freedesktop.org
Sun Dec 3 22:14:57 UTC 2017


Module: Mesa
Branch: master
Commit: 6648bd68fd27fce9cdcdbf9cb7a370907fb30dd9
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=6648bd68fd27fce9cdcdbf9cb7a370907fb30dd9

Author: Timothy Arceri <tarceri at itsqueeze.com>
Date:   Mon Nov 20 17:20:35 2017 +1100

st/glsl_to_nir: enable NIR link time opts

Reviewed-by: Nicolai Hähnle <nicolai.haehnle at amd.com>

---

 src/gallium/drivers/radeonsi/si_shader_nir.c | 34 +++++++++---
 src/mesa/state_tracker/st_glsl_to_nir.cpp    | 78 ++++++++++++++++++++++++++++
 2 files changed, 105 insertions(+), 7 deletions(-)

diff --git a/src/gallium/drivers/radeonsi/si_shader_nir.c b/src/gallium/drivers/radeonsi/si_shader_nir.c
index 12eb8763ed..979361a74e 100644
--- a/src/gallium/drivers/radeonsi/si_shader_nir.c
+++ b/src/gallium/drivers/radeonsi/si_shader_nir.c
@@ -136,9 +136,6 @@ void si_nir_scan_shader(const struct nir_shader *nir,
 	info->num_tokens = 2; /* indicate that the shader is non-empty */
 	info->num_instructions = 2;
 
-	info->num_inputs = nir->num_inputs;
-	info->num_outputs = nir->num_outputs;
-
 	if (nir->info.stage == MESA_SHADER_GEOMETRY) {
 		info->properties[TGSI_PROPERTY_GS_INPUT_PRIM] = nir->info.gs.input_primitive;
 		info->properties[TGSI_PROPERTY_GS_OUTPUT_PRIM] = nir->info.gs.output_primitive;
@@ -147,6 +144,8 @@ void si_nir_scan_shader(const struct nir_shader *nir,
 	}
 
 	i = 0;
+	uint64_t processed_inputs = 0;
+	unsigned num_inputs = 0;
 	nir_foreach_variable(variable, &nir->inputs) {
 		unsigned semantic_name, semantic_index;
 		unsigned attrib_count = glsl_count_attribute_slots(variable->type,
@@ -167,9 +166,18 @@ void si_nir_scan_shader(const struct nir_shader *nir,
 			if (variable->data.pixel_center_integer)
 				info->properties[TGSI_PROPERTY_FS_COORD_PIXEL_CENTER] =
 					TGSI_FS_COORD_PIXEL_CENTER_INTEGER;
+
+			num_inputs++;
 			continue;
 		}
 
+		i = variable->data.driver_location;
+		if (processed_inputs & ((uint64_t)1 << i))
+			continue;
+
+		processed_inputs |= ((uint64_t)1 << i);
+		num_inputs++;
+
 		tgsi_get_gl_varying_semantic(variable->data.location, true,
 					     &semantic_name, &semantic_index);
 
@@ -235,11 +243,16 @@ void si_nir_scan_shader(const struct nir_shader *nir,
 			info->colors_read |= 0x0f;
 		else if (variable->data.location == VARYING_SLOT_COL1)
 			info->colors_read |= 0xf0;
-
-		i++;
 	}
 
+	if (nir->info.stage != MESA_SHADER_VERTEX)
+		info->num_inputs = num_inputs;
+	else
+		info->num_inputs = nir->num_inputs;
+
 	i = 0;
+	uint64_t processed_outputs = 0;
+	unsigned num_outputs = 0;
 	nir_foreach_variable(variable, &nir->outputs) {
 		unsigned semantic_name, semantic_index;
 
@@ -251,6 +264,13 @@ void si_nir_scan_shader(const struct nir_shader *nir,
 						     &semantic_name, &semantic_index);
 		}
 
+		i = variable->data.driver_location;
+		if (processed_outputs & ((uint64_t)1 << i))
+			continue;
+
+		processed_outputs |= ((uint64_t)1 << i);
+		num_outputs++;
+
 		info->output_semantic_name[i] = semantic_name;
 		info->output_semantic_index[i] = semantic_index;
 		info->output_usagemask[i] = TGSI_WRITEMASK_XYZW;
@@ -327,10 +347,10 @@ void si_nir_scan_shader(const struct nir_shader *nir,
 				info->writes_position = true;
 			break;
 		}
-
-		i++;
 	}
 
+	info->num_outputs = num_outputs;
+
 	nir_foreach_variable(variable, &nir->uniforms) {
 		const struct glsl_type *type = variable->type;
 		enum glsl_base_type base_type =
diff --git a/src/mesa/state_tracker/st_glsl_to_nir.cpp b/src/mesa/state_tracker/st_glsl_to_nir.cpp
index fdb6b8be04..9672ffbe64 100644
--- a/src/mesa/state_tracker/st_glsl_to_nir.cpp
+++ b/src/mesa/state_tracker/st_glsl_to_nir.cpp
@@ -473,6 +473,39 @@ st_nir_get_mesa_program(struct gl_context *ctx,
    NIR_PASS_V(nir, nir_lower_var_copies);
 }
 
+static void
+st_nir_link_shaders(nir_shader **producer, nir_shader **consumer)
+{
+   nir_lower_io_arrays_to_elements(*producer, *consumer);
+
+   NIR_PASS_V(*producer, nir_remove_dead_variables, nir_var_shader_out);
+   NIR_PASS_V(*consumer, nir_remove_dead_variables, nir_var_shader_in);
+
+   if (nir_remove_unused_varyings(*producer, *consumer)) {
+      NIR_PASS_V(*producer, nir_lower_global_vars_to_local);
+      NIR_PASS_V(*consumer, nir_lower_global_vars_to_local);
+
+      /* The backend might not be able to handle indirects on
+       * temporaries so we need to lower indirects on any of the
+       * varyings we have demoted here.
+       *
+       * TODO: radeonsi shouldn't need to do this, however LLVM isn't
+       * currently smart enough to handle indirects without causing excess
+       * spilling causing the gpu to hang.
+       *
+       * See the following thread for more details of the problem:
+       * https://lists.freedesktop.org/archives/mesa-dev/2017-July/162106.html
+       */
+      nir_variable_mode indirect_mask = nir_var_local;
+
+      NIR_PASS_V(*producer, nir_lower_indirect_derefs, indirect_mask);
+      NIR_PASS_V(*consumer, nir_lower_indirect_derefs, indirect_mask);
+
+      st_nir_opts(*producer);
+      st_nir_opts(*consumer);
+   }
+}
+
 extern "C" {
 
 bool
@@ -481,14 +514,53 @@ st_link_nir(struct gl_context *ctx,
 {
    struct st_context *st = st_context(ctx);
 
+   /* Determine first and last stage. */
+   unsigned first = MESA_SHADER_STAGES;
+   unsigned last = 0;
+   for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
+      if (!shader_program->_LinkedShaders[i])
+         continue;
+      if (first == MESA_SHADER_STAGES)
+         first = i;
+      last = i;
+   }
+
    for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
       struct gl_linked_shader *shader = shader_program->_LinkedShaders[i];
       if (shader == NULL)
          continue;
 
       st_nir_get_mesa_program(ctx, shader_program, shader);
+
+      nir_variable_mode mask = (nir_variable_mode) 0;
+      if (i != first)
+         mask = (nir_variable_mode)(mask | nir_var_shader_in);
+
+      if (i != last)
+         mask = (nir_variable_mode)(mask | nir_var_shader_out);
+
+      nir_shader *nir = shader->Program->nir;
+      nir_lower_io_to_scalar_early(nir, mask);
+      st_nir_opts(nir);
+   }
+
+   /* Linking the stages in the opposite order (from fragment to vertex)
+    * ensures that inter-shader outputs written to in an earlier stage
+    * are eliminated if they are (transitively) not used in a later
+    * stage.
+    */
+   int next = last;
+   for (int i = next - 1; i >= 0; i--) {
+      struct gl_linked_shader *shader = shader_program->_LinkedShaders[i];
+      if (shader == NULL)
+         continue;
+
+      st_nir_link_shaders(&shader->Program->nir,
+                          &shader_program->_LinkedShaders[next]->Program->nir);
+      next = i;
    }
 
+   int prev = -1;
    for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
       struct gl_linked_shader *shader = shader_program->_LinkedShaders[i];
       if (shader == NULL)
@@ -531,6 +603,12 @@ st_link_nir(struct gl_context *ctx,
       nir_shader_gather_info(nir, nir_shader_get_entrypoint(nir));
       shader->Program->info = nir->info;
 
+      if (prev != -1) {
+         nir_compact_varyings(shader_program->_LinkedShaders[prev]->Program->nir,
+                              nir, ctx->API != API_OPENGL_COMPAT);
+      }
+      prev = i;
+
       st_glsl_to_nir_post_opts(st, shader->Program, shader_program);
 
       assert(shader->Program);




More information about the mesa-commit mailing list