aboutsummaryrefslogtreecommitdiff
path: root/src/shader_recompiler
diff options
context:
space:
mode:
authorDuck912 <350528965+Duck912@users.noreply.github.com>2026-11-01 21:42:24 -0500
committerDuck912 <350528965+Duck912@users.noreply.github.com>2026-11-01 21:54:48 -0500
commitc08b5efbaa4a7a2da78ca4509bec823ad38d5223 (patch)
tree5592a03016aeec80bd129399729291638ee9bef1 /src/shader_recompiler
parent808feaf3bf34b3c108ff30baae1d2261f216f4f3 (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.cpp12
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()) {