ppu: rebuild bg pair LUT after priority |= 64, fixes Mega Man 3 sprites

The pair LUT introduced in a502cea was built at the top of
RefreshLine, before the

    Pal[0] |= 64;
    Pal[4] |= 64;
    Pal[8] |= 64;
    Pal[0xC] |= 64;

block that follows.  That OR sets the 0x40 "background priority"
marker on the universal-background entries of PALRAM (Pal is
`#define Pal (PALRAM)`), so that the framebuffer downstream of the
pputile.h tile expansion can distinguish BG-colour pixels from
true zero-pen pixels for sprite priority / sprite-0-hit testing.
The matching `Pal[i] &= 63` at the bottom of the function strips
the bit again after rendering.

Building the LUT before the |= 64 meant entries 0/4/8/0xC carried
the PALRAM value WITHOUT the priority bit, so every tile pixel that
expanded to one of those four indices wrote a plain palette index
to the framebuffer instead of (palette | 0x40).  Sprite compositing
then could not tell which BG pixels were the universal background,
and broke priority for games that exercise Pal[0x04/0x08/0x0C] --
Mega Man 3 sprites were reported.

Fix: move the FCEU_BuildBgPairLUT() call to just after the
`Pal[i] |= 64` block.  The LUT is now built with the priority bit
present in entries 0/4/8/0xC and bit-exactly matches what the
original eight-load scalar code reads from PALRAM during the
pputile.h includes.  No second rebuild is needed before the
`Pal[i] &= 63` cleanup because the LUT is only consumed inside
the includes, which sit between the OR and the AND.

Mid-scanline RefreshLine entries via FCEUPPU_LineUpdate continue
to work: each entry walks the same |= 64 -> BuildLUT -> includes
-> &= 63 sequence, so any $3F00..$3F0F write the CPU made since
the previous span is folded into the LUT before the resumed tile
span renders.

Codegen unchanged: still one leaq fceu_bg_pair_lut at function
entry, 48 indexed LUT loads across the 12 pputile.h expansion
sites, one movq per site to P.
This commit is contained in:
libretroadmin
2026-06-14 14:37:35 +00:00
committed by U-DESKTOP-SPFP6AQ\twistedtechre
parent 01b7446a66
commit 6911042cf6

View File

@@ -138,12 +138,16 @@ uint8_t UPALRAM[0x03];/* for 0x4/0x8/0xC addresses in palette, the ones in
* emit four pair-lookups and a single 64-bit store instead of eight
* serial nibble-load-store iterations.
*
* Rebuilt at the start of every RefreshLine call so that mid-frame
* raster effects writing to $3F00-$3F0F see their pen changes on the
* very next scanline. 256 entries x ~3 ops = ~768 ops per rebuild;
* RefreshLine runs once per scanline plus the occasional mid-scanline
* call from FCEUPPU_LineUpdate, so the worst-case rebuild cost is
* well under 1% of frame budget. */
* Rebuilt INSIDE RefreshLine just before the pputile.h includes, so
* that:
* (a) any PALRAM[0x00..0x0F] change since the previous RefreshLine
* is reflected on the next tile span, and
* (b) crucially, the 0x40 "background priority" bit that RefreshLine
* OR's into Pal[0/4/8/0xC] right before rendering -- and ANDs
* off again after -- is captured in the LUT. Without that the
* sprite compositor cannot tell BG-color pixels apart from the
* universal background, breaking sprite priority for any game
* that hits Pal[0x04/0x08/0x0C] (e.g. Mega Man 3 sprites). */
static uint16_t fceu_bg_pair_lut[256];
static void FCEU_BuildBgPairLUT(void)
@@ -468,13 +472,6 @@ static void FASTAPASS(1) RefreshLine(int lastpixel) {
if (numtiles <= 0) return;
/* Rebuild the bg pair LUT once per RefreshLine call. This covers
* both per-scanline calls from FCEUPPU_Loop and mid-scanline calls
* from FCEUPPU_LineUpdate (raster effects); any PALRAM[0x00..0x0F]
* change done since the previous RefreshLine is reflected for the
* about-to-be-rendered tile span. */
FCEU_BuildBgPairLUT();
P = Pline;
vofs = 0;
@@ -512,6 +509,17 @@ static void FASTAPASS(1) RefreshLine(int lastpixel) {
Pal[8] |= 64;
Pal[0xC] |= 64;
/* Rebuild the bg pair LUT *after* the priority |= 64 modification
* above so that the LUT entries for PALRAM[0/4/8/0xC] carry the
* 0x40 bit while the pputile.h includes below run. The matching
* Pal[i] &= 63 cleanup at the bottom of this function does NOT
* require a second rebuild: the LUT is only consumed by the
* pputile.h block, which runs between the |= 64 and the &= 63.
* The LUT is also rebuilt at every mid-scanline RefreshLine call
* via FCEUPPU_LineUpdate, picking up any $3F00..$3F0F write the
* CPU made since the previous tile span. */
FCEU_BuildBgPairLUT();
/* This high-level graphics MMC5 emulation code was written for MMC5 carts in "CL" mode.
* It's probably not totally correct for carts in "SL" mode.
*/