summaryrefslogtreecommitdiff
path: root/src/gallium/drivers/nouveau/codegen
diff options
context:
space:
mode:
authorEmma Anholt <emma@anholt.net>2022-04-20 16:30:37 -0700
committerMarge Bot <emma+marge@anholt.net>2022-04-29 23:07:03 +0000
commit3ddc505400ee91905cc4ee0762947b8377db5504 (patch)
tree2f952ddbc7305efc643faec003e70832ab7b7add /src/gallium/drivers/nouveau/codegen
parent53d87865caca949ce3e73f2a8ec04c17d5818754 (diff)
nouveau/nir: Move FS output stores to the end of the last block.
The nir_move/sink caused instructions to sink interleaved into the output stores at the end of the shader. nouveau's RA doesn't track liveness of FS outputs in registers after the export instruction, so they could end up overwritten. To work around it, after normal NIR move/sink, move the output stores back to the end of the shader. Fixes: b1fa2068b8e8 ("nouveau/nir: Enable nir_opt_move/sink.") Reviewed-by: M Henning <drawoc@darkrefraction.com> Reviewed-by: Karol Herbst <kherbst@redhat.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/15949>
Diffstat (limited to 'src/gallium/drivers/nouveau/codegen')
-rw-r--r--src/gallium/drivers/nouveau/codegen/nv50_ir_from_nir.cpp34
1 files changed, 33 insertions, 1 deletions
diff --git a/src/gallium/drivers/nouveau/codegen/nv50_ir_from_nir.cpp b/src/gallium/drivers/nouveau/codegen/nv50_ir_from_nir.cpp
index 7abd83d3a56..6d9ba1ccca5 100644
--- a/src/gallium/drivers/nouveau/codegen/nv50_ir_from_nir.cpp
+++ b/src/gallium/drivers/nouveau/codegen/nv50_ir_from_nir.cpp
@@ -1034,7 +1034,6 @@ bool Converter::assignSlots() {
int slot = var->data.location;
uint16_t slots = calcSlots(type, prog->getType(), nir->info, true, var);
uint32_t vary = var->data.driver_location;
-
assert(vary + slots <= PIPE_MAX_SHADER_INPUTS);
switch(prog->getType()) {
@@ -3122,6 +3121,36 @@ Converter::visit(nir_tex_instr *insn)
return true;
}
+/* nouveau's RA doesn't track the liveness of exported registers in the fragment
+ * shader, so we need all the store_outputs to appear at the end of the shader
+ * with no other instructions that might generate a temp value in between them.
+ */
+static void
+nv_nir_move_stores_to_end(nir_shader *s)
+{
+ nir_function_impl *impl = nir_shader_get_entrypoint(s);
+ nir_block *block = nir_impl_last_block(impl);
+ nir_instr *first_store = NULL;
+
+ nir_foreach_instr_safe(instr, block) {
+ if (instr == first_store)
+ break;
+ if (instr->type != nir_instr_type_intrinsic)
+ continue;
+ nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);
+ if (intrin->intrinsic == nir_intrinsic_store_output) {
+ nir_instr_remove(instr);
+ nir_instr_insert(nir_after_block(block), instr);
+
+ if (!first_store)
+ first_store = instr;
+ }
+ }
+ nir_metadata_preserve(impl,
+ nir_metadata_block_index |
+ nir_metadata_dominance);
+}
+
bool
Converter::run()
{
@@ -3191,6 +3220,9 @@ Converter::run()
NIR_PASS_V(nir, nir_opt_sink, move_options);
NIR_PASS_V(nir, nir_opt_move, move_options);
+ if (nir->info.stage == MESA_SHADER_FRAGMENT)
+ NIR_PASS_V(nir, nv_nir_move_stores_to_end);
+
NIR_PASS_V(nir, nir_lower_bool_to_int32);
NIR_PASS_V(nir, nir_convert_from_ssa, true);