Skip to content

fix(agc): render a nonzero slice of an XOR color view with MIP0_DEPTH 0 into its array slice - #4937

Closed
Tamalero wants to merge 1 commit into
boykopovar:mainfrom
Tamalero:fix/agc-color-view-slice-of-unsized-array
Closed

Tamalero wants to merge 1 commit into
boykopovar:mainfrom
Tamalero:fix/agc-color-view-slice-of-unsized-array

Conversation

@Tamalero

Copy link
Copy Markdown
Contributor

What

A color view of a nonzero slice with CB_COLOR_ATTRIB3 MIP0_DEPTH = 0 renders into the wrong bytes under the 64 KiB XOR swizzle modes. High on Life (PPSA15388) draws every face of its sky-light cube this way, and the cube comes back scrambled. That is the stale-mip pattern in #4736.

The downsample pass draws face f with:

  • CB_COLOR_VIEW = 0x1c00a005 for face 5 (slice start = slice end = f);
  • CB_COLOR_ATTRIB3 = 0x4dc6c000 (MIP0_DEPTH 0, 2D, SW_64KB_R_X).

Cause: DecodeColorBuffer keeps the array slice only when MIP0_DEPTH is nonzero. With MIP0_DEPTH 0 it adds slice × slice size to the address and renders a standalone 2D surface there, so the slice term of the swizzle is lost. In the R_X equations in TextureSwizzleEquations.hpp (from addrlib's GFX10 non-RB+ pattern tables), at 8 bytes per element, byte-address bits 8–11 are XORed with slice bits 3–0. Slice 0 is unaffected. For slices 1–5 the bytes land in permuted 256-byte blocks, and the cube texture that later reads slice f sees them in the wrong order. The pass also downsamples into mip tails, which share a 64 KiB block, so the permutation mixes mips there.

Fix: a nonzero slice of an XOR color view with MIP0_DEPTH 0 becomes slice slice of an array of max(slice, last slice) + 1 layers at the surface base. That is the path MIP0_DEPTH ≠ 0 already takes. Linear and non-XOR views are unchanged.

The source is the slice term in the existing addrlib-derived equations. This has not been measured on hardware: I have no capture showing the CB applies the slice term when MIP0_DEPTH is 0. The game's own use is the evidence. It draws face f this way and samples the six faces as a cube, so the slice term must apply.

Tested

Checklist

🤖 Generated with Claude Code

… 0 into its array slice

CB_COLOR_VIEW selects slice N while CB_COLOR_ATTRIB3 MIP0_DEPTH is 0. The
XOR swizzle equations take the slice index, so the view addresses slice N
of an array at the surface base, not a 2D surface N slices further on.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@xXPBSXx

xXPBSXx commented Oct 13, 2026

Copy link
Copy Markdown
Contributor

Windows test (MinGW GCC 15.2, Release, Windows 10, RTX 4080 SUPER). Built on main 88107b7de together with thirteen other open GPU PRs (their own commits cherry-picked, no merge commits), so only the tests that belong to this PR say something about it:

  • tests/execution/ArrayLayerTarget.cpp (agc_driver_array_layer_target): 3 of 3 runs passed.

Not tested: no game run. The batch was built once, not per PR; nothing failed, so no bisect was needed.

AI-assisted (Claude Code).

@github-actions github-actions Bot added the needs rebase Conflicts with main, rebase needed label Oct 13, 2026
@Tamalero

Copy link
Copy Markdown
Contributor Author

Closing as superseded by #4551, which fixes the same bug (a nonzero slice of an XOR color view with MIP0_DEPTH 0 loses its slice term) and merged today. #4551 keeps the shifted 2D surface and folds the slice's equation bits into the pipe/bank XOR; this PR rendered the view into the array slice instead. Both put the bytes where the hardware does. #4551 was opened first, from Lost Soul Aside's reflection cube (#4387), which is the same symptom as High on Life's in #4736.

Thanks @xXPBSXx for the Windows run. I'll recheck High on Life's cube on main with #4551 and report on #4736.

Tested and written by Claude (AI assistant) on a contributor's machine.

@Tamalero Tamalero closed this Oct 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agc libSceAgc* needs rebase Conflicts with main, rebase needed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants