Skip to content

fix(agc): keep texture images inside their extent's mip chain - #6280

Draft
fdfawef324 wants to merge 6 commits into
boykopovar:mainfrom
fdfawef324:claude/agc-cap-texture-mip-chain
Draft

fdfawef324 wants to merge 6 commits into
boykopovar:mainfrom
fdfawef324:claude/agc-cap-texture-mip-chain

Conversation

@fdfawef324

@fdfawef324 fdfawef324 commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

What

A guest texture descriptor can name more mip levels than Vulkan permits for its extent. Cap sampled, storage and expanded-copy images at the physical chain; bound their allocations, views, uploads, blits, barriers, clears and write-back. Extra-level storage views and attachments remain refused; #7085 supplies separate backing in a follow-up.

Demon's Souls PPSA01342 originally lost the device after a 28x1 BC3 array declared ten levels while the extent held five. The private integration fault pointed to the first byte beyond that image. This is historical diagnosis; it is not a fresh title run on the final rebase.

For the decoded views exercised here (MAX_MIP = LAST_LEVEL), image_get_resinfo retains the guest level count and returns 1x1 spatial extents for extra levels within that count. At LOD >= count, it zeros every extent/layer component and retains the count. The emitter selects a valid physical query LOD before asking Vulkan, including for LOD 31 / UINT_MAX. Single-level descriptors with an unrepresented base refuse texel loads and LOD queries; pure size queries remain valid. Repacked storage-to-sampled copies use the same allocation/view cap.

The rebase preserves #6054's uploadImage path and passes physical geometry.imageLevels/copyLevels through sRGB image creation, blits, views and refresh. It retains main's ConvertedSampleRequired alongside ViewLevelsPastChain/LevelsPastChain, and keeps convertedSamples and levelUses in the cache encoder, decoder and nonzero round-trip fixture. Final cache format: 41; ImageResource guard: 40.

The existing decoder still clamps raw LAST_LEVEL to MAX_MIP when BASE_LEVEL <= MAX_MIP. The reported 28x1 LAST_LEVEL=9 / MAX_MIP=0 count of ten remains a discrepancy; this change does not fix it. A CPU LAST9/MAX6 control pins that unchanged decode. Samples/gathers past the chain still clamp to represented data, with console behavior unverified. There is no local PS5 or 3D/cube resinfo hardware claim.

External evidence is attributed, not counted as our own testing:

  • XairRrR reports Uncharted PPSA05684 overlong storage chains and eight ten-minute composed Linux/RTX4070TiSUPER runs without device loss. This supersedes the old no-title-use statement; no missing-level access was reported.
  • fisherjoey reports one 1500-second clean Demon's Souls PPSA01341 run and feat(agc): sample 8 and 8_8 sRGB textures through an RGBA8 sRGB copy #6054 composition guidance, adopted here. That run tested the driver commit. Their later stack passed 1535/1536 lavapipe tests, with application_heap_lazy also failing previously; no game run was claimed on that later build. Its suggested format40 applied to its earlier main, so this rebase uses the next available version on its own pinned base.
  • thuanquang reports RX 6700 XT/gfx1031 HIP query counts/extents, zero extents beyond count and distinct texels for extra mip loads. That is desktop RDNA2 evidence, not PS5 or sampling/gather coverage; the raw LAST_LEVEL/MAX_MIP discrepancy above remains.
  • Amoenus's #7085 remains the extra-level representation follow-up, whose reviewed head was based on the earlier c80ba9e prerequisite. Its composed-title outcomes are not standalone cap-only success evidence.

Tested

Windows Server 2025 (10.0.26100), WinLibs MinGW-w64 GCC 15.2.0, Release. Final publication candidate 0e1f2ab53b596a4d33ec8426097bda2c05b82068 on main 676d423968a1a8fcc79c6247020ce22090a8e0d4.

Seven selected Release/O3 targets complete; the final restored incremental build took 14.06 seconds. Four CPU/mock CTests passed without skips in 14.91 seconds: agc_shader_bindless, agc_shader_memory, agc_shader_disk_cache and agc_driver_graphics. Two precise current-source controls failed at the intended single-unrepresented-base admission and repacked mip-5-of-5 copy assertions. Source was restored, rebuilt and retested. Conventions pass against the pinned base and later main 72a3d9f2a49d; its clean merge was checked separately from this 676-based execution.

The recording mock checks ordinary and beyond-chain sampled/upload/storage sRGB expansion and repacked-copy allocation, view and copy bounds. Device query fixtures cover shortened and ordinary five-level views, single-level base 7 / last 7, 2D/2D-array layouts, LOD=count/count+1/31/UINT_MAX, and uniform/mixed lanes. The inherited llvmpipe mixed-LOD exclusion remains; no Mesa-version cutoff is newly claimed.

Current-head device checks passed 5/5 registrations / four executables without skips in 4.35 seconds on the RTX 3060, sequentially in the managed slot. Required cases: image_levels_past_chain, image_sample_lod_clamp, image_srgb_load, image_srgb_sample_copy and forced sRGB-copy. The frozen naturally dirty query control at this same source head exited 1 in 0.90 seconds and reproduced both expected errors (LOD10 width1 instead of0; LOD5 width28 instead of0), with actual RTX/Vulkan initialization. The checker requires both diagnostics; this is an expected regression failure, separate from the five passing production cases. Device skips/exit77 are not passes. The selective control removes only the zero-extent selection, retaining the safe physical query LOD and guest count; count-boundary mismatches must be observed to count it as a meaningful red.

Runtime hashes were verified before and after; ANYPS5_REQUIRE_VULKAN=1 was set. No fresh title, FPS, console-equivalence or playability result is claimed by this update.

Shared-source coordination is pending: #7550 codec order and #7579 eligibility-line order propose this PR first, with both changes retained by the later rebase. Those proposals are not agreements, so the verified update remains a draft. #7085 already declares this PR as a prerequisite; its depth/layer/level argument order must be reconciled by meaning. There is no additional standalone build dependency or combined-runtime claim.

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: PPSA01342 Demon's Souls (PPSA01341) #1283, overlong image-chain stop only
  • GPUs tested: NVIDIA GeForce RTX 3060 12 GB, driver 591.86 (32.0.15.9186), Vulkan 1.4.325, Windows Server 2025 10.0.26100 (TextureMipChain is a recording mock; external vendor/title reports remain separately attributed)
  • AI-assisted: yes (Claude Code and Codex)

Co-Authored-By: Codex noreply@openai.com

@github-actions

github-actions Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

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 862 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 907 core/shader/recompiler/Optimization/src/ResourceMaterializer.cpp
core/shader/recompiler/SpirvBackend/src/SpirvImageEmitter.cpp
PR 1368 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 1395 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 2434 core/libs/prx/libSceAgcDriver/CMakeLists.txt
docs/dev/debt/libSceAgcDriver.md
PR 4040 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 4448 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
docs/dev/debt/libSceAgcDriver.md
PR 4449 docs/dev/debt/libSceAgcDriver.md
PR 5021 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/shader/recompiler/SpirvBackend/src/SpirvImageEmitter.cpp
docs/dev/debt/shader.md
PR 5058 docs/dev/debt/libSceAgcDriver.md
PR 5315 core/libs/prx/libSceAgcDriver/tests/ShaderDiskCache.cpp
PR 5371 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/shader/recompiler/IntermediateRepresentation/include/IntermediateRepresentation/IrMetadata/Resources.hpp
core/shader/recompiler/Optimization/include/Optimization/ResourceMaterializer.hpp
core/shader/recompiler/Optimization/src/DescriptorBindingBuilder.cpp
core/shader/recompiler/Optimization/src/ResourceMaterializer.cpp
core/shader/recompiler/PipelineSpecialization.hpp
core/shader/recompiler/RuntimeAbi.hpp
core/shader/recompiler/SpirvBackend/src/SpirvImageEmitter.cpp
docs/dev/debt/shader.md
PR 5372 docs/dev/debt/libSceAgcDriver.md
PR 5426 core/libs/prx/libSceAgcDriver/CMakeLists.txt
docs/dev/debt/shader.md
PR 5431 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 5441 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 5499 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 5609 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
core/libs/prx/libSceAgcDriver/tests/ShaderDiskCache.cpp
core/shader/recompiler/Optimization/src/DescriptorBindingBuilder.cpp
core/shader/recompiler/ShaderDiskCache.cpp
PR 5925 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
core/shader/recompiler/ShaderDiskCache.cpp
core/shader/recompiler/ShaderDiskCache.hpp
docs/dev/debt/libSceAgcDriver.md
PR 5941 docs/dev/debt/shader.md
PR 6009 docs/dev/debt/shader.md
PR 6010 docs/dev/debt/shader.md
PR 6011 docs/dev/debt/shader.md
PR 6044 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6108 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 6146 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6169 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6182 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6185 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6186 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6187 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 6188 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 6192 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 6194 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6197 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 6202 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 6209 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 6218 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
core/shader/recompiler/Optimization/src/ResourceMaterializer.cpp
core/shader/recompiler/SpirvBackend/src/SpirvImageEmitter.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6223 docs/dev/debt/libSceAgcDriver.md
PR 6235 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
core/libs/prx/libSceAgcDriver/tests/ShaderDiskCache.cpp
docs/dev/debt/shader.md
PR 6249 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 6273 docs/dev/debt/libSceAgcDriver.md
PR 6292 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 6300 core/libs/prx/libSceAgcDriver/CMakeLists.txt
docs/dev/debt/libSceAgcDriver.md
PR 6498 docs/dev/debt/libSceAgcDriver.md
PR 6501 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6539 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
core/libs/prx/libSceAgcDriver/tests/ShaderDiskCache.cpp
core/shader/recompiler/Optimization/src/DescriptorBindingBuilder.cpp
core/shader/recompiler/ShaderDiskCache.cpp
PR 6548 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6549 docs/dev/debt/libSceAgcDriver.md
PR 6588 core/libs/prx/libSceAgcDriver/CMakeLists.txt
docs/dev/debt/libSceAgcDriver.md
PR 6604 docs/dev/debt/shader.md
PR 6612 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
docs/dev/debt/shader.md
PR 6615 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 6636 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6639 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6642 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6682 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 6718 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 6727 docs/dev/debt/libSceAgcDriver.md
PR 6741 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6743 core/libs/prx/libSceAgcDriver/CMakeLists.txt
docs/dev/debt/libSceAgcDriver.md
PR 6747 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6788 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6801 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6804 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6808 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6820 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 6848 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 6858 core/libs/prx/libSceAgcDriver/tests/ShaderDiskCache.cpp
core/shader/recompiler/ShaderDiskCache.cpp
core/shader/recompiler/ShaderDiskCache.hpp
PR 6867 docs/dev/debt/libSceAgcDriver.md
PR 6868 core/libs/prx/libSceAgcDriver/CMakeLists.txt
docs/dev/debt/libSceAgcDriver.md
PR 6879 core/libs/prx/libSceAgcDriver/Graphics/include/TextureTiling.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/TextureTiling.cpp
core/shader/recompiler/ShaderDiskCache.cpp
docs/dev/debt/shader.md
PR 6887 core/libs/prx/libSceAgcDriver/CMakeLists.txt
docs/dev/debt/libSceAgcDriver.md
PR 6905 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6921 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 6924 core/libs/prx/libSceAgcDriver/tests/ShaderDiskCache.cpp
core/shader/recompiler/ShaderDiskCache.cpp
core/shader/recompiler/ShaderDiskCache.hpp
docs/dev/debt/shader.md
PR 6926 docs/dev/debt/libSceAgcDriver.md
PR 6946 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
core/shader/recompiler/ShaderDiskCache.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6947 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
core/libs/prx/libSceAgcDriver/tests/ShaderDiskCache.cpp
core/shader/recompiler/Optimization/src/DescriptorBindingBuilder.cpp
core/shader/recompiler/Optimization/src/ResourceMaterializer.cpp
core/shader/recompiler/RuntimeAbi.hpp
core/shader/recompiler/ShaderDiskCache.cpp
core/shader/recompiler/ShaderDiskCache.hpp
docs/dev/debt/libSceAgcDriver.md
PR 6948 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 6959 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/tests/ShaderDiskCache.cpp
core/shader/recompiler/PipelineSpecialization.hpp
core/shader/recompiler/ShaderDiskCache.cpp
docs/dev/debt/libSceAgcDriver.md
docs/dev/debt/shader.md
PR 6960 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 6965 core/libs/prx/libSceAgcDriver/CMakeLists.txt
docs/dev/debt/libSceAgcDriver.md
PR 6970 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
core/libs/prx/libSceAgcDriver/tests/ShaderDiskCache.cpp
core/shader/recompiler/ShaderDiskCache.cpp
PR 6971 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 6973 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6977 core/libs/prx/libSceAgcDriver/Graphics/include/TextureTiling.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/TextureTiling.cpp
core/shader/recompiler/Optimization/src/ResourceMaterializer.cpp
core/shader/recompiler/ShaderDiskCache.cpp
docs/dev/debt/libSceAgcDriver.md
docs/dev/debt/shader.md
PR 6987 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6989 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6995 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
docs/dev/debt/libSceAgcDriver.md
PR 7002 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
docs/dev/debt/libSceAgcDriver.md
PR 7048 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 7201 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7223 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/tests/ShaderDiskCache.cpp
core/shader/recompiler/Optimization/src/ResourceMaterializer.cpp
core/shader/recompiler/Optimization/src/ResourceTracker.cpp
core/shader/recompiler/ShaderDiskCache.cpp
core/shader/recompiler/SpirvBackend/src/SpirvImageEmitter.cpp
docs/dev/debt/shader.md
PR 7243 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 7256 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 7275 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7307 core/libs/prx/libSceAgcDriver/CMakeLists.txt
docs/dev/debt/libSceAgcDriver.md
PR 7310 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 7392 docs/dev/debt/shader.md
PR 7395 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/tests/ShaderDiskCache.cpp
core/shader/recompiler/Optimization/src/ResourceMaterializer.cpp
core/shader/recompiler/Optimization/src/ResourceTracker.cpp
core/shader/recompiler/ShaderDiskCache.cpp
core/shader/recompiler/ShaderDiskCache.hpp
core/shader/recompiler/SpirvBackend/src/SpirvImageEmitter.cpp
docs/dev/debt/shader.md
PR 7410 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/shader.md
PR 7426 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
docs/dev/debt/shader.md
PR 7446 core/libs/prx/libSceAgcDriver/CMakeLists.txt
docs/dev/debt/libSceAgcDriver.md
PR 7449 docs/dev/debt/libSceAgcDriver.md
PR 7457 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7464 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7484 core/libs/prx/libSceAgcDriver/tests/ShaderDiskCache.cpp
docs/dev/debt/shader.md
PR 7505 core/libs/prx/libSceAgcDriver/CMakeLists.txt
docs/dev/debt/libSceAgcDriver.md
PR 7508 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7514 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 7535 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7550 core/libs/prx/libSceAgcDriver/tests/ShaderDiskCache.cpp
core/shader/recompiler/IntermediateRepresentation/include/IntermediateRepresentation/IrMetadata/Resources.hpp
core/shader/recompiler/Optimization/src/ResourceMaterializer.cpp
core/shader/recompiler/Optimization/src/ResourceTracker.cpp
core/shader/recompiler/ShaderDiskCache.cpp
core/shader/recompiler/ShaderDiskCache.hpp
PR 7600 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 7604 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
docs/dev/debt/libSceAgcDriver.md
PR 7618 docs/dev/debt/libSceAgcDriver.md
PR 7622 core/shader/recompiler/ShaderDiskCache.cpp
PR 7629 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7642 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
core/libs/prx/libSceAgcDriver/tests/ShaderDiskCache.cpp
core/shader/recompiler/IntermediateRepresentation/include/IntermediateRepresentation/IrMetadata/Resources.hpp
core/shader/recompiler/Optimization/include/Optimization/ResourceMaterializer.hpp
core/shader/recompiler/Optimization/src/DescriptorBindingBuilder.cpp
core/shader/recompiler/Optimization/src/ResourceMaterializer.cpp
core/shader/recompiler/Optimization/src/ResourceTracker.cpp
core/shader/recompiler/PipelineSpecialization.hpp
core/shader/recompiler/RuntimeAbi.hpp
core/shader/recompiler/ShaderDiskCache.cpp
core/shader/recompiler/ShaderDiskCache.hpp
core/shader/recompiler/SpirvBackend/src/SpirvImageEmitter.cpp
docs/dev/debt/libSceAgcDriver.md
PR 7644 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7647 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 7659 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 7668 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 7677 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7689 core/shader/recompiler/Optimization/src/DescriptorBindingBuilder.cpp
core/shader/recompiler/Optimization/src/ResourceMaterializer.cpp
core/shader/recompiler/ShaderDiskCache.cpp
core/shader/recompiler/ShaderDiskCache.hpp
PR 7694 core/shader/recompiler/Optimization/src/ResourceTracker.cpp
PR 7696 docs/dev/debt/libSceAgcDriver.md
PR 7705 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7717 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 7725 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 7729 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 7799 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 7800 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
docs/dev/debt/libSceAgcDriver.md
PR 7803 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/shader/recompiler/Optimization/src/ResourceMaterializer.cpp
docs/dev/debt/libSceAgcDriver.md
docs/dev/debt/shader.md
PR 7817 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7831 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
core/shader/recompiler/ShaderDiskCache.cpp
PR 7833 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7844 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 7849 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7869 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 7880 core/shader/recompiler/Optimization/src/ResourceTracker.cpp
PR 7882 core/shader/recompiler/Optimization/src/ResourceMaterializer.cpp
PR 7883 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 7888 core/shader/recompiler/ShaderDiskCache.cpp
docs/dev/debt/shader.md
PR 7893 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 7910 docs/dev/debt/libSceAgcDriver.md
PR 7911 docs/dev/debt/libSceAgcDriver.md
PR 7919 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7922 docs/dev/debt/shader.md
PR 7927 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 7942 docs/dev/debt/shader.md
PR 7948 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
core/shader/recompiler/Optimization/src/ResourceMaterializer.cpp
docs/dev/debt/libSceAgcDriver.md
PR 7965 docs/dev/debt/libSceAgcDriver.md
docs/dev/debt/shader.md
PR 7978 docs/dev/debt/libSceAgcDriver.md
PR 7984 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 8004 docs/dev/debt/shader.md
PR 8014 core/libs/prx/libSceAgcDriver/CMakeLists.txt
docs/dev/debt/libSceAgcDriver.md
PR 8055 core/shader/recompiler/SpirvBackend/src/SpirvImageEmitter.cpp
docs/dev/debt/shader.md
PR 8070 docs/dev/debt/libSceAgcDriver.md
PR 8077 core/libs/prx/libSceAgcDriver/tests/ShaderDiskCache.cpp
core/shader/recompiler/IntermediateRepresentation/include/IntermediateRepresentation/IrMetadata/Resources.hpp
core/shader/recompiler/Optimization/src/ResourceMaterializer.cpp
core/shader/recompiler/Optimization/src/ResourceTracker.cpp
core/shader/recompiler/ShaderDiskCache.cpp
docs/dev/debt/shader.md
PR 8083 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
docs/dev/debt/shader.md
PR 8089 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 8099 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 8104 core/libs/prx/libSceAgcDriver/CMakeLists.txt
docs/dev/debt/libSceAgcDriver.md
PR 8105 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 8115 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 8121 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 8123 docs/dev/debt/libSceAgcDriver.md
PR 8126 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 8139 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 8145 core/libs/prx/libSceAgcDriver/tests/ShaderDiskCache.cpp
core/shader/recompiler/ShaderDiskCache.cpp
docs/dev/debt/libSceAgcDriver.md
PR 8160 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 8161 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 8180 docs/dev/debt/libSceAgcDriver.md
PR 8212 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 8213 docs/dev/debt/libSceAgcDriver.md
PR 8223 docs/dev/debt/libSceAgcDriver.md
PR 8246 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
core/libs/prx/libSceAgcDriver/tests/GraphicsTests.hpp
PR 8261 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
docs/dev/debt/libSceAgcDriver.md
PR 8267 core/libs/prx/libSceAgcDriver/CMakeLists.txt
docs/dev/debt/shader.md
PR 8276 docs/dev/debt/shader.md
PR 8277 docs/dev/debt/shader.md
PR 8281 docs/dev/debt/libSceAgcDriver.md
docs/dev/debt/shader.md
PR 8283 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 8317 docs/dev/debt/libSceAgcDriver.md
PR 8319 docs/dev/debt/libSceAgcDriver.md
PR 8336 docs/dev/debt/libSceAgcDriver.md
PR 8339 docs/dev/debt/shader.md
PR 8365 core/libs/prx/libSceAgcDriver/CMakeLists.txt
docs/dev/debt/libSceAgcDriver.md
PR 8372 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 8374 core/libs/prx/libSceAgcDriver/tests/ShaderDiskCache.cpp
PR 8395 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 8401 docs/dev/debt/libSceAgcDriver.md
PR 8403 docs/dev/debt/shader.md
PR 8406 docs/dev/debt/shader.md
PR 8410 docs/dev/debt/shader.md
PR 8412 docs/dev/debt/libSceAgcDriver.md
PR 8419 docs/dev/debt/libSceAgcDriver.md
PR 8420 docs/dev/debt/libSceAgcDriver.md
PR 8423 docs/dev/debt/libSceAgcDriver.md
PR 8424 docs/dev/debt/libSceAgcDriver.md
PR 8425 docs/dev/debt/shader.md
PR 8426 docs/dev/debt/libSceAgcDriver.md
PR 8429 core/shader/recompiler/Optimization/src/DescriptorBindingBuilder.cpp
core/shader/recompiler/Optimization/src/ResourceMaterializer.cpp
core/shader/recompiler/PipelineSpecialization.hpp
core/shader/recompiler/SpirvBackend/src/SpirvImageEmitter.cpp
docs/dev/debt/shader.md
PR 8445 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 8450 docs/dev/debt/shader.md
PR 8458 docs/dev/debt/shader.md
PR 8484 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 8489 core/libs/prx/libSceAgcDriver/tests/ShaderDiskCache.cpp
docs/dev/debt/shader.md
PR 8495 docs/dev/debt/shader.md
PR 8518 core/shader/recompiler/Optimization/src/ResourceMaterializer.cpp
PR 8519 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 8527 core/libs/prx/libSceAgcDriver/CMakeLists.txt
docs/dev/debt/libSceAgcDriver.md
PR 8538 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
core/shader/recompiler/ShaderDiskCache.cpp
docs/dev/debt/libSceAgcDriver.md
PR 8542 core/libs/prx/libSceAgcDriver/CMakeLists.txt
docs/dev/debt/libSceAgcDriver.md
PR 8552 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 8563 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 8564 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
core/shader/recompiler/IntermediateRepresentation/include/IntermediateRepresentation/IrMetadata/Resources.hpp
core/shader/recompiler/Optimization/src/ResourceMaterializer.cpp
core/shader/recompiler/ShaderDiskCache.cpp
core/shader/recompiler/ShaderDiskCache.hpp
docs/dev/debt/libSceAgcDriver.md
docs/dev/debt/shader.md
PR 8566 core/shader/recompiler/Optimization/src/ResourceMaterializer.cpp
PR 8592 core/libs/prx/libSceAgcDriver/CMakeLists.txt
docs/dev/debt/libSceAgcDriver.md
PR 8608 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
core/libs/prx/libSceAgcDriver/tests/GraphicsTests.hpp
PR 8612 core/shader/recompiler/SpirvBackend/src/SpirvImageEmitter.cpp
PR 8625 core/shader/recompiler/Optimization/src/ResourceMaterializer.cpp
core/shader/recompiler/SpirvBackend/src/SpirvImageEmitter.cpp
docs/dev/debt/shader.md
PR 8632 core/shader/recompiler/Optimization/src/ResourceMaterializer.cpp
PR 8639 docs/dev/debt/libSceAgcDriver.md
docs/dev/debt/shader.md
PR 8642 core/shader/recompiler/Optimization/src/ResourceMaterializer.cpp
docs/dev/debt/shader.md
PR 8658 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
core/shader/recompiler/SpirvBackend/src/SpirvImageEmitter.cpp
PR 8667 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 8672 core/libs/prx/libSceAgcDriver/CMakeLists.txt
docs/dev/debt/libSceAgcDriver.md
PR 8678 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 8707 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
docs/dev/debt/libSceAgcDriver.md
PR 8713 docs/dev/debt/shader.md
PR 8716 core/shader/recompiler/SpirvBackend/src/SpirvImageEmitter.cpp
PR 8740 core/libs/prx/libSceAgcDriver/CMakeLists.txt
docs/dev/debt/libSceAgcDriver.md
PR 8792 core/shader/recompiler/Optimization/include/Optimization/ResourceMaterializer.hpp
core/shader/recompiler/Optimization/src/DescriptorBindingBuilder.cpp
core/shader/recompiler/Optimization/src/ResourceMaterializer.cpp
core/shader/recompiler/Optimization/src/ResourceTracker.cpp
docs/dev/debt/shader.md
PR 8856 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 8858 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 8871 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 8874 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 8881 core/shader/recompiler/ShaderDiskCache.cpp
core/shader/recompiler/ShaderDiskCache.hpp
docs/dev/debt/shader.md
PR 8883 core/shader/recompiler/Optimization/src/ResourceMaterializer.cpp
PR 8887 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 8898 core/shader/recompiler/Optimization/src/ResourceMaterializer.cpp
PR 8908 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 8911 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 8932 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
docs/dev/debt/libSceAgcDriver.md
PR 8939 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/tests/ShaderDiskCache.cpp
core/shader/recompiler/Optimization/src/ResourceMaterializer.cpp
core/shader/recompiler/Optimization/src/ResourceTracker.cpp
core/shader/recompiler/ShaderDiskCache.cpp
core/shader/recompiler/ShaderDiskCache.hpp
core/shader/recompiler/SpirvBackend/src/SpirvImageEmitter.cpp
docs/dev/debt/shader.md
PR 8971 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 8975 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 8991 core/shader/recompiler/Optimization/src/ResourceTracker.cpp
docs/dev/debt/shader.md
PR 8998 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
core/shader/recompiler/Optimization/src/ResourceMaterializer.cpp
core/shader/recompiler/SpirvBackend/src/SpirvImageEmitter.cpp
PR 8999 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 9007 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 9013 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 9017 docs/dev/debt/libSceAgcDriver.md
PR 9020 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
core/shader/recompiler/IntermediateRepresentation/include/IntermediateRepresentation/IrMetadata/Resources.hpp
core/shader/recompiler/Optimization/src/ResourceMaterializer.cpp
core/shader/recompiler/ShaderDiskCache.cpp
core/shader/recompiler/ShaderDiskCache.hpp
docs/dev/debt/libSceAgcDriver.md
docs/dev/debt/shader.md
PR 9022 docs/dev/debt/libSceAgcDriver.md
PR 9026 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
docs/dev/debt/libSceAgcDriver.md

This was referenced Oct 15, 2026
@fisherjoey

Copy link
Copy Markdown
Contributor

Two things from Demon's Souls (PPSA01341 v1.07, Linux, RTX 5070 Ti, NVIDIA 595.91.07).

It fixes our Xid 31. We'd hit NVRM: Xid 31 (MMU fault, copy engine write) three times in the level. With b9badf4 on our base, a 1500 s run was clean, and the clamp fired once, on the 256-layer BC array at 0x1009000000 (11 mips cut to 5). That's the texture that had been created right before each of the three faults.

The conflict with main is #6054. It added CreateExpandImage/RecordExpandBlit, which size the RGBA8 copy from descriptor.mipCount. Applied on top of this PR, they rebuild the over-long chain this PR removes. Our resolution, replaying b9badf4 on main 5057673:

  • CreateExpandImage and RecordExpandBlit take a levels argument, fed geometry.imageLevels on the upload path.
  • The sRGB storage-copy constructor sets copyLevels = geometry.imageLevels and uses ViewLevels() for the view, like your block-copy and depth-copy paths. refreshSrgbExpand passes copyLevels through.
  • In the barrier hunk, feat(agc): sample 8 and 8_8 sRGB textures through an RGBA8 sRGB copy #6054's uploadImage is combined with your geometry.imageLevels.

Lavapipe full suite on that tree: 1460 of 1461 pass. The one failure, application_heap_lazy, also fails on our trees without this PR. image_levels_past_chain, image_sample_lod_clamp, image_srgb_sample_copy, image_srgb_sample_copy_forced and image_srgb_load pass. This covers only the driver commit b9badf4, not 5fb9380. Use any of it if it helps.

Resolution hunks (b9badf4 replayed on main 5057673)
diff --git a/core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp b/core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
index 82f733941..a16eb56fe 100644
--- a/core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
+++ b/core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
@@ -244,14 +257,14 @@ struct ExpandImage {
     VkDeviceSize bytes = 0;
 };
 
-ExpandImage CreateExpandImage(const Context& context, const GuestTextureResource& descriptor, std::uint32_t depth, std::uint32_t layers) {
+ExpandImage CreateExpandImage(const Context& context, const GuestTextureResource& descriptor, std::uint32_t depth, std::uint32_t levels, std::uint32_t layers) {
     ExpandImage result;
     VkImageCreateInfo imageInfo{VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO};
     imageInfo.flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT | (descriptor.dimension == TextureDimension::kCube ? VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT : 0u);
     imageInfo.imageType = ImageTypeFor(descriptor.dimension);
     imageInfo.format = VK_FORMAT_R8G8B8A8_UNORM;
     imageInfo.extent = {descriptor.width, descriptor.height, depth};
-    imageInfo.mipLevels = descriptor.mipCount;
+    imageInfo.mipLevels = levels;
     imageInfo.arrayLayers = layers;
     imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
     imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
@@ -271,9 +284,9 @@ ExpandImage CreateExpandImage(const Context& context, const GuestTextureResource
     return result;
 }
 
-void RecordExpandBlit(const Context& context, VkCommandBuffer commands, VkImage source, VkImageLayout sourceLayout, VkImage target, const GuestTextureResource& descriptor, std::uint32_t depth, std::uint32_t layers) {
+void RecordExpandBlit(const Context& context, VkCommandBuffer commands, VkImage source, VkImageLayout sourceLayout, VkImage target, const GuestTextureResource& descriptor, std::uint32_t depth, std::uint32_t levels, std::uint32_t layers) {
     std::vector<VkImageBlit> regions;
-    for (std::uint32_t level = 0; level < descriptor.mipCount; ++level) {
+    for (std::uint32_t level = 0; level < levels; ++level) {
         const VkOffset3D end{static_cast<std::int32_t>(std::max(descriptor.width >> level, 1u)), static_cast<std::int32_t>(std::max(descriptor.height >> level, 1u)), static_cast<std::int32_t>(descriptor.dimension == TextureDimension::k3D ? std::max(depth >> level, 1u) : 1u)};
         VkImageBlit region{};
         region.srcSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, level, 0, layers};
@@ -285,6 +298,11 @@ void RecordExpandBlit(const Context& context, VkCommandBuffer commands, VkImage
     context.Function<PFN_vkCmdBlitImage>("vkCmdBlitImage")(commands, source, sourceLayout, target, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, static_cast<std::uint32_t>(regions.size()), regions.data(), VK_FILTER_NEAREST);
 }
 
+void RequireImageLevel(const GuestTextureResource& descriptor, const SurfaceGeometry& geometry, std::uint32_t level, const char* access) {
+    if (level < geometry.imageLevels) return;
+    throw std::runtime_error("AGC graphics: " + std::string(access) + " of mip level " + std::to_string(level) + " of a " + std::to_string(descriptor.width) + "x" + std::to_string(descriptor.height) + "x" + std::to_string(geometry.imageDepth) + " surface of " + std::to_string(descriptor.mipCount) + " levels is not implemented: a Vulkan image of that extent holds " + std::to_string(geometry.imageLevels) + " levels, and the 1x1 levels past floor(log2(max extent)) + 1 are not represented");
+}
+
 std::atomic<std::uint64_t>& SampledMemoryCounter() {
     static std::atomic<std::uint64_t> bytes{0};
     return bytes;
@@ -353,7 +375,7 @@ Texture::Texture(const Context& context, TextureDetiler& detiler, const GuestTex
         const VkImage uploadImage = image;
         std::shared_ptr<OwnedImage> uploadOwned;
         if (srgbExpand) {
-            auto expanded = CreateExpandImage(context, descriptor, geometry.imageDepth, geometry.imageLayers);
+            auto expanded = CreateExpandImage(context, descriptor, geometry.imageDepth, geometry.imageLevels, geometry.imageLayers);
             uploadOwned = std::move(owned);
             owned = std::move(expanded.owned);
             image = expanded.image;
@@ -445,14 +467,14 @@ Texture::Texture(const Context& context, TextureDetiler& detiler, const GuestTex
             toTransferDst.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
             toTransferDst.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
             toTransferDst.image = uploadImage;
-            toTransferDst.subresourceRange = {aspect, 0, descriptor.mipCount, 0, geometry.imageLayers};
+            toTransferDst.subresourceRange = {aspect, 0, geometry.imageLevels, 0, geometry.imageLayers};
             context.Function<PFN_vkCmdPipelineBarrier>("vkCmdPipelineBarrier")(commands, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 1, &linearReadBarrier, 1, &toTransferDst);
 
             std::vector<VkBufferImageCopy> regions;
             regions.reserve(static_cast<std::size_t>(arrayLayers) * mips.size());
             for (std::uint32_t layer = 0; layer < arrayLayers; ++layer) {
                 const auto linearLayerOffset = static_cast<std::uint64_t>(layer) * sliceLinearBytes;
-                for (std::uint32_t level = 0; level < descriptor.mipCount; ++level) {
+                for (std::uint32_t level = 0; level < geometry.imageLevels; ++level) {
                     if (!geometry.HasLayer(level, layer)) continue;
                     const auto& mip = mips[level];
                     VkBufferImageCopy region{};
@@ -476,7 +498,7 @@ Texture::Texture(const Context& context, TextureDetiler& detiler, const GuestTex
                 toBlit[1] = toTransferDst;
                 toBlit[1].image = image;
                 context.Function<PFN_vkCmdPipelineBarrier>("vkCmdPipelineBarrier")(commands, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 2, toBlit.data());
-                RecordExpandBlit(context, commands, uploadImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, image, descriptor, geometry.imageDepth, geometry.imageLayers);
+                RecordExpandBlit(context, commands, uploadImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, image, descriptor, geometry.imageDepth, geometry.imageLevels, geometry.imageLayers);
             }
             std::unique_ptr<Buffer> dump;
             if (dumpWanted) {
@@ -531,7 +553,7 @@ Texture::Texture(const Context& context, TextureDetiler& detiler, const GuestTex
         viewInfo.format = srgbExpand ? VK_FORMAT_R8G8B8A8_SRGB : vkFormat;
         viewFormat = viewInfo.format;
         viewInfo.components = depthCompare ? VkComponentMapping{} : components;
-        viewInfo.subresourceRange = {aspect, descriptor.baseLevel, viewLevelCount, descriptor.baseArray, viewLayerCount};
+        viewInfo.subresourceRange = {aspect, viewBaseLevel, viewLevelCount, descriptor.baseArray, viewLayerCount};
         VkImageViewMinLodCreateInfoEXT minLod{VK_STRUCTURE_TYPE_IMAGE_VIEW_MIN_LOD_CREATE_INFO_EXT};
         ChainMinLod(context, descriptor, viewInfo, minLod);
 
@@ -777,15 +799,15 @@ Texture::Texture(const Context& context, const std::shared_ptr<StorageTexture>&
         const auto geometry = DescribeSurface(descriptor);
         copyWidth = descriptor.width;
         copyHeight = descriptor.height;
-        copyLevels = descriptor.mipCount;
+        copyLevels = geometry.imageLevels;
         copyLayers = geometry.imageLayers;
         APS5_LOG_OUT("Texture address=0x%llx %ux%u mips=%u layers=%u sRGB copy of storage image (guest format %u)", static_cast<unsigned long long>(descriptor.baseAddress), descriptor.width, descriptor.height, descriptor.mipCount, copyLayers, descriptor.format);
-        auto expanded = CreateExpandImage(context, descriptor, 1u, copyLayers);
+        auto expanded = CreateExpandImage(context, descriptor, 1u, copyLevels, copyLayers);
         image = expanded.image;
         owned = std::move(expanded.owned);
         allocationBytes = expanded.bytes;
 
-        const auto viewLevelCount = std::min(descriptor.lastLevel, descriptor.mipCount - 1u) - descriptor.baseLevel + 1u;
+        const auto [viewBaseLevel, viewLevelCount] = ViewLevels(descriptor, geometry.imageLevels);
         const auto viewLayerCount = geometry.imageLayers - descriptor.baseArray;
         if (descriptor.dimension == TextureDimension::kCube) {
             Require(viewLayerCount % 6u == 0, "guest cube texture view does not contain a multiple of 6 array slices");
@@ -796,7 +818,7 @@ Texture::Texture(const Context& context, const std::shared_ptr<StorageTexture>&
         viewInfo.format = VK_FORMAT_R8G8B8A8_SRGB;
         viewFormat = viewInfo.format;
         viewInfo.components = components;
-        viewInfo.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, descriptor.baseLevel, viewLevelCount, descriptor.baseArray, viewLayerCount};
+        viewInfo.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, viewBaseLevel, viewLevelCount, descriptor.baseArray, viewLayerCount};
         VkImageViewMinLodCreateInfoEXT minLod{VK_STRUCTURE_TYPE_IMAGE_VIEW_MIN_LOD_CREATE_INFO_EXT};
         ChainMinLod(context, descriptor, viewInfo, minLod);
         Check(context.Function<PFN_vkCreateImageView>("vkCreateImageView")(context.device, &viewInfo, nullptr, &view), "vkCreateImageView sRGB copy");
@@ -836,7 +858,7 @@ bool Texture::refreshSrgbExpand() {
     toTransferDst.image = image;
     toTransferDst.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, copyLevels, 0, copyLayers};
     barrier(commands, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 1, &produced, 0, nullptr, 1, &toTransferDst);
-    RecordExpandBlit(context, commands, storageSource->Image(), VK_IMAGE_LAYOUT_GENERAL, image, sourceDescriptor, 1u, copyLayers);
+    RecordExpandBlit(context, commands, storageSource->Image(), VK_IMAGE_LAYOUT_GENERAL, image, sourceDescriptor, 1u, copyLevels, copyLayers);
     VkImageMemoryBarrier toShaderRead = toTransferDst;
     toShaderRead.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
     toShaderRead.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;

AI-assisted: yes

@adriadam10 adriadam10 self-assigned this Oct 18, 2026
@thuanquang

Copy link
Copy Markdown
Contributor

Hardware data for the part the description says is not measured on AMD. RX 6700 XT (gfx1031, RDNA 2), run through HIP: image_get_resinfo with dmask:0xf and the T#'s own DIM, one LOD per lane from 0 to 31, 32-bit float format:

T# levels result by LOD
2D 28x1 0-9 LOD 0-9: (max(1, 28 >> LOD), 1, 0, 10), so 28, 14, 7, 3, then 1 for LOD 4-9
2D 28x1, MAX_MIP 0 0-9 the same as with MAX_MIP 9: 10 levels
2D 28x1 5-9 LOD 0-4: (1, 1, 0, 5)
2D 28x1 7-9 LOD 0-2: (1, 1, 0, 3)
2D_ARRAY 28x1, 4 and 256 layers 0-9 as the 2D T#, with the layer count third
2D_ARRAY 28x1, 4 layers 7-9 LOD 0-2: (1, 1, 4, 3)
2D_ARRAY 4x1, 64 layers 0-10 (4, 1, 64, 11), (2, 1, 64, 11), then width 1 up to LOD 10
3D 28x1x4 0-9 (max(1, 28 >> LOD), 1, max(1, 4 >> LOD), 10)
3D 28x1x4 7-9 LOD 0-2: (1, 1, 1, 3)

So the second commit's values hold on RDNA 2: the level count is LAST_LEVEL - BASE_LEVEL + 1 whatever MAX_MIP says, and each extent is max(1, extent >> (BASE_LEVEL + LOD)), so it is 1 at every LOD past the chain. One case the PR's test doesn't cover: at a LOD at or past the level count, every row above returns 0 for width, height and depth, with the level count unchanged ((0, 0, 0, 10) for the 28x1 levels 0-9 T# at LOD 10 to 31).

image_load_mip at (0, 0) through the 28x1 2D T# of levels 0-9, linear and SW_64KB_S, over memory where each dword holds its own index: LODs 0-9 return ten different dwords, and LODs 10 to 15 return 0. So each of the five levels past the chain reads a 1x1 texel at its own address, as the description says, and a read through such a level that the emulator served from another level would return the wrong texel. That matches refusing image_load_mip there.

This is desktop RDNA 2, not a PS5, and it covers only the queries and loads above, not samples or gathers past the chain.

@github-actions github-actions Bot added the unblocks title Names a title ID on the Unblocks line label Oct 18, 2026
@fisherjoey

Copy link
Copy Markdown
Contributor

Two more conflicts with current main (40393b0), beyond the Texture.cpp one in my last comment:

  • ResourceMaterializer.hpp: an add/add next to feat(shader): sample converted unorm images in the shader #5958's ConvertedSampleRequired. Both additions can stay; we kept ViewLevelsPastChain and LevelsPastChain alongside it.
  • Shader disk cache: main is already at 39 ImageResource fields (it added convertedSamples) and FormatVersion 39. With this PR's levelUses, the fieldCount assert has to be 40 and FormatVersion 40, not 37.

With those resolved, the stack (main 40393b0 + this PR + #6567 + #6926) builds, and lavapipe passes 1535 of 1536 tests. The only failure is application_heap_lazy, which also failed on our previous stack. No game run on this build yet.

AI-assisted: yes

fdfawef324 and others added 6 commits October 19, 2026 00:37
A T# or a color target may name more mip levels than its extent halves
into. On RDNA a level's extent is max(1, extent >> level), so the levels
past floor(log2(max(width, height, depth))) + 1 are more 1x1 levels with
texels of their own in guest memory. A Vulkan image cannot have them
(VUID-VkImageCreateInfo-mipLevels-00947), but the sampled texture upload,
its block and depth copies and the storage image created their images with
the descriptor's level count and copied every guest level into them.

Demon's Souls (PPSA01342) samples 28x1 and 4x1 BC3 and BC7 arrays through
T#s of 8 to 11 levels, among them a 28x1 BC3 array of 256 layers and 10
levels whose extent holds 5. NVIDIA (RTX 3060, 591.86) sizes a 28x1 BC3
image of 10 levels like one of 5 (0xc00 bytes a layer), so the copies of
levels 5-9 wrote past the image's memory. Each of the title's seven device
losses followed the creation of such a texture; in the run with the
address log, VK_EXT_device_fault reported a write fault at the first byte
past that image.

SurfaceGeometry::imageLevels is the descriptor's level count, at most
FullMipChainLevels of the extent. Sampled textures and their block and
depth copies create, transition and copy only those levels, and their
views keep the base level, the level count and the minimum LOD inside
them: a view of levels past the chain reads the image's last level.

Storage images hold the same levels. Their uploads, write-backs, clears,
barriers and copy regions cover only those levels, so the guest bytes of
the levels past the chain are neither read into the image nor written
back. A storage view or a color attachment of a level past the chain
throws, and so does creating a storage image for such a level. A fill or
a buffer copy over such a surface is no longer turned into a clear or an
image copy (FillClear and CopyFrom refuse it), since that would leave the
levels past the chain unchanged, and the surface is tracked per layer: a
64 KiB unit of it may hold only those levels, which no slice window moves.
docs/dev/debt/libSceAgcDriver.md records the levels that are not
represented.

Test: agc_driver_graphics (tests/TextureMipChain.cpp) runs the sampled
upload of the 28x1 BC3 10-level array, a 4x1 11-level one and two full
chains, and a 28x1 RGBA8 storage surface of 10 levels (upload, views, a
color target, a fill, a buffer copy and a write-back) and a full 64x32
storage chain, through a recording mock device. It checks that every
image, copy, barrier, clear and view stays inside the levels the extent
can hold and that the accesses past them throw or are refused. On main it
fails with "28x1 BC3 with 10 levels: the image was created with 10 mip
levels, more than its 28x1 extent can hold (5)"; with only the sampled
texture part it fails with "a 28x1 storage image of 10 guest levels must
keep the 5 levels its extent has, not 10".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The previous commit gives a sampled view of a T# whose levels reach past
its extent's full mip chain only the levels of that chain. Shader
accesses that see the level count then diverged from the T#:
image_get_resinfo returned the view's count (5 for the 28x1 T# of levels
0-9 that Demon's Souls samples, 1 for its levels 7-9) instead of
LAST_LEVEL - BASE_LEVEL + 1, and its sizes at those LODs came from an
out-of-range OpImageQuerySizeLod.

image_get_resinfo adds the levels the view lacks to OpImageQueryLevels
and returns 1 for the width, height and depth at a LOD the view does not
hold. Both follow query_levels and lower_query_size in Mesa's
src/amd/common/nir/ac_nir_lower_resinfo.c, which derive them from the
descriptor: LAST_LEVEL - BASE_LEVEL + 1 and max(1, extent >>
(BASE_LEVEL + lod)); every level past the chain is 1x1. The count comes
from ResourceMaterializer::LevelsPastChain, which repeats the driver's
view rule, as a pipeline specialization constant (LevelsPastViewBase)
or, for registration modules, in bits 22-25 of the runtime image
metadata flags. The tracker records which image accesses observe levels
(ImageResource::levelUses), which moves the shader disk cache format to
37.

MIMG BY2/BY4 and PCK2/PCK4 loads stay as they are: on hardware they
return zero at every level narrower than their N texels, so a level the
view lacks reads zero either way. image_load_mip and image_get_lod, an
image_load through a T# whose base level lies past the chain, and
image_get_resinfo through an image table cannot be exact (the texels of
those levels are not represented, and a table does not carry the
missing count), so such a descriptor is refused: the draw or dispatch
throws, an image table entry faults. docs/dev/debt/shader.md records
it.

Test: agc_driver_image_levels_past_chain (tests/execution/
ImageLevelsPastChain.cpp) runs on the device: image_get_resinfo of a
28x1 2D and 2D-array T# of levels 0-9 at LODs 0-9 and of levels 7-9,
image_load_mip and image_load at base level 7 refused, image_sample_l of
levels 0-4 and image_load at base level 0 reading the uploaded texels,
and an image_store to level 0 of a 28x1 R32_UINT surface of 10 levels
(linear and R64KBX) changing only that level's 28 texels in guest
memory. Without this commit it fails with "image_get_resinfo of a
28x1 2D T# of levels 0-9 at LOD 0: the level count is 5, expected 10"
and the two loads run. agc_driver_graphics (tests/TextureMipChain.cpp)
checks that LevelsPastChain matches the driver's view for seven T#s,
the specialization constant and the metadata bits, and which accesses
are refused; its range check also covers array layers now.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
agc_driver_image_levels_past_chain sent each of its 32 invocations
another LOD (tid % levels) in one image_get_resinfo dispatch. On
lavapipe the 28x1 2D and 2D-array T#s of levels 0-9 failed at LOD 1
with a width of 28 instead of 14 (boykopovar#6280), although the module is
right: OpImageQuerySizeLod takes any integer LOD per invocation. Mesa's
llvmpipe up to 25.2 answers the size query of a vector of invocations
at the LOD of its first one (lp_build_size_query_soa in
src/gallium/auxiliary/gallivm/lp_bld_sample_soa.c, "FIXME: this needs
to honor per-element lod"), which bc56ec7ce032 (gallivm: Implement txs
with divergent explicit lod) removed in 25.3.0. Applied to the emitted
instructions, that behaviour gives exactly these two failures and
passes the levels 7-9 case, where every width is 1.

Every LOD of the T# now gets a dispatch of its own, with the same
expected width, height, layer count and level count. The dispatch with
a different LOD per invocation still runs on every device but llvmpipe,
which prints that it skips it.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Keep out-of-range queries on a valid Vulkan LOD, zero their extent and layer results, and retain the guest level count. Cover shortened and ordinary views, a single unrepresented base level, and capped sRGB copy paths. Preserve the active refusal for loads whose single base mip is not represented.

Co-Authored-By: Codex <noreply@openai.com>
Keep the repacked image, its view and refresh regions inside the levels allocated for the source extent. Exercise ordinary and unrepresented guest base levels through the recording mock device.

Co-Authored-By: Codex <noreply@openai.com>
Set the recording device's compute group-count limits so the repack refresh control reaches its recorded copy bounds. Qualify the existing raw LAST_LEVEL/MAX_MIP query discrepancy without changing decode behavior.

Co-Authored-By: Codex <noreply@openai.com>
@fdfawef324
fdfawef324 marked this pull request as draft October 19, 2026 05:26
@fdfawef324
fdfawef324 force-pushed the claude/agc-cap-texture-mip-chain branch from c80ba9e to 0e1f2ab Compare October 19, 2026 05:27
@fdfawef324

Copy link
Copy Markdown
Contributor Author

Thanks for the reports. The #6280 recovery preserves #6054's physical allocation/blit/view/refresh bounds, including uploadImage, plus the repacked-copy cap. ConvertedSampleRequired remains beside the level helpers; convertedSamples and levelUses both survive the codec and round-trip fixture. On final base 676d423968a1a8fcc79c6247020ce22090a8e0d4, the image field guard is 40 and cache format is 41, chosen after that base's version rather than copying an earlier suggestion.

The missing LOD>=count case is now covered: a valid physical LOD is selected before the Vulkan query, every extent/layer word is zeroed beyond the decoded count, and the count is retained. Tests include ordinary and shortened views, LOD=count/count+1/31/UINT_MAX and mixed lanes. A single base 7 / last 7 missing level now refuses loads/LOD queries while pure size queries remain valid. Frozen a599 passed four CPU/mock groups and its two selective CPU controls failed as intended. Final rebased/device evidence: 0e1f2ab53b59 passed the final seven-target Release build, CPU4 and actual Vulkan5 without skips; the latter took 4.35 seconds. Removing only the final zero-extent selection reproduced both expected count-boundary failures with exit1 in0.90 seconds. Exact runtime hashes were checked; the positive and negative results remain separate.

The new query fixtures have MAX_MIP=LAST_LEVEL. Raw LAST_LEVEL=9 / MAX_MIP=0 still follows the inherited decoder clamp and remains a discrepancy against thuanquang's report. The debt credits that RX 6700 XT/HIP evidence as desktop RDNA2 queries/loads, not PS5 or sampling/gather proof. Uncharted's eight clean ten-minute composed runs, fisherjoey's driver-commit 1500 s run and later 1535/1536 lavapipe stack remain attributed external results, not our own reruns. Extra-level backing and the composed-title results remain #7085's scope. The shared codec/eligibility order with #7550/#7579 is being coordinated in the linked description; this verified update stays in draft pending agreement, with no invented dependency or composed execution result.

AI-assisted: yes (Codex)
Co-Authored-By: Codex noreply@openai.com

@github-actions github-actions Bot removed the needs rebase Conflicts with main, rebase needed label Oct 19, 2026
@thuanquang

Copy link
Copy Markdown
Contributor

On the remaining MAX_MIP point: I measured what a T# whose LAST_LEVEL lies past MAX_MIP reads, on the same RX 6700 XT (gfx1031), through HIP. 28x1 2D T#, levels 0-9, linear, 32-bit float format, over memory where each dword holds its own index, with MAX_MIP 9, 4 and 0:

MAX_MIP 9 MAX_MIP 4 MAX_MIP 0
image_get_resinfo 10 levels, extents as in my earlier table the same the same
image_load_mip at (0, 0), LOD 0-9 10 different dwords LOD 0-4: 5 different dwords; LOD 5-9: LOD 4's dword the same dword at every LOD
image_sample_l near (0, 0), LOD 0-15 LOD 0-9: those 10 dwords; LOD 10-15: LOD 9's LOD 0-4 as for the load; LOD 5-15: LOD 4's the same dword at every LOD

image_load_mip at LOD 10 to 15 returns 0 in all three.

So MAX_MIP doesn't change what the query reports, but it decides the memory: every level past MAX_MIP reads the texels of level MAX_MIP, and the levels' addresses move with it (LOD 4 reads dword 16576 with MAX_MIP 9 and dword 16256 with MAX_MIP 4). So the decoder's clamp to MAX_MIP matches what loads and samples read on this GPU; only image_get_resinfo answers from LAST_LEVEL.

Desktop RDNA 2 again, not a PS5.

@oneandonlydean

Copy link
Copy Markdown
Collaborator

Thanks for keeping this current. Before a full review, could you rebase it onto current main? Two things come up:

  1. Texture.cpp conflicts in three places. Two are the imageInfo.mipLevels lines, where main also added a maxImageArrayLayers check that should stay next to geometry.imageLevels. The third is the copy-refusal block: main moved those checks into CopyRefusal(...), so the new "levels past the image" refusal belongs there now.
  2. The disk-cache bump needs to move on. main already raised FormatVersion to 41 and fieldCount<ImageResource>() to 40 for another field (1ed8eb6). With this PR on top, ImageResource has 41 fields and the static_assert in ShaderDiskCache.cpp fails to compile, so the rebase needs fieldCount 41 and FormatVersion 42.

#7085 composes these commits, so once this is rebased it can be restacked on the new head.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agc libSceAgc* build docs needs rebase Conflicts with main, rebase needed shader core/shader unblocks title Names a title ID on the Unblocks line

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants