You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Sampled image heap of 16 rejects a retail shader before the metadata limit #1789
That throw is BindingAllocator, when one image binding group is larger than RuntimeAbi::HeapCapacity. On this commit the sampled heap is 16 and the storage heap is 4 (core/shader/recompiler/RuntimeAbi.hpp). The earlier metadata check (ImageCapacity 256, SamplerHeapCapacity 16) had not fired, so the shader fit in the metadata arrays and still overflowed one descriptor group.
SampledHeapCapacity is also ResourceMaterializer::BindlessSlots(), and StorageHeapCapacity is the mip reservation for one dynamic storage image. Raising either constant to a device's raw maxPerStageDescriptorSampledImages (8,388,606 on an RX 6650 XT / RADV NAVI23) would size every bindless table and every dynamic storage image to that count. The per-stage limit is a shared budget, not a safe per-heap size.
Locally, sampled images and ImageCapacity were raised to 65,536, samplers to 1,024, and the storage mip chain to 16 (enough for a 16,384 texture). The libraries were rebuilt and the same title got past shader image heap capacity exceeded. The next abort was a non-constant texel offset, which already requires VK_KHR_maintenance8 and is covered by the closed test issue #827. This driver does not expose that extension.
Nothing in docs/ or the open issues records the 16-wide sampled heap as a title-facing limit.
@darklinkworker I’d like to take this one. I’ll investigate the bindless sampled/storage heap capacity handling and work toward a fix with appropriate limits and tests.
sounds good to me I just based it on the limits of my current GPU to see if it would get passed that point and it did. It doesn't to seem like AMD GPU's work yet since I saw another issue having driver issues like my did and my agent said we would have to put a patch in the mesa driver for linux which I am not doing. there has to be a better way around it. anyways I am off topic of this issue
Another title and an AMD data point: Astro Bot (PPSA21567 v01.019.000, retail) hits this on main4b6ab6b on an RX 9070 XT (Mesa 26.2.4 RADV). To get that far I needed #1836 and #1837 applied; on plain main it stops earlier (#1817).
I added a local print before the throw in BindingAllocator (not part of any PR). These groups overflow:
image group (FirstImageBinding + i)
images in group
capacity
images in the shader
2 (sampled)
40
16
44
30 (storage)
5
4
5
30 (storage)
5
4
6
30 (storage)
6
4
8
So a single sampled group reaches 40 here, more than double the current 16, and storage groups go to 6.
RADV on this device reports maxPerStageDescriptorSampledImages, maxPerStageDescriptorStorageImages and the update-after-bind variants all at 8388606. On this hardware, the device limit wouldn't be what caps these heaps.
Happy to run a candidate fix on this title and GPU.
Tested and written by Claude (AI assistant) on a contributor's machine.
@Priyasmit-work are you still on this one? I have a candidate on a branch and don't want to step on your claim: it splits RuntimeAbi's heap constant into the sampled group size, the storage group size, the storage mips (4) and the bindless slots (16), so groups go up to the 256 images the metadata allows while layouts stay sized by the shader's count. A new agc_driver_typed_heaps case with 40 sampled images (the Astro Bot group size above) fails on mainf145139 with this exact message on an RTX 4070 Ti and a Radeon 610M (RADV), and passes with the change; full ctest 497/497 on both.
If you have a PR close, I'll leave it to you and can compare notes there. Otherwise I'll open mine tomorrow.
Another data point: Sonic Origins (PPSA05324 v02.002.000) on mainf145139 + #2004, R9 380 (RADV), hits this 7 s in, at shader registration. With the group, size and capacity added to the message locally:
shader image heap capacity exceeded: group 31 holds 6 of capacity 4, images in shader 13
With the storage group capacity raised to 16 locally (the dynamic mip reservation kept at 4), the next registration stops at shader sampler pairs exceed runtime heap capacity. A sampler heap of 32 gets past it. That needs the ShaderData static assertions updated: the struct grows to 14528 bytes and ExportMappingsDword moves to 3624. Happy to test a candidate fix on this title and card.
@NahuelGenchi thanks, that log helps. My candidate is on CouchRiv:fix-shader-sampled-heap-capacity (bd5f22c, on mainf145139). A storage group now holds up to 1024 elements instead of 4, with a dynamic storage image still reserving 4 mips. So group 31 holds 6 of capacity 4 should go through. It doesn't touch the sampler pair limit, so I'd expect Sonic Origins to stop next at shader sampler pairs exceed runtime heap capacity, as in your local run. That would be a separate PR.
If you can run it on Sonic Origins, the first line it stops on would tell us whether the image heap part is enough. Still no PR from me while @Priyasmit-work's claim stands.
@CouchRiv Thanks for investigating this. I'm still interested in contributing to #1789, but I haven't opened a PR yet. Your candidate looks promising, especially with the Astro Bot reproduction. I'll review the changes and investigate the remaining capacity assumptions, including the sampler-pair limit seen with Sonic Origins. If you're planning to open a PR, I'd be happy to help validate the implementation and look for additional regressions rather than duplicate your work
I reviewed CouchRiv's candidate bd5f22c9 at source level against its f1451396 base. The split among the sampled group ceiling (256 metadata entries), storage group ceiling (256 × 4 mips), and 16 bindless table slots matches the reported failure and keeps the raw Vulkan per-stage limits out of the static ABI. The existing graphics code still checks actual sampled/storage descriptor counts against both per-stage and descriptor-set limits. git diff --check passes, and a merge-tree check onto current main6cc0503d is conflict-free.
One test detail to consider when preparing the PR: the new typed-heap execution case exercises 40 sampled images, while the reports here also include storage groups of 5–6. If the Astro Bot run on this candidate exercises those storage groups, calling that out in the Tested section would make the evidence clear; otherwise, a small storage-heap execution case would cover the second half of the reported limit. The current shader-device-profile case proves planning capacity, not Vulkan execution of a storage group larger than four.
Windows + NVIDIA data point for @CouchRiv's bd5f22c9: a retail Unreal Engine title on an RTX 5090 (Windows 11, MinGW-w64 build), maind70b8998 + #1836 + bd5f22c9 merged cleanly.
Without the branch, 58 shaders per run stop on shader image heap capacity exceeded (plus one shader sampler pairs exceed runtime heap capacity). With it, 0 heap-capacity failures in four runs. The sampler-pair message did not appear either.
There's a side effect worth noting for anyone else seeing Unreal's heartbeat hang (FThreadHeartBeat deliberately writing 0xE0000001 to address 3). Because those shaders never prepare, they are never stored in the shader disk cache. Every run had 57 permanent misses, recompiled on each attempt under ShaderPreparationTransaction's process-wide State::writers mutex. A CDB dump at the hang showed 11 UE worker threads waiting in the ShaderPreparationTransaction constructor while one thread was in SPIR-V emission. That stalled the game thread past UE's hang timeout every run.
With the branch and a warm cache, misses go to 0 (902 hits, 0 misses) and the heartbeat hang is gone in both runs. The title now stops later on an unrelated issue.
Tested and written by Claude (Claude Code) on a contributor's machine.
Retried PPSA20612 on another machine. After the local heap change, the previous machine stopped here:
SPIR-V emission failed: hash=0x139752974974976 stage=4 opcode=ImageSampleRaw
reason=has a texel offset that is not a constant, which image sampling takes only with VK_KHR_maintenance8 and shaderImageGatherExtended
That box was Fedora 38, an RX 6650 XT, and Mesa 23.1.9. Its kernel and Mesa were too old: that Mesa does not advertise VK_KHR_maintenance8.
This machine does (VK_KHR_maintenance8 revision 1, and shaderImageGatherExtended is true). The same title, with the same local RuntimeAbi heap sizes, selected the integrated GPU and compiled 1,275 shaders. The ImageSampleRaw non-constant texel offset abort did not recur.
Host:
Nobara Linux 44, kernel 7.1.3-200.nobara.fc44.x86_64, glibc 2.43
This seems like a doc issue to state that you should be on a newer Linux kernel or at least have mesa 25.2 drivers if you want the game to run.
The run still aborts later, on packed pixel ancillary input has an unsupported live use. That is separate from this heap issue. (still in process to see if this is a new issue to report or my own fault at the moment)
Open PRs for these limits: #2347 (sampled heap 16 -> 32), #2282 (storage heap 4 -> 16) and #2141 (sampler pairs 16 -> 32). The sampled group of 40 reported above is still over #2347's 32.
#2282 (85268f8) on a second title, on Linux with NVIDIA: 007 First Light (PPSA11386 v01.018.000), CachyOS (kernel 7.2.9), GCC 16.2.1, RTX 3080 (NVIDIA 615.71.09), Release build of main8b393b6 plus the changes that get the title this far (SleglJan#15 to #20 and #1964; none of them touches BindingAllocator or RuntimeAbi).
Closing: #2347, #2282 and #2141 are merged, so the sampled heap holds 64 images, the storage heap 16 and the sampler heap 32 (core/shader/recompiler/RuntimeAbi.hpp:37-41). Please reopen if a title still stops on a heap capacity check on current main.
Activity
Priyasmit-work commentedon Oct 8, 2026
@darklinkworker I’d like to take this one. I’ll investigate the bindless sampled/storage heap capacity handling and work toward a fix with appropriate limits and tests.
darklinkworker commentedon Oct 8, 2026
sounds good to me I just based it on the limits of my current GPU to see if it would get passed that point and it did. It doesn't to seem like AMD GPU's work yet since I saw another issue having driver issues like my did and my agent said we would have to put a patch in the mesa driver for linux which I am not doing. there has to be a better way around it. anyways I am off topic of this issue
EdouardSence commentedon Oct 8, 2026
Another title and an AMD data point: Astro Bot (PPSA21567 v01.019.000, retail) hits this on
main4b6ab6b on an RX 9070 XT (Mesa 26.2.4 RADV). To get that far I needed #1836 and #1837 applied; on plainmainit stops earlier (#1817).I added a local print before the throw in
BindingAllocator(not part of any PR). These groups overflow:FirstImageBinding + i)So a single sampled group reaches 40 here, more than double the current 16, and storage groups go to 6.
RADV on this device reports
maxPerStageDescriptorSampledImages,maxPerStageDescriptorStorageImagesand the update-after-bind variants all at 8388606. On this hardware, the device limit wouldn't be what caps these heaps.Happy to run a candidate fix on this title and GPU.
Tested and written by Claude (AI assistant) on a contributor's machine.
CouchRiv commentedon Oct 9, 2026
@Priyasmit-work are you still on this one? I have a candidate on a branch and don't want to step on your claim: it splits
RuntimeAbi's heap constant into the sampled group size, the storage group size, the storage mips (4) and the bindless slots (16), so groups go up to the 256 images the metadata allows while layouts stay sized by the shader's count. A newagc_driver_typed_heapscase with 40 sampled images (the Astro Bot group size above) fails onmainf145139 with this exact message on an RTX 4070 Ti and a Radeon 610M (RADV), and passes with the change; full ctest 497/497 on both.If you have a PR close, I'll leave it to you and can compare notes there. Otherwise I'll open mine tomorrow.
NahuelGenchi commentedon Oct 9, 2026
Another data point: Sonic Origins (PPSA05324 v02.002.000) on
mainf145139 + #2004, R9 380 (RADV), hits this 7 s in, at shader registration. With the group, size and capacity added to the message locally:With the storage group capacity raised to 16 locally (the dynamic mip reservation kept at 4), the next registration stops at
shader sampler pairs exceed runtime heap capacity. A sampler heap of 32 gets past it. That needs theShaderDatastatic assertions updated: the struct grows to 14528 bytes andExportMappingsDwordmoves to 3624. Happy to test a candidate fix on this title and card.Bring-up thread: #2021
CouchRiv commentedon Oct 9, 2026
@NahuelGenchi thanks, that log helps. My candidate is on
CouchRiv:fix-shader-sampled-heap-capacity(bd5f22c, onmainf145139). A storage group now holds up to 1024 elements instead of 4, with a dynamic storage image still reserving 4 mips. Sogroup 31 holds 6 of capacity 4should go through. It doesn't touch the sampler pair limit, so I'd expect Sonic Origins to stop next atshader sampler pairs exceed runtime heap capacity, as in your local run. That would be a separate PR.If you can run it on Sonic Origins, the first line it stops on would tell us whether the image heap part is enough. Still no PR from me while @Priyasmit-work's claim stands.
EdouardSence commentedon Oct 9, 2026
@CouchRiv Astro Bot (PPSA21567) data for your branch bd5f22c, on RX 9070 XT (RADV / Mesa 26.2.4, Linux).
maina8b032b + feat(agc): implement deferred faults for reads through null SRT pointers #759 + fix(agc): defer shaders that cannot be prepared at registration to their first use #1836 + fix(agc): accept bound copies of a registered shader header that differ only in user_data #1837, the run stops about 2 min 20 s in onshader image heap capacity exceeded.sampler pairs exceed runtime heap capacityerror appears either.prepared shader artifact is missing for the requested static ABIfor the null pixel program (Draw with no pixel program fails: "prepared shader artifact is missing for the requested static ABI" (null pixel program) #1901/fix(agc): prepare the null pixel program at draw when its variant was not prepared #1902), which is unrelated to this issue.Tested and written by Claude (AI assistant) on a contributor's machine.
Priyasmit-work commentedon Oct 9, 2026
@CouchRiv Thanks for investigating this. I'm still interested in contributing to #1789, but I haven't opened a PR yet. Your candidate looks promising, especially with the Astro Bot reproduction. I'll review the changes and investigate the remaining capacity assumptions, including the sampler-pair limit seen with Sonic Origins. If you're planning to open a PR, I'd be happy to help validate the implementation and look for additional regressions rather than duplicate your work
MarcZX10 commentedon Oct 9, 2026
I reviewed CouchRiv's candidate
bd5f22c9at source level against itsf1451396base. The split among the sampled group ceiling (256 metadata entries), storage group ceiling (256 × 4 mips), and 16 bindless table slots matches the reported failure and keeps the raw Vulkan per-stage limits out of the static ABI. The existing graphics code still checks actual sampled/storage descriptor counts against both per-stage and descriptor-set limits.git diff --checkpasses, and a merge-tree check onto currentmain6cc0503dis conflict-free.One test detail to consider when preparing the PR: the new typed-heap execution case exercises 40 sampled images, while the reports here also include storage groups of 5–6. If the Astro Bot run on this candidate exercises those storage groups, calling that out in the Tested section would make the evidence clear; otherwise, a small storage-heap execution case would cover the second half of the reported limit. The current shader-device-profile case proves planning capacity, not Vulkan execution of a storage group larger than four.
mrk1987 commentedon Oct 9, 2026
Windows + NVIDIA data point for @CouchRiv's
bd5f22c9: a retail Unreal Engine title on an RTX 5090 (Windows 11, MinGW-w64 build),maind70b8998+ #1836 +bd5f22c9merged cleanly.shader image heap capacity exceeded(plus oneshader sampler pairs exceed runtime heap capacity). With it, 0 heap-capacity failures in four runs. The sampler-pair message did not appear either.FThreadHeartBeatdeliberately writing0xE0000001to address 3). Because those shaders never prepare, they are never stored in the shader disk cache. Every run had 57 permanent misses, recompiled on each attempt underShaderPreparationTransaction's process-wideState::writersmutex. A CDB dump at the hang showed 11 UE worker threads waiting in theShaderPreparationTransactionconstructor while one thread was in SPIR-V emission. That stalled the game thread past UE's hang timeout every run.902 hits, 0 misses) and the heartbeat hang is gone in both runs. The title now stops later on an unrelated issue.Tested and written by Claude (Claude Code) on a contributor's machine.
darklinkworker commentedon Oct 9, 2026
Retried PPSA20612 on another machine. After the local heap change, the previous machine stopped here:
That box was Fedora 38, an RX 6650 XT, and Mesa 23.1.9. Its kernel and Mesa were too old: that Mesa does not advertise
VK_KHR_maintenance8.This machine does (
VK_KHR_maintenance8revision 1, andshaderImageGatherExtendedis true). The same title, with the same localRuntimeAbiheap sizes, selected the integrated GPU and compiled 1,275 shaders. TheImageSampleRawnon-constant texel offset abort did not recur.Host:
This seems like a doc issue to state that you should be on a newer Linux kernel or at least have mesa 25.2 drivers if you want the game to run.
The run still aborts later, on
packed pixel ancillary input has an unsupported live use. That is separate from this heap issue. (still in process to see if this is a new issue to report or my own fault at the moment)oneandonlydean commentedon Oct 9, 2026
Open PRs for these limits: #2347 (sampled heap 16 -> 32), #2282 (storage heap 4 -> 16) and #2141 (sampler pairs 16 -> 32). The sampled group of 40 reported above is still over #2347's 32.
SleglJan commentedon Oct 10, 2026
#2282 (85268f8) on a second title, on Linux with NVIDIA: 007 First Light (PPSA11386 v01.018.000), CachyOS (kernel 7.2.9), GCC 16.2.1, RTX 3080 (NVIDIA 615.71.09), Release build of
main8b393b6 plus the changes that get the title this far (SleglJan#15 to #20 and #1964; none of them touchesBindingAllocatororRuntimeAbi).ShaderRecompiler::Recompile: shader image heap capacity exceeded. A temporary print at the throw inBindingAllocatorshowsimageGroups[30](binding 31, the 2D float storage-image heap) at 5 slots againstStorageHeapCapacity4.VOP3 source modifiers are not implemented(v_cubeid_f32withdiv:2, the case in fix(shader): accept cube output modifiers #2463), no sampled-heap (fix(recompiler): hold 64 images in a sampled image heap #2347) or sampler-pair (fix(shader): reserve heap space for sixteen sampler pairs #2141) error comes up.AI-assisted: yes (Claude Code)
oneandonlydean commentedon Oct 10, 2026
Closing: #2347, #2282 and #2141 are merged, so the sampled heap holds 64 images, the storage heap 16 and the sampler heap 32 (
core/shader/recompiler/RuntimeAbi.hpp:37-41). Please reopen if a title still stops on a heap capacity check on current main.