Skip to content

feat(recompiler): bindless image tables up to the device's sampled-image limit - #1184

Closed
MichonGoddijn231849 wants to merge 5 commits into
boykopovar:mainfrom
MichonGoddijn231849:feat/large-bindless-tables
Closed

MichonGoddijn231849 wants to merge 5 commits into
boykopovar:mainfrom
MichonGoddijn231849:feat/large-bindless-tables

Conversation

@MichonGoddijn231849

Copy link
Copy Markdown
Contributor

What

A whole-table bindless image table binds its entries as one descriptor array, sized by the table (the next power of two, at least APS5_BINDLESS_SLOTS) up to the device's per-stage sampled-image limit, at most 65536. Before, tables wider than 48 slots were refused. The key indexes the array directly. GTA V's fidelity mode reads a 65536-entry T# heap from a compute pass.

  • A table binds the shape (numeric class, dimension, cube) of the access's group, not of its first entry. A 2D access whose table started with a cube or 3D texture sampled zeros for its 2D entries.
  • A table entry whose reads build more than one T# is planned for each of them. A heap offset (key * 32) & mask, with a contiguous mask keeping at least 16 key bits, matches like key * 32.
  • A table whose keys select nothing binds null descriptors and an empty mapping, so every key samples zeros, as on hardware.
  • A T# in a depth-comparison binding whose format no comparison can read binds a zero texture, as a null T# does.
  • SetBindlessTableLimit is reviewed for the shader disk cache key (it reaches the key through the specialization's table slots). The disk cache format version is 8.

tests/ShaderMemory.cpp covers the table planning cases.

Tested

Windows 11 Pro, AMD Ryzen 5 7600, NVIDIA GeForce RTX 5080 (driver 32.0.16.1074), 32 GB, MinGW-w64 GCC 15.2.0.

  • GTA V PPSA04264 (01.005) runs with this change on the combined gta-v/testing branch (Performance mode, the prologue).
  • On this branch: builds, and ctest passes. Not run here: the relinker's Python tests (my local Python does not find their helper modules) and guest_gameupdate.

Checklist

  • Based on current main; no other open PR implements the same functions
  • One topic per PR; follow-ups go in a new PR
  • No comments in code except technical debt
  • Unimplemented paths throw (NotImplemented_nid_no_patch); silent stubs are listed in TechnicalDebt
  • No notes, investigation .md files or images added to the repository (attach them to this PR)
  • New third-party code is a submodule built from source
  • Generic behaviour, not specific to one title
  • Depends on: fix(agc): an all-zero sampled descriptor binds a 1x1 zero texture #293 (null texture descriptors, which the padded and empty tables bind)
  • AI-assisted: yes. Written with Claude (Anthropic) under my direction; I reviewed and tested it.

🤖 Generated with Claude Code

@MichonGoddijn231849
MichonGoddijn231849 force-pushed the feat/large-bindless-tables branch from de5be91 to 1761a5d Compare October 7, 2026 18:18
@github-actions github-actions Bot added build shader core/shader docs agc libSceAgc* labels Oct 7, 2026
@MichonGoddijn231849

Copy link
Copy Markdown
Contributor Author

Rebased onto main and onto the updated #293 (its own changes are now one commit). Adapting to what changed underneath:

  • nullTexture keeps fix(agc): an all-zero sampled descriptor binds a 1x1 zero texture #293's rule: without nullDescriptor, a comparison binding of a T# no comparison can read (all zero, or a format no comparison reads) throws instead of binding a zero texture. resourceTests in agc_driver_graphics checks the refusal names nullDescriptor and carries the dwords.
  • Descriptor pools: main now checks SetDescriptorLimit and gives a set that does not fit the chain pool a dedicated pool, so the chain-pool growth this PR had is gone; a large table set gets a dedicated pool sized for it.
  • The shader disk cache format is version 10 (main is at 9), and the Linux layout checks match the current structs.

@fisherjoey thanks for the Demon's Souls run. You read it right: the material-selected path (table.hasMaterial) still caps the distinct keys at APS5_BINDLESS_SLOTS (16, at most 48); only the direct-index path goes up to the device limit. Raising the material path changes how its slots are materialized, so I'll do it in a follow-up PR rather than grow this one.

@fisherjoey

Copy link
Copy Markdown
Contributor

Data from Demon's Souls (PPSA01341 v1.07, Linux, RTX 5070 Ti) on a stack with this PR, for the table paths it doesn't cover.

Compute shader 0x248946900 selects its images through a material table (resolveTableImage), and that path still sizes the table from APS5_BINDLESS_SLOTS (default 16, clamped to 48) rather than the device limit. The number of distinct keys it needs depends on the scene:

where distinct keys
opening cinematic 17, and 37 in another run (32 slots crashed)
tutorial level, loaded through the title's debug start menu 60 to 93

With this PR and no APS5_BINDLESS_SLOTS, the debug-start route ends with exit -6: compute shader 0x248946900: bindless image table: 60 distinct keys exceed the 16 slots. With APS5_BINDLESS_SLOTS=128 on a local build it reaches the level. Through the normal menus the same shader stayed under 48 in our runs, so this only shows up with the larger material sets.

The other failure we saw on this shader, bindless image table selects no entry when every material key is past the heap's entry count (2 of 4 runs in the character creator), is the case bindNullTable here covers; we had the same fix locally.

Is the material-selected path meant to move to the device limit too, here or in #757?

@MichonGoddijn231849

Copy link
Copy Markdown
Contributor Author

Parked as a draft: with #639 a bindless table expands statically into the runtime ABI's sampled heap, so binding tables larger than 16 slots needs a new design rather than a rebase. @fisherjoey thanks for the Demon's Souls data on the material-table path; I'll use it when I redo this on the runtime ABI.

Scramblrrrr added a commit to Scramblrrrr/AnyPS5 that referenced this pull request Oct 10, 2026
Implement the BitReverse32 prerequisite from Michon upstream boykopovar#1184, with owned constant and runtime-value regressions.
@simonbronk

Copy link
Copy Markdown
Contributor

@MichonGoddijn231849 are you already redoing this on the runtime ABI? Onimusha: Way of the Sword (PPSA27836) needs it too: after #5620 and #5550 it stops at static bindless image capacity exceeded (#5720), and with MaxImages and SampledHeapCapacity raised locally to 128, at a compute program that reads a whole 32768-entry table with no material records (bindless image table has 32768 entries (0 materials), limit 16). Details in #5769.

If you have not started, I would like to try the redesign and would build on this PR's approach, crediting you. If you have, I will test your branch on this title instead of writing a second version. Either way is fine.

AI-assisted: yes (Claude Code).

@MichonGoddijn231849
MichonGoddijn231849 marked this pull request as ready for review October 15, 2026 10:13
@adriadam10 adriadam10 self-assigned this Oct 15, 2026
@adriadam10

Copy link
Copy Markdown
Collaborator

Closing: the author said on 2026-10-09 that after #639 a bindless table expands statically into the runtime ABI's sampled heap, so this needs a new design rather than a rebase. The branch has had no push since 2026-10-08, conflicts with main in the resource materializer/tracker, binding allocator, ShaderResources.cpp and the disk cache, and depends on #293, which was closed as superseded by #639.

The measurements here (Demon's Souls material-table counts from @fisherjoey, GTA V's 65536-entry heap, Onimusha's 32768-entry table in #5769) are useful input for the redesign. @simonbronk has offered to redo it on the runtime ABI; feel free to coordinate there or reopen if you push a version rebased on the runtime ABI.

@adriadam10 adriadam10 closed this Oct 15, 2026
@MichonGoddijn231849

Copy link
Copy Markdown
Contributor Author

@simonbronk I haven't started the redesign, so please go ahead and build on this PR's approach. @adriadam10 closing this is fine.

What I'd keep from it: the table sized from the device's sampled-image limit instead of a slot count. The data in this thread gives the sizes to design for: Demon's Souls' material-selected table needs 60-93 distinct keys in the tutorial level, GTA V binds a 65536-entry heap, and Onimusha reads a whole 32768-entry table with no material records. Since #639 the table expands statically into the runtime ABI's sampled heap, which is where SampledHeapCapacity and MaxImages stop it, so the redesign has to start there. Link your PR here and I'll test it on Wolverine and GTA V.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants