Skip to content

Voodoo: Fix nccTable0 Q2 writes landing in the I2 coefficient - #7926

Merged
OBattler merged 1 commit into
86Box:masterfrom
MaxFreedomPollard:fix/voodoo-ncc-q2
Sep 11, 2026
Merged

OBattler merged 1 commit into
86Box:masterfrom
MaxFreedomPollard:fix/voodoo-ncc-q2

Conversation

@MaxFreedomPollard

Copy link
Copy Markdown
Contributor

Summary

Textures in the NCC (YIQ) compressed formats decoded through NCC table 0 come out with the wrong colours on the emulated Voodoo. Table 1 is fine, so the same texture looks right or wrong depending only on which table the game selected through TEXTUREMODE_NCC_SEL.

The cause is in voodoo_reg_writel(). The SST_nccTable0_Q2 case assigns voodoo->nccTable[tmu][0].i[2] instead of q[2] (src/video/vid_voodoo_reg.c:1152 and :1156). I2 (0x33c) and Q2 (0x34c) are two different registers (src/include/86box/vid_voodoo_regs.h:234 and :238), but both cases write i[2], so nothing in the tree ever writes nccTable[tmu][0].q[2]. Two things go wrong: the Q2 coefficient of table 0 keeps its reset value of zero, and i[2] ends up holding whichever of the two registers the driver wrote last. Every other NCC case in the function writes its own component, including the table 1 twin at src/video/vid_voodoo_reg.c:1337.

voodoo_update_ncc() indexes i[] and q[] independently, with i = (col >> 2) & 3 and q = col & 3 (src/video/vid_voodoo_display.c:65-66). So table 0 decodes wrong in at least the 64 entries with Q index 2, which lose the Q2 coefficient whatever the driver does. When the driver writes I0 to I3 before Q0 to Q3, i[2] is clobbered as well and 112 of the 256 entries are wrong: 64 with Q index 2, 64 with I index 2, 16 of them shared. That table is what voodoo_use_texture() uses for TEX_Y4I2Q2 and TEX_A8Y4I2Q2 (src/video/vid_voodoo_texture.c:336 and :428). The path is shared by Voodoo 1, Voodoo 2, Banshee and Voodoo 3.

The change is two characters on two lines, i[2] to q[2], matching the shape of the table 1 case. The fall-through chain above it is untouched: it is the bit 31 texture palette write path and it is correct.

How I checked it. clang -fsyntax-only -Wall -Wextra -std=gnu11 on src/video/vid_voodoo_reg.c is silent both before and after the change, so no new diagnostics, and clang-format with the repo style leaves the changed hunk alone.

I did not run this in the emulator, as I have no Qt build here, so the argument is at code level with table 1 as the in-tree control. I built a standalone harness that extracts the NCC register switch, voodoo_update_ncc() and the register offsets verbatim from the tree, writes the same Y, I and Q coefficients to both tables, and compares the two decoded 256 entry lookups. Before the change 112 of 256 entries differ between table 0 and table 1 in I then Q write order, and 64 of 256 in Q then I order; after it, 0 differ in either order. Writing the same registers again with bit 31 set gives the same palette checksum before and after, so the palette path is unaffected.

Checklist

  • I have tested my changes locally and validated that the functionality works as intended

References

The evidence is in the tree. The SST register map gives each NCC table twelve distinct registers, Y0 to Y3 at 0x324 to 0x330, I0 to I3 at 0x334 to 0x340 and Q0 to Q3 at 0x344 to 0x350 (src/include/86box/vid_voodoo_regs.h:228-239), and voodoo_update_ncc() indexes i[] and q[] from separate bit fields of the texel, so an I coefficient sitting in a Q slot is not a harmless aliasing (src/video/vid_voodoo_display.c:65-66). The table 1 block is the control: SST_nccTable1_Q2 already writes q[2] (src/video/vid_voodoo_reg.c:1337).

The SST_nccTable0_Q2 case assigned nccTable[tmu][0].i[2] instead of
q[2], so the Q2 chroma coefficient of NCC table 0 was never stored and
i[2] ended up holding whichever of the two registers the driver wrote
last. Every other NCC case in the function, including the table 1 twin
SST_nccTable1_Q2, writes its own component. voodoo_update_ncc() reads
i[] and q[] independently, so 64 of the 256 decoded entries of table 0
always came out with the wrong colour, and 112 of 256 in the usual I
before Q write order, for Y4I2Q2 and A8Y4I2Q2 textures.
@OBattler
OBattler merged commit 101a7fe into 86Box:master Sep 11, 2026
44 of 45 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants