Skip to content

fix(agc): treat other-shaped views of a depth surface's memory as reused memory - #1495

Merged
adriadam10 merged 3 commits into
boykopovar:mainfrom
TideOPL:fix/agc-depth-memory-reuse
Oct 10, 2026
Merged

adriadam10 merged 3 commits into
boykopovar:mainfrom
TideOPL:fix/agc-depth-memory-reuse

Conversation

@TideOPL

@TideOPL TideOPL commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

What

Engines alias transient render targets, so a texture can sit at the address of a depth surface after that memory has been handed to a color image: a 384x384 R11G11B10 texture over a 384x384 D32S8 surface, for example. DepthSurfaceTexture sent every texture at a depth surface's address to DepthSurface::Sampled, which threw sampling the depth plane ... is not implemented, and the draw was skipped.

Now a view with a different extent, or a depth-plane view in a format that cannot hold the plane, is treated as reused memory. "Cannot hold the plane" means it is neither the plane's own R32F / R16 unorm nor a T# that reads the raw depth bits. The lookup returns null, so the texture goes through the ordinary texture path, as it would at any other address. Stencil-plane views keep their current handling.

#425 rewrites DepthSurfaceTexture for array and cube depth reads but has no reuse rule. The two touch the same function, so whichever merges second needs a small rebase.

Tested

Windows 11, NVIDIA RTX 5070 (driver 610.88).

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 in TechnicalDebt
  • 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 (overlaps feat(agc): depth planes sampled as 2D arrays, cubes and integer views #425 textually)
  • AI-assisted: yes

…sed memory

Engines alias transient render targets, so a texture can sit at the
address of a depth surface after the memory has been handed to a color
image: a 384x384 R11G11B10 texture over a 384x384 D32S8 surface, say.
Sampling it threw "sampling the depth plane ... is not implemented"
and the draw was skipped.

A view with another extent, or a depth-plane view in a format that
cannot hold the plane (neither the plane's own R32F / R16 unorm nor a
T# that reads the raw depth bits), is now treated as memory reuse: the
lookup falls through to the ordinary texture path instead of the depth
surface. Stencil-plane views keep their current handling.

@klosixgaming-arch klosixgaming-arch left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good improvement to depth surface texture matching. This adds proper validation to ensure the depth format matches between the requested resource and existing depth surfaces, preventing incorrect texture reuse that could cause rendering issues.

Strengths:

  • Clean implementation with proper validation of width, height, and depth format
  • Good handling of both depth-only and stencil surfaces
  • Proper use of ShaderRecompiler::DepthBitsTextureWidth for format detection
  • Correct distinction between D16 and D32 formats

This will improve rendering correctness by preventing mismatched depth texture reuse. Ready to merge.

@orbz22

orbz22 commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

Another case this rule fixes, from Astro's Playroom (PPSA01325), Windows 11 / RTX 3060 Laptop:

  • After the start sequence, the game renders its shadow map at 0x529430000 as a 1536x1536 depth target. An earlier scene had used the same memory as a 2048x2048 D16 surface (vk format 124), and that surface is still resident.
  • The deferred lighting dispatch 0x5001c6a00 samples the memory as a 1536x1536 2D array (guest format 7, R16 unorm, tile mode 4, slice 0). On main, ValidateSampled throws, and because the format is depth-like the title aborts:
compute shader 0x5001c6a00: AGC graphics: sampling the depth plane of depth surface 0x529430000 (2048x2048, vk format 124) as a 1536x1536 texture of guest format 7 (vk 70), tile mode 4, dimension 2, levels 0-0, slice 0 is not implemented
  • On main this crash only shows up when no stale stage-A cache entry hides the depth surface; fix(agc): sample resident depth surfaces when a stage-A texture record hits #1957 removes that stale entry, so it shows up more often.
  • Locally I applied the same extent rule as this PR (return null for another extent, arrays included), retired the old surface, and preferred a resident surface of the sampled extent when several share the address. With that, the game runs on into the in-game DualSense platform with correct shadows.

The preference matters when both shapes are resident: a newest-first search can return the other one. That could be a follow-up; it's not needed for this PR.

@hugodearaujo

hugodearaujo commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

Another title that hits this: Hollow Knight: Silksong (PPSA12544) on Linux (RX 9070 XT), after lowering the in-game resolution scale.

Before this PR:

AGC graphics: sampling the depth plane of depth surface 0x265e90000 (1920x1080, vk format 130) as a 1882x1058 texture of guest format 56 (vk 37), tile mode 7, dimension 1, levels 0-0, slice 0 is not implemented

With this PR, that stop is gone. The same reuse then happens on the stencil plane, which this PR leaves as it was:

AGC graphics: sampling the stencil plane of depth surface 0x266010000 (1766x994, vk format 130) as a 1766x994 texture of guest format 56 (vk 37), tile mode 7, dimension 1, levels 0-0, slice 0 is not implemented (T# 02667200 43800000 00f841b9 91b00fac 00000000 00700000 107b0000 00026671)

The extent matches, but an R8G8B8A8 view cannot be a stencil read: Sampled only accepts VK_FORMAT_R8_UINT for that plane. Applying the same rule to the stencil plane gets the title past this point:

const bool stencil = target.stencilAddress != 0 && resource.baseAddress == target.stencilAddress;
if (stencil && ResolveTextureFormat(resource.format) != VK_FORMAT_R8_UINT) return nullptr;

I only ran it locally, so I'm leaving it here in case you want it in this PR rather than opening a separate one.

Base for these runs: main + #1836 + #1431 + #846 + #2323 + #861 + #2401 + #1902.

@github-actions

github-actions Bot commented Oct 9, 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
#374 core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp L172
#454 core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp L169-172
#1186 core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp L172
#2053 core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp L172
#2076 core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp L172
#2169 core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp L172
#2490 core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp L172
#2491 core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp L172

@adriadam10 adriadam10 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the fix, and for the title logs. The rule looks right to me, but it needs a test before it can merge:

  • No test covers this. Fixes for a title-specific crash need a Linux test that reproduces the case (CONTRIBUTING: tests next to their component, registered in ctest). Suggested cases in the existing libSceAgcDriver graphics tests: a depth surface plus a texture at the same address with (a) a different extent, (b) the same extent but a colour format that cannot hold the plane (e.g. R11G11B10), (c) a 2D array view of a different extent (the Astro's Playroom case reported by @orbz22). Each must go through the ordinary texture path instead of throwing, and a texture of the surface's own extent and R32F/R16 must still hit DepthSurface::Sampled. The new tests must fail on main.
  • DepthSurface.cpp:178-179: please pin the "raw depth bits" exception (DepthBitsTextureWidth) with a test row too, so the !depthBits branch is covered both ways.
  • @hugodearaujo reports (Silksong, PPSA12544) the same reuse on the stencil plane with an R8G8B8A8 view, which this PR leaves as is. If you add the R8_UINT check for the stencil plane here, add a test row for it as well. Otherwise it is a separate PR.
  • CI covers the build only; the title runs (PPSA16064 / PPSA01325 / PPSA12544) are not something we can reproduce, hence the test request.

agc_driver_graphics registers a D32 and a D16 surface on a mock device and looks up views at their addresses. Views of the surface's own extent in R32F or R16, and T#s that read the raw depth bits, sample the depth plane; a view of another extent, a 2D array view of another extent, an R11G11B10 view, an R32 uint view without a depth layout and an R32F view of a D16 surface return null and take the ordinary texture path. On main the first of these throws in DepthSurface::Sampled.
@TideOPL

TideOPL commented Oct 10, 2026

Copy link
Copy Markdown
Contributor Author

Thanks. I added RunDepthSurfaceReuseTests to agc_driver_graphics (tests/DepthSurfaceReuse.cpp, mock device, no GPU needed). It registers a 384x384 D32 and a 256x256 D16 surface:

  • (a) R32F view at 192x192 → null (ordinary texture path)
  • (b) R11G11B10 view at the surface's own extent → null
  • (c) 2D array view at 512x512, 6 layers → null
  • R32F view of the D32 surface and R16 view of the D16 surface at their own extents → DepthSurface::Sampled
  • raw depth bits: R32 uint (D32) and R16 uint (D16) views in a depth tile layout → Sampled; R32 uint in a render-target layout → null
  • R32F view of the D16 surface → null

On current main it fails in Sampled ("sampling the depth plane ... is not implemented"). Full ctest passes on Linux and Windows. I left the stencil-plane check for a separate PR.

@adriadam10 adriadam10 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the test. Checked: the new cases pass, and they fail with DepthSurface.cpp reverted (negative check); libSceAgcDriver ctest 270/270 green on current main. Merging once CI is green.

@adriadam10
adriadam10 merged commit 806ff29 into boykopovar:main Oct 10, 2026
8 checks passed
SleglJan pushed a commit to SleglJan/AnyPS5 that referenced this pull request Oct 10, 2026
…reuse

fix(agc): treat other-shaped views of a depth surface's memory as reused memory
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.

5 participants