Repository navigation
perf(agc): copy a pending block-compressed surface into its sampled texture on the GPU - #4747
Conversation
…exture on the GPU A compute pass can write a block-compressed surface through an uncompressed storage view whose element is one block (32_32_UINT for 8-byte blocks, 32_32_32_32_UINT for 16-byte ones). cachedTexture rejected such a storage image for the BC descriptor, so every sample stored the whole surface to guest memory, compared it with the snapshot and uploaded it again. Texture::CanBlockCopyFrom accepts a storage image over the same memory, tiling and swizzle whose element is the block and whose extent is the surface's extent in blocks, with whole blocks on every copied level. The sampled texture then owns a BC image that vkCmdCopyImage refreshes from the storage image when its version moved, through the same refreshed-on-reuse path as the depth copy.
7d38543 to
126a1e4
Compare
|
An Intel run, a second driver for the bit-exact check, and the full suite. Setup: Windows 11 (26200), WinLibs GCC 15.2.0 r7, Release, CI configure flags, an RTX 4070 Laptop GPU and an Intel Raptor Lake-S iGPU. The head 126a1e4 merged into
Written with AI assistance. |
|
Checked on Linux (RADV): |
|
|
|
Independent reproduction on the same reported main commit
Pinned ICDs, explicit GPU selection, I then changed only the temporary fixture to inspect the result:
So this reproduces on another NVIDIA generation/driver, and the explicit-settle control does not point to incorrect first-block bytes from GPU writeback. The stale copied/sampled image or its reuse remains to be isolated; these checks do not prove a particular cache or synchronization fix. The original fixture was restored byte-for-byte and the borrowed isolated checkout restored/rebuilt to its prior head. No title run in this report. |
|
@TideOPL AI-assisted: yes |
fastTexture hands back the texture of a stage-A record when its memory is unchanged, and declines only depth surfaces and textures remade per use. The block copy of #4747 is a copy refreshed on reuse over a surface that is not a depth surface, so the fast path returned it without RefreshDepthCopy: after a compute pass stored new blocks into its storage image, a sample read the blocks of the previous copy. Decline copies refreshed on reuse in fastTexture as well, so the lookup takes cachedTexture, whose cache hit refreshes them. agc_driver_bc_block_copy failed on main at "sample of blocks stored again" (Linux, NVIDIA) and passes with this change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
What
A compute pass can write a block-compressed surface through an uncompressed storage view whose element is one block:
32_32_UINTfor 8-byte blocks (BC1, BC4) and32_32_32_32_UINTfor 16-byte blocks (BC2, BC3, BC5, BC6H, BC7). Unreal Engine's runtime virtual textures encode their physical pages this way every frame. Minecraft Dungeons II (PPSA16064) has three 4096x4096 pages (BC5, BC6H and BC7, 16 MiB each) that are written by compute and sampled in the same frame.cachedTexturefound the pending storage image but dropped it, becauseTexture::CanCopyFromrejects block-compressed descriptors. The lookup then took the snapshot path every time:StorageTexture::FlushPendingstored the whole 16 MiB surface to guest memory.UnchangedSince, soEqualsCommittedcompared all 16 MiB with the snapshot. That took 1 to 8 ms per lookup.ReadTextureSurfaceread the surface again and a new texture uploaded it.With this change the BC texture is a copy of the storage image instead:
Texture::CanBlockCopyFromaccepts a storage image over the same memory with:BlockCopyTagtexture owns a BC image.RefreshDepthCopyrefreshes it with onevkCmdCopyImageper level from the storage image, whenever the image'sVersion()moved. This is the same refresh-on-reuse scheme the depth copy uses: no flush, no CPU compare, no upload.cachedTexturekeeps such a pending source and makes or reuses the block copy, in both the cached and the uncached path.Sources for the semantics:
src/amd/common/ac_surface.c(ac_compute_surface:blk_w/blk_h= 4 andbpe= 8/16 for compressed formats) and addrlib'sGfx10Libelement-based swizzle equations cover this. An uncompressed view with the same element size and the extent in blocks therefore addresses the same bytes.vkCmdCopyImagebetween size-compatible uncompressed and compressed formats. Theextentis given in texels of the source image (Vulkan spec, "Copying Data Between Images",VkImageCopy).Tested
System: Windows 11 (26200), RTX 5070, NVIDIA Vulkan 1.4, WinLibs GCC, Release,
BUILD_TESTING=ON, rebased onmain90c6839. The block-copy texture is aPerUseCopy::RefreshedOnReusecopy like the depth copy, so it goes throughIsDepthCopy/RefreshDepthCopyunchanged.agc_driver_bc_block_copy(new execution test): for BC7 (through32_32_32_32_UINT) and BC1 (through32_32_UINT), a compute pass stores blocks, the test samples the BC view while the results are pending, then stores and samples again.mainwithsampling the compressed view stored the pending blocks to guest memory, and passes with this change.Suite:
ctest -R "^agc"after the rebase: 447 tests, all pass.agc_driver_stencil_ref_exportis skipped, as onmain. The new test fails on thismaintoo.Minecraft Dungeons II (PPSA16064), title screen. This is not a clean-
mainA/B: the title does not reach its title screen on plainmainyet (it needs feat(agc): depth planes sampled as 2D arrays, cubes and integer views #425 and fix(agc): take an HTILE fill from a value in memory as a depth fast clear #3816). I tested onmaine7c70a2 plus those PRs and the local patches the title needs, none of which touch this path. Same capture window (APS5_TRACE_SECONDS=30:10), two runs of each:Resources.CompleteThe three pages became block copies. Screenshots of the title render the same as before.
Not run: Linux, lavapipe, AMD.
Checklist
main; no other open PR implements the same functionsNotImplemented_nid_no_patch); silent stubs are listed under Silent stubs in their library's technical debt file.mdfiles or images added to the repository (attach them to this PR)