Skip to content

fix(agc): read 128-bit T#s that start past MAX_MIP from their resident levels - #8962

Merged
oneandonlydean merged 1 commit into
boykopovar:mainfrom
Celegans12:fix/agc-r128-texture-max-mip
Oct 22, 2026
Merged

oneandonlydean merged 1 commit into
boykopovar:mainfrom
Celegans12:fix/agc-r128-texture-max-mip

Conversation

@Celegans12

Copy link
Copy Markdown
Contributor

What

An R128 image instruction reads only words 0-3 of its T#, and the recompiler passes words 4-7 as zero (getImageResource), so DecodeTextureResource sees MAX_MIP 0. A 128-bit T# with a BASE_LEVEL above 0 then throws "starts past the surface's last mip level at levels that would move the surface's own". Ghost of Yōtei's streamed textures are like that: a 2048x2048 BC3 T# naming levels 2..11, of which only those 10 levels are resident.

  • When words 4-7 are all zero and the T# would be refused this way, the decoder reads it as a 128-bit T#: MAX_MIP = LAST_LEVEL, with levels BASE..LAST described as their own chain (size shifted by BASE_LEVEL, MIN_LOD moved with it). It does this only when DescribeSurface gives each of those levels the same offset, size and tail slot as in the full chain (GFX10 places a chain from its last level up, so the resident levels start the allocation).
  • Only 1D and 2D T#s are read this way. Any other type, a layout that doesn't match, or a T# with any of words 4-7 set still throws as before.
  • The driver can't tell a 128-bit access from a 256-bit T# whose words 4-7 are zero, so it takes the 128-bit reading only where the 256-bit one is refused. A zero-tail T# starting at level 0 still decodes as one level.

Overlaps: #8564 adds EncodeTextureResource right below the refusal this PR changes (textual only). #7948 and #8429 edit other parts of DecodeTextureResource and its test and merge cleanly with this PR. #6977 edits the same function too but already conflicts with main.

Tested

  • Windows 11 Pro, MinGW-w64 GCC 15.2.0, -DBUILD_TESTING=ON, RTX 3080 Laptop, based on main 65c393a: ctest 1834/1838. log_macros, log_macros_timestamps and agc_driver_image_array_window_past_layer_limit (doesn't compile with MinGW) fail on main too; guest_raise_in_host_code timed out under load and passed 3/3 alone.
  • Linux (WSL, lavapipe), CI's job on the merge: 1772/1792; the same 20 fail on main.
  • New R128 cases in agc_driver_graphics: the streamed T# decodes as 512x512 with 10 levels, each equal to level n+2 of the 12-level chain; a 1024x2048 T# of levels 4..11 as 64x128 with 8; MIN_LOD moves with the base level. They fail on main with the "starts past" message. The old 1920x1080 refusal case gets a PERF_MOD so it stays a 256-bit T#.
  • PPSA26344: this reading in our tree's bindless path fixed black streamed rocks in the open world; not run on main.
  • Not tested: AMD, Intel, console behaviour.

Checklist

  • Based on current main; no other open PR implements the same functions
  • One topic per PR; follow-ups go in a new PR
  • No comments in code except technical debt
  • Unimplemented paths throw (NotImplemented_nid_no_patch); silent stubs are listed under Silent stubs in their library's technical debt file
  • No notes, investigation .md files or images added to the repository (attach them to this PR)
  • New third-party code is a submodule built from source
  • Generic behaviour, not specific to one title
  • Depends on: none
  • Fixes: none
  • Unblocks: none
  • GPUs tested: NVIDIA GeForce RTX 3080 Laptop GPU, driver 610.62, Windows 11 Pro; lavapipe (Mesa 25.2.8, WSL Ubuntu 24.04)
  • AI-assisted: yes

…t levels

An R128 image access reads only words 0-3 of its T#; the recompiler
passes words 4-7 as zero, so the decoder saw MAX_MIP 0 and refused a
128-bit T# with BASE_LEVEL above 0 ("starts past the surface's last mip
level at levels that would move the surface's own"). Streamed textures
such as a 2048x2048 BC3 T# naming its resident levels 2..11 hit this.

Where a T# with words 4-7 zero would be refused that way, it is now read
as a 128-bit T#: MAX_MIP = LAST_LEVEL, with levels BASE..LAST described
as their own chain (size and MIN_LOD rebased), but only for 1D and 2D
T#s whose rebased levels have the same offsets, sizes and tail slots as
in the full chain. Everything else still throws as before.

AI-assisted: yes
@github-actions

github-actions Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

Other open pull requests touch the same code. Merging one will break the other, or both implement the same thing. If this one builds on them, list them in Depends on.

Pull request Conflicting files (lines on main) Same exports Same new files
PR 8564 core/libs/prx/libSceAgcDriver/Graphics/src/GuestTextureResource.cpp L7

Some comparisons could not be completed because a pull request conflicts with the base branch. Review these shared files manually before concluding that there is no overlap.

Pull request Shared files not compared
PR 6977 core/libs/prx/libSceAgcDriver/Graphics/src/GuestTextureResource.cpp
PR 9020 core/libs/prx/libSceAgcDriver/Graphics/src/GuestTextureResource.cpp
PR 9335 core/libs/prx/libSceAgcDriver/Graphics/src/GuestTextureResource.cpp
PR 9431 core/libs/prx/libSceAgcDriver/Graphics/src/GuestTextureResource.cpp
PR 9432 core/libs/prx/libSceAgcDriver/Graphics/src/GuestTextureResource.cpp
PR 9672 core/libs/prx/libSceAgcDriver/Graphics/src/GuestTextureResource.cpp
PR 9673 core/libs/prx/libSceAgcDriver/Graphics/src/GuestTextureResource.cpp
PR 9674 core/libs/prx/libSceAgcDriver/Graphics/src/GuestTextureResource.cpp
PR 9675 core/libs/prx/libSceAgcDriver/Graphics/src/GuestTextureResource.cpp
PR 9676 core/libs/prx/libSceAgcDriver/Graphics/src/GuestTextureResource.cpp
PR 9891 core/libs/prx/libSceAgcDriver/Graphics/src/GuestTextureResource.cpp
core/libs/prx/libSceAgcDriver/tests/GuestTextureResource.cpp
PR 9892 core/libs/prx/libSceAgcDriver/Graphics/src/GuestTextureResource.cpp
PR 9893 core/libs/prx/libSceAgcDriver/Graphics/src/GuestTextureResource.cpp
PR 9895 core/libs/prx/libSceAgcDriver/Graphics/src/GuestTextureResource.cpp

@github-actions github-actions Bot added the agc libSceAgc* label Oct 21, 2026
@oneandonlydean oneandonlydean self-assigned this Oct 22, 2026
@oneandonlydean
oneandonlydean merged commit 56cf438 into boykopovar:main Oct 22, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agc libSceAgc*

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants