diff options
| author | Duck912 <350528965+Duck912@users.noreply.github.com> | 2026-11-01 21:42:24 -0500 |
|---|---|---|
| committer | Duck912 <350528965+Duck912@users.noreply.github.com> | 2026-11-01 21:54:48 -0500 |
| commit | c08b5efbaa4a7a2da78ca4509bec823ad38d5223 (patch) | |
| tree | 5592a03016aeec80bd129399729291638ee9bef1 /src/shader_recompiler | |
| parent | 808feaf3bf34b3c108ff30baae1d2261f216f4f3 (diff) | |
shader: keep root table reads the blit constants would zero
Fire Emblem: Fortune's Weave's enemy health gauges read only offset 0x40
of root table 0, which is inside the blit parameter block (title 4's
zero dither bias). The pass replaced it with zero and the gauges drew
black. A shader that reads only words the block leaves zero now keeps
its reads: an unbound bank reads zero anyway, and a bound root table
keeps its values.
Assisted-by: Claude Opus 5.5 (debugging, implementation and drafting)
Signed-off-by: Duck912 <350528965+Duck912@users.noreply.github.com>
Diffstat (limited to 'src/shader_recompiler')
| -rw-r--r-- | src/shader_recompiler/ir_opt/position_pass.cpp | 12 |
1 files changed, 11 insertions, 1 deletions
diff --git a/src/shader_recompiler/ir_opt/position_pass.cpp b/src/shader_recompiler/ir_opt/position_pass.cpp index 23b1200cfc..600a596bf3 100644 --- a/src/shader_recompiler/ir_opt/position_pass.cpp +++ b/src/shader_recompiler/ir_opt/position_pass.cpp @@ -85,10 +85,16 @@ void BlitConstantsPass(Environment& env, IR::Program& program) { } // Bank 24 is root table 0, which games may load themselves (3D methods 0x504/0x508; the buffer // cache binds it as bank 17): Fire Emblem: Fortune's Weave keeps its material push constants - // there. A shader reading bank 17 outside the blit block reads such a table and keeps its reads. + // there. A shader reading bank 17 outside the blit block reads such a table and keeps its reads, + // as does one reading only words the blit block leaves zero (an unbound bank reads zero anyway; + // the game's enemy health gauges read only 0x40 of their table). const auto in_blit_block = [](u32 offset) { return offset < 0x20 || (offset >= 0x30 && offset < 0x4c) || (offset >= 0x50 && offset < 0x60); }; + const auto is_nonzero_word = [](u32 offset) { + return offset < 0x20 || offset == 0x38 || offset == 0x3c || offset == 0x58 || offset == 0x5c; + }; + bool reads_nonzero_word{}; for (IR::Block* const block : program.post_order_blocks) { for (IR::Inst& inst : block->Instructions()) { const IR::Opcode opcode{inst.GetOpcode()}; @@ -102,8 +108,12 @@ void BlitConstantsPass(Environment& env, IR::Program& program) { if (!in_blit_block(offset) || (pair && !in_blit_block(offset + 4))) { return; } + reads_nonzero_word |= is_nonzero_word(offset) || (pair && is_nonzero_word(offset + 4)); } } + if (!reads_nonzero_word) { + return; + } bool used{}; for (IR::Block* const block : program.post_order_blocks) { for (IR::Inst& inst : block->Instructions()) { |
