diff --git a/docs/emulation-bug-hunt-todos.md b/docs/emulation-bug-hunt-todos.md index 28b2b1b2..b402dd47 100644 --- a/docs/emulation-bug-hunt-todos.md +++ b/docs/emulation-bug-hunt-todos.md @@ -77,6 +77,17 @@ describe guesses, timing gaps, or known emulation shortcuts. road/ground rendering. ## Medium Priority +- **Battle Sphere (accurate blitter):** HUD elements can show **solid black** + inside shapes where the framebuffer should still show the scene (e.g. cockpit + reticles / targeting squares). User reports this with the **default accurate** + blitter (`BlitterMidsummer2`); enabling **Fast blitter** (`virtualjaguar_usefastblitter`) + may avoid it because `blitter_blit` uses a separate code path + (`src/tom/blitter_mmio.c` dispatches on `vjs.useFastBlitter`). Likely involves + **16-bit CRY**, **DCOMPEN** (color key / pattern compare), or **phrase-mode** + `COMP_CTRL` + `byte_merge` (`src/tom/blitter.c` `DATA()`, `blitter_simd_scalar.c`) + not matching hardware for inner pixels. Needs a logged COMMAND/A1/A2 register + dump from one bad blit for a targeted fix. + - `src/tom/tom.c`: replace hard-coded visible-window constants with values derived from TOM timing registers where possible. This should be tested against NTSC, PAL, and games that reprogram HDB/HDE/VDB/VDE. diff --git a/src/tom/blitter.c b/src/tom/blitter.c index 01560b41..c084b972 100644 --- a/src/tom/blitter.c +++ b/src/tom/blitter.c @@ -1686,9 +1686,13 @@ A2ptrldi := NAN2 (a2ptrldi, a2update\, a2pldt);*/ Start and end from the address level of the pipeline are used. */ - //Phrase mode needs destination data for start/end mask byte merging, - //but NOT when bkgwren is set (hardware uses DSTDATA register value). - if (phrase_mode && !dsten && !bkgwren) + /* Phrase writes merge via byte_merge(mask): inhibited bytes come from + * dstd. With !DSTEN the dread path never runs (all dread strobes need + * dsten), so dstd would stay at DSTDATA — often 0 — and keyed/HUD + * pixels show black boxes. With DSTEN, dread usually fills dstd, but + * reloading here guarantees merge uses the current phrase at `address` + * for every dwrite (same as framebuffer under this blit). */ + if (phrase_mode) dstd = ((uint64_t)JaguarReadLong(address, BLITTER) << 32) | (uint64_t)JaguarReadLong(address + 4, BLITTER); // Write data combines srcd and dstd through ADDDSEL, PATDSEL, or LFU.