diff options
author | Emma Anholt <emma@anholt.net> | 2022-04-20 16:30:37 -0700 |
---|---|---|
committer | Marge Bot <emma+marge@anholt.net> | 2022-04-29 23:07:03 +0000 |
commit | 3ddc505400ee91905cc4ee0762947b8377db5504 (patch) | |
tree | 2f952ddbc7305efc643faec003e70832ab7b7add /src/gallium/drivers/nouveau/codegen | |
parent | 53d87865caca949ce3e73f2a8ec04c17d5818754 (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.cpp | 34 |
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); |