[Mesa-dev] [PATCH 1/3] nir: Add a lowering pass for gl_FragColor to glFragData[] writes.

Eric Anholt eric at anholt.net
Fri Dec 29 01:56:18 UTC 2017


For VC5, the shader needs to have the appropriate base type for the
variable in the render target write, and gallium's
FS_COLOR0_WRITES_ALL_CBUFS (used for glClearBufferiv) doesn't give you
that information.  This pass lets the backend decide what types to explode
the gl_FragColor write out to.

This would also be a prerequisite of moving some of VC5's render target
format packing into NIR as well.
---
 src/compiler/Makefile.sources             |   1 +
 src/compiler/nir/meson.build              |   1 +
 src/compiler/nir/nir.h                    |   3 +
 src/compiler/nir/nir_lower_gl_fragcolor.c | 143 ++++++++++++++++++++++++++++++
 4 files changed, 148 insertions(+)
 create mode 100644 src/compiler/nir/nir_lower_gl_fragcolor.c

diff --git a/src/compiler/Makefile.sources b/src/compiler/Makefile.sources
index d3f746f5f948..4afaa1a2146a 100644
--- a/src/compiler/Makefile.sources
+++ b/src/compiler/Makefile.sources
@@ -220,6 +220,7 @@ NIR_FILES = \
 	nir/nir_lower_constant_initializers.c \
 	nir/nir_lower_double_ops.c \
 	nir/nir_lower_drawpixels.c \
+	nir/nir_lower_gl_fragcolor.c \
 	nir/nir_lower_global_vars_to_local.c \
 	nir/nir_lower_gs_intrinsics.c \
 	nir/nir_lower_load_const_to_scalar.c \
diff --git a/src/compiler/nir/meson.build b/src/compiler/nir/meson.build
index 5dd21e6652f0..9e11279118f6 100644
--- a/src/compiler/nir/meson.build
+++ b/src/compiler/nir/meson.build
@@ -114,6 +114,7 @@ files_libnir = files(
   'nir_lower_constant_initializers.c',
   'nir_lower_double_ops.c',
   'nir_lower_drawpixels.c',
+  'nir_lower_gl_fragcolor.c',
   'nir_lower_global_vars_to_local.c',
   'nir_lower_gs_intrinsics.c',
   'nir_lower_load_const_to_scalar.c',
diff --git a/src/compiler/nir/nir.h b/src/compiler/nir/nir.h
index 440c3fe9974c..17bb8fc8de4c 100644
--- a/src/compiler/nir/nir.h
+++ b/src/compiler/nir/nir.h
@@ -2680,6 +2680,9 @@ bool nir_lower_atomics(nir_shader *shader,
 bool nir_lower_atomics_to_ssbo(nir_shader *shader, unsigned ssbo_offset);
 bool nir_lower_uniforms_to_ubo(nir_shader *shader);
 bool nir_lower_to_source_mods(nir_shader *shader);
+bool nir_lower_gl_fragcolor(nir_shader *shader,
+                            uint32_t rt_mask,
+                            const struct glsl_type **types);
 
 bool nir_lower_gs_intrinsics(nir_shader *shader);
 
diff --git a/src/compiler/nir/nir_lower_gl_fragcolor.c b/src/compiler/nir/nir_lower_gl_fragcolor.c
new file mode 100644
index 000000000000..d4b39f00c233
--- /dev/null
+++ b/src/compiler/nir/nir_lower_gl_fragcolor.c
@@ -0,0 +1,143 @@
+/*
+ * Copyright © 2017 Broadcom
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "nir.h"
+#include "nir_builder.h"
+
+/**
+ * Lowers gl_FragColor to a per-render-target store.
+ *
+ * GLSL's gl_FragColor writes implicitly broadcast their store to every active
+ * render target.  This can be used by driver backends to implement
+ * gl_FragColor in the same way as other multiple-render-target shaders, and
+ * is particularly useful if the driver needs to do other per-render-target
+ * lowering in NIR.
+ *
+ * Run before nir_lower_io.
+ */
+
+typedef struct {
+   nir_shader *shader;
+   nir_builder b;
+
+   nir_variable *var; /* gl_FragColor */
+
+   int num_rt_vars;
+   nir_variable *rt_var[32]; /* gl_FragDataN */
+} lower_gl_fragcolor_state;
+
+static void
+lower_gl_fragcolor(lower_gl_fragcolor_state *state, nir_intrinsic_instr *intr)
+{
+   nir_builder *b = &state->b;
+
+   assert(intr->dest.is_ssa);
+
+   b->cursor = nir_before_instr(&intr->instr);
+
+   /* Generate a gl_FragDataN write per render target. */
+   nir_ssa_def *color = nir_ssa_for_src(b, intr->src[0], 4);
+   for (int i = 0; i < state->num_rt_vars; i++) {
+      nir_store_var(b, state->rt_var[i], color, 0xf);
+   }
+
+   /* Remove the gl_FragColor write. */
+   nir_instr_remove(&intr->instr);
+}
+
+static bool
+lower_gl_fragcolor_block(lower_gl_fragcolor_state *state, nir_block *block)
+{
+   nir_foreach_instr_safe(instr, block) {
+      if (instr->type == nir_instr_type_intrinsic) {
+         nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
+         if (intr->intrinsic == nir_intrinsic_store_var) {
+            nir_deref_var *dvar = intr->variables[0];
+            nir_variable *var = dvar->var;
+
+            if (var == state->var) {
+               /* gl_FragColor should not have array/struct derefs: */
+               assert(dvar->deref.child == NULL);
+               lower_gl_fragcolor(state, intr);
+            }
+         }
+      }
+   }
+
+   return true;
+}
+
+bool
+nir_lower_gl_fragcolor(nir_shader *shader, const uint32_t rt_mask,
+                      const struct glsl_type **types)
+{
+   lower_gl_fragcolor_state state = {
+      .shader = shader,
+   };
+
+   assert(shader->info.stage == MESA_SHADER_FRAGMENT);
+
+   nir_foreach_variable(var, &shader->outputs) {
+      if (var->data.location == FRAG_RESULT_COLOR) {
+         state.var = var;
+         break;
+      }
+   }
+
+   if (!state.var)
+      return false;
+
+   for (int i = 0; i < ARRAY_SIZE(state.rt_var); i++) {
+      if (!(rt_mask & (1 << i)))
+         continue;
+
+      char name[16];
+      snprintf(name, sizeof(name), "gl_FragData%d", i);
+
+      nir_variable *rt_var = nir_variable_create(state.shader,
+                                                 nir_var_shader_out,
+                                                 types[i],
+                                                 name);
+      rt_var->data.location = FRAG_RESULT_DATA0 + i;
+
+      state.rt_var[state.num_rt_vars++] = rt_var;
+   }
+
+   nir_foreach_function(function, shader) {
+      if (function->impl) {
+         nir_builder_init(&state.b, function->impl);
+
+         nir_foreach_block(block, function->impl) {
+            lower_gl_fragcolor_block(&state, block);
+         }
+
+         nir_metadata_preserve(function->impl,
+                               nir_metadata_block_index |
+                               nir_metadata_dominance);
+      }
+   }
+
+   exec_node_remove(&state.var->node);
+
+   return true;
+}
-- 
2.15.0



More information about the mesa-dev mailing list