Repository navigation
feat(libSceAgcDriver): storage image access to depth surfaces - #4500
Conversation
|
Windows build of head
Not run: the GPU tests ( AI-assisted (Claude Code). |
|
@ee6aba54 I ran the stencil test from my follow-up to #425 against this PR ( It checks the one path
It's a single file, AI-assisted: yes. |
A texture over a depth surface could only sample one 2D slice of the
plane's own format; 2D arrays, cubes and the R16_UINT view of a D16
plane were refused ("sampling the depth plane of depth surface ... is
not implemented"). A one-slice 2D array now views the depth image as an
array. Several slices, a cube, or an integer view of a D16 plane are
copied into a DepthPlaneCopy image at every use: each slice from the
depth surface bound at its address (base plus one 64 KiB-block depth
slice per layer), otherwise from guest memory, detiled. A depth-bits
R16_UINT view (a depth swizzle) keeps the depth copy, since the shader
converts the sampled depth to its bits itself (GTA V's compute
0x242d4a200 samples a D16 plane array that way, reported by
@tibzejoker). Such a texture is not kept in resource templates.
Storage-image access to depth surfaces is no longer part of this
change; boykopovar#4500 implements it.
TechnicalDebt (Depth plane copies) and ARCHITECTURE describe the copy and
what still throws.
|
For coordination: #425 had a storage path for depth surfaces too. I've taken it out, so storage access to depth surfaces is this PR's alone. #425 now only samples depth planes as 2D arrays, cubes and R16_UINT views ( |
dfa8766 to
0d32f7e
Compare
|
Thanks for the reviews. Updated to
|
0d32f7e to
cdfba51
Compare
|
Updated to
|
|
Data point from a title we test with, on |
A texture over a depth surface could only sample one 2D slice of the
plane's own format; 2D arrays, cubes and the R16_UINT view of a D16
plane were refused ("sampling the depth plane of depth surface ... is
not implemented"). A one-slice 2D array now views the depth image as an
array. Several slices, a cube, or an integer view of a D16 plane are
copied into a DepthPlaneCopy image at every use: each slice from the
depth surface bound at its address (base plus one 64 KiB-block depth
slice per layer), otherwise from guest memory, detiled. A depth-bits
R16_UINT view (a depth swizzle) keeps the depth copy, since the shader
converts the sampled depth to its bits itself (GTA V's compute
0x242d4a200 samples a D16 plane array that way, reported by
@tibzejoker). Such a texture is not kept in resource templates.
Storage-image access to depth surfaces is no longer part of this
change; boykopovar#4500 implements it.
TechnicalDebt (Depth plane copies) and ARCHITECTURE describe the copy and
what still throws.
cdfba51 to
ac2ffc4
Compare
|
Rebased onto |
|
Astro's Playroom (PPSA01325) data point for head On With this PR merged onto
|
|
Pushed two commits on top of your rebase (848b97b), fast-forward, yours untouched:
Linux, RTX 4090: The 2D-array case is the one The Pathless (PPSA01825) hits in the Windows report above, so it stops there again until one-layer array views are handled; that is a separate change. This will conflict with #2491 in |
Compute shaders bind the depth and stencil planes of a depth surface as storage images, to read the depth or to write it before later draws test against it. The driver kept depth on the GPU and refused such bindings. A depth surface now owns one storage image per plane (R32_SFLOAT or R16_UNORM for depth, R8_UINT for stencil). Binding copies the plane into it through a staging buffer; a written element is copied back into the depth image during write-back, so the next draw sees the shader's depth. A view whose extent differs from the surface's means the memory was reused for another texture and takes the ordinary texture path; this applies to sampled views of a depth surface too. PPSA15304 copies depth and stencil through storage images every frame.
A D16_UNORM_S8_UINT surface is stored as D24_UNORM_S8_UINT or D32_SFLOAT_S8_UINT on devices without the 16-bit format. Copying its depth aspect yields 4 bytes per texel, so the 16-bit storage image of the depth plane would receive the wrong layout. Such an access now throws, naming the surface and both formats; the stencil plane keeps its 8-bit layout and stays supported.
A 2D array or cube view with the plane's extent and format reached the ordinary path and read guest bytes the depth was never written to; it throws again, with the message main has for it. A multisampled surface is refused before the plane copy, as sampling it already is. A written view that another view of the same plane replaced had its results dropped at store-back; that throws now. Update the debt entry to what is supported and what still throws.
Draw depth and stencil, read and rewrite each plane in compute dispatches, and check the stored values with depth-tested and stencil-tested draws, a following dispatch and the flushed guest bytes. The array view, multisampled and two-view refusals are checked through dispatches as well.
A sampled copy of a depth plane is kept while the surface's write serial is unchanged. Storing a written storage view back into the depth image did not bump the serial, so a later draw or dispatch that sampled the plane as an array or cube kept the values from before the store. The store-back bumps it now. The dispatch test samples the plane through a copy, stores to it in a dispatch and samples it again.
848b97b to
f15671e
Compare
|
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.
|
127 files conflicted. Resolved per group (AgcDriver depth / graphics / execution, shader recompiler + libSceAgc, libc, libkernel, net/np, media, Usbd, misc, docs), each group checked against both sides by a second pass. Kept from local: the Astro Bot perf work (draw prep helper, per-unit pending image checks, depth plane copies only for changed slices, layer copy on the device, register clear without the key-fill wait, GDS DMA_DATA without drains, 32-bit fault words for validated V# atomics, request version 22 with frontFaceAllBits), local swscanf_s/vsscanf_s, cpuset_getaffinity, Mbed TLS, the libSceUsbd transfer tracking on top of main's libusb path, the libReactNative VSH modules main deleted (boykopovar#5010), the Ngs2 GeomApply and AudioIn Hq/Async open implementations. Took main: sceKernelFcntl (File::Fcntl), sceCoredumpDebugTextOut, asinl, nan/nanf, the depth/stencil plane storage path (boykopovar#4500/boykopovar#2076) in cachedStorageTexture, the epoll model in libSceHttp, Json2 setSpecialFloatFormatType storing any value (RE4, PRAGMATA call it), the per-library debt files under docs/dev/debt. Post-merge fixes: DrawKeyRegisters holds 50 ranges, draw prep passes the hidden user words, duplicate VideoOut stubs and libc definitions removed, APS5_LIST_ALL_COMPLETION_WRITERS also restores whole-write overlap tests in the readers, tests adjusted where the kept implementation changed on purpose (fcntl, pm4 message, pixel push slots, v19 request layout, font syllable state, Json2, depth plane drawn note, atomic fault words). Build clean, test_fast 1125/1125 (guest_raise_exception and guest_video_out_high_frame_rate pass alone; parallel-load timing). Progress 3248/3529 -> 3387/3716.
…ed path SILENT HILL: The Short Message (PPSA10112) stopped at "compute shader 0x2007a70000: AGC graphics: storage image access to depth/stencil surface 0x205da70000 is not implemented (storage=1024x1024 guest format=7 mip=0 dimension=2 tile=4)": a compute shader binds a depth surface as a 2D array storage image of more than one layer. Main's depth plane storage path (boykopovar#4500/boykopovar#2076), which replaced our boykopovar#425 port in the e965b46 merge, takes one layer only. DepthSurface::Storage now leaves a depth (not stencil) 2D array from layer 0 to the ordinary storage path, and cachedStorageTexture seeds that image from the depth slices again (SeedStorageFromDepth: every layer that is a depth surface of its own is copied in, the surface becomes its writer and takes its writes back when it is drawn to; the code the merge left without a caller). Stencil arrays and arrays from a later layer still refuse. Tests: agc_driver_depth_storage expects the two-layer depth view to be left to that path; agc_driver_depth_storage_dispatch now stores through a two-layer 2D array view and requires the depth test to see layer 0's stored row (was: expected the refusal). test_fast 1126/1127 (windows_import_modules = Defender WinError 225).
Compute shaders bind the depth and stencil planes of a depth surface as storage images, to read the depth or to write it before later draws test against it. The driver kept depth on the GPU and refused such bindings. A depth surface now owns one storage image per plane (R32_SFLOAT or R16_UNORM for depth, R8_UINT for stencil). Binding copies the plane into it through a staging buffer; a written element is copied back into the depth image during write-back, so the next draw sees the shader's depth. A view whose extent differs from the surface's means the memory was reused for another texture and takes the ordinary texture path; this applies to sampled views of a depth surface too. PPSA15304 copies depth and stencil through storage images every frame. (cherry picked from boykopovar#4500, commit 0d32f7e, onto local/main-sync-20261011b) Conflicts with the local depth/stencil storage alias path (dd16d16): both kept; the plane storage images are tried first, the cache plus SeedStorageFromDepth handle the rest. This base has no StorageTexture::Create (make_shared instead) and no RequireNoMultisampleTarget (no MSAA targets).
…s path lean-x10 died at 1230 s on compute 0x8000405d00: a 3840x2160 R16G16B16A16_SFLOAT storage image at the address of a D32 depth surface of the same extent reached the local alias path (SeedStorageFromDepth -> Transfer), which refused it. boykopovar#4500's plane storage already returns nullptr for that view; the alias path now applies the same rule: a view of another extent, or in a format that cannot hold the plane's bits, is reused memory (ordinary storage image, no seed, no copy-back). Glue between the two paths: a plane's own storage image is stored back right after its writes and is skipped by the deferred copy-back, but the ownership guard still sees it; binding it first lands pending alias writes; a stencil plane with a programmed SW_MODE or HTILE keeps the alias layout checks; plane copies fall back to a command batch when no recorder is active and take the GPU lock like the rest of the file.
lean-x10 went over the VRAM budget (vk_device 13.5 GB in 34k allocations, 23k images, 51k buffers) with no way to tell who holds it. Creation sites now name their owner with a thread-local MemoryStats::OwnerScope (sampled and storage textures, depth surfaces and boykopovar#4500's plane storage, attachment proxies, depth copies, render targets, colour transfers, texture uploads, guest-buffer staging shadows, mirrors, host imports, unit-shadow slabs, draw snapshots and scratch, ShaderResources buffers, BDA, workgroup memory, presentation). The device wrapper charges vkAllocateMemory to the innermost owner (the buffer pool's own allocations to pool_device / pool_host / pool_slab) and counts live VkImages/VkBuffers per owner; pooled Buffer/DeviceBuffer objects count as live under the owner that asked (pooled_<owner>), so a pool tier splits into users and retained rest. The [mem] line gains devmem_/hostmem_/importmem_/img_/buf_/pooled_ fields (non-zero only) and vk_device_unattributed. Off unless APS5_MEM_STATS is set: a scope then costs one static check; nothing under core/shader/recompiler changes (SourceVersion 16c99fcab2ec7b8c).
What
Compute shaders bind the depth and stencil planes of a depth surface as storage images, to read the depth or to write it before later draws test against it. The driver kept depth on the GPU and refused such bindings ("storage image access to depth/stencil surface ... is not implemented").
A depth surface now owns one storage image per plane (
R32_SFLOATorR16_UNORMfor depth,R8_UINTfor stencil). Binding applies a pending fast clear and copies the plane into the storage image through a staging buffer (the depth image is created withVK_IMAGE_USAGE_TRANSFER_SRC_BITfor that copy); a written element is copied back into the depth image during write-back, so the next draw sees the shader's depth. A view of another extent, or of a format that is not the plane's, takes the ordinary texture path, asDepthSurfaceAtalready decides for sampled views; a view of another level still throws.A
D16_UNORM_S8_UINTsurface that the device stores asD24_UNORM_S8_UINTorD32_SFLOAT_S8_UINTholds 4 bytes per depth texel, so a storage view of its depth plane throws, naming both formats; its stencil plane is supported.This is the storage counterpart of the depth copy that comparison sampling takes since d024709. The refused binding is the stop reported in #1409 (PPSA10112); that title is not tested here.
Tested
1c5e62878.ctest: 996 tests pass.agc_driver_depth_storage(RTX 5080) checks both copy directions for depth and stencil, the reuse of the storage image, the fall-through for another extent or format and the refusal of another level;agc_driver_depth_storage_reuseandagc_driver_depth_compare_copystill pass.agc_driver_graphics: on a device withoutD16_UNORM_S8_UINT, a storage view of the depth plane of a D16 surface with stencil throws.D32_SFLOAT_S8_UINTtarget through storage images every frame; the dispatch that stopped the title now runs, and together with fix(agc): count every CP data write of a dispatch group as a write of the run #4586 and layered rendering into 3D color targets (the change feat(agc): render layered draws into 3D color targets #1077 proposes) the title reaches its main menu.Checklist
main; no other open PR implements the same functionsNotImplemented_nid_no_patch); silent stubs are listed in TechnicalDebt.mdfiles or images added to the repository (attach them to this PR)🤖 Generated with Claude Code