Repository navigation
fix(shader): follow pointer hops and fixed-offset V# reads behind a record pointer - #9457
EagleBearerYS wants to merge 82 commits into
Conversation
An S# read from a V# that a scalar record selects through a pointer was refused, so recompiling failed with "GetSamplerResource dword 0 is not a valid runtime value". The nested branch now takes sampler columns: they get child tables per distinct V# like nested T#s, share equal children, count against the nested key budget and the S# entry budget, and fault on an unmapped, non-buffer or uncaptured parent. The plan decoder accepts a nested sampler column; the plan encoding is unchanged.
An S# or T# loaded through a pointer that a scalar record holds was refused when a Phi merged the pointer's low word with constants, so recompiling failed with "GetSamplerResource dword 0 is not a valid runtime value". Such a column is now pointer-keyed: the snapshot captures every record's pointer and the descriptor behind it, the map holds boykopovar#7223's sorted pointer dictionary with descriptor records as its codes, and the GPU looks up the actual 64-bit pointer. A pointer that was not captured faults as outside the snapshot, and a null one as unmapped. The plan gains TableColumn::pointerKeyed and the snapshot gains ImageTableColumnSnapshot::pointerKeyed, so the disk-cache format moves to 43 and the image-table ABI to 4.
A T# loaded through a record pointer whose low word passes nested Phis was refused when one Phi arm held a word of a Ballot lane mask, as in a waterfall loop that reuses the pointer's SGPR for an s_and_saveexec or v_cmp mask, so recompiling failed with "GetImageResource dword 0 is not a valid runtime value". A pointer-keyed column now accepts such a word as an arm that is not a record pointer, as it does for constants, and still refuses any other foreign arm. At run time a pointer built from a lane mask is not a captured pointer and faults as outside the snapshot. A pointer-keyed column also accepts low-word reads, and a high-word read, of the same record word under different keys: same table, record offset, stride and addend. The GPU looks the pointer up by its value, so the key does not matter there. The column takes its table and record offset from the high-word read, which dominates the descriptor load. A shader that planned before plans the same way, so the disk-cache format stays at 43.
…ed record pointer A T# loaded through a record pointer was still refused with "GetImageResource dword 0 is not a valid runtime value" when the pointer's low word passed ANDs with lane masks, as a waterfall loop that copies EXEC into the pointer's SGPR builds them, or when its high word was a Phi of the record's high word read under several keys. For a pointer-keyed column, the walk of the low word now takes an AND with a lane-mask operand (a Ballot word, or an AND or Phi of only Ballot words and immediates) and keeps walking its other operand, so its record reads must still match the column and anything else still refuses. The high word is walked the same way: its record reads must be the record word at the low word's offset plus 4. A high word that is one read still gives the column its table and record offset, as before. Otherwise the table comes from a record read whose V# words are defined before the descriptor load, and the record offset from the high word, which the GPU does not read for a pointer-keyed column. A high-word arm read from another buffer, such as one whose V# is loaded through a pointer, stays refused. A shader that planned before plans the same way, so the disk-cache format does not change.
… a pointer-keyed record pointer A T# loaded through a record pointer was still refused with "GetImageResource dword 0 is not a valid runtime value" when a Phi of the pointer's low word merged the record read, a zero, and the waterfall's lane mask with the handled lane's bit cleared, BitwiseAnd32(CompositeExtractU32x4(Ballot(...), 0), BitwiseNot32(ShiftLeftLogical32(1, index))), as s_ff1, s_lshl and s_not with s_and, or s_andn2, build it in the SGPR the pointer reuses. The walk took only Ballot words and ANDs of them as lane masks, so it walked into the NOT and refused. A lane-mask operand is now a Ballot word or the loop's lane bit, a shift of 1 by an index from FindILsb32, FindUMsb32 or ReadFirstLane (through the AND, add, subtract and select that s_ff1_i32_b64, s_bitset0 and the shift's own mask put around it), or an AND, OR, NOT or Phi of only those and immediates. An arm of the pointer that is entirely such an operand is skipped. An AND with a record read in it still has the read matched against the column, and anything else still refuses. agc_driver_pointer_phi_lane_not_table builds that shape in a wave64 waterfall: the low word's Phis merge the record read at +0, a zero and the lane mask without the handled lane's bit, cleared by s_not and s_and and by s_andn2, and the high word is one read at +4. Each lane samples the T# of its record, and every masked word faults outside the snapshot. agc_driver_pointer_vsharp_select_table reads a record keyed by ReadFirstLane(SelectU32(LogicalAnd, IAdd32, Phi)), a pointer from it, a V# through the pointer and the T# through the V#; it passes without this change and keeps that chain checked, including a record pointer moved to the other V# without a recompile. Shaders that planned before plan the same way, and a refusal is never cached, so the disk-cache format does not change.
…keyed records A pointer-keyed record pointer now also takes lane-mask ANDs, the waterfall loop's lane bit and its OR and NOT forms, and a high word merged from the record's next word. A high word read from a second buffer stays refused.
The low and high words of a pointer-keyed record pointer were walked separately, so a high-word arm on a path whose low word is a lane mask refused the plan even though that pair is no pointer. Ratchet & Clank: Rift Apart (PPSA01474) stops this way at LoadAddressU32@pc=0x9a30: one high-word arm reads a second buffer, and on that edge the low word is a lane mask, the waterfall loop reusing the SGPR pair. Walk the two words together. Where both are Phis of one block, each low-word edge takes the high word of the same predecessor. An edge whose low word is a constant or a lane mask is skipped with its high word. A record low word still needs every high word it can meet to be a constant, a lane mask or the same record column at offset + 4, so a second-buffer high word paired with the record word stays refused. agc_driver_pointer_phi_high_second_lane_table adds the lane-mask low word to the second-buffer arm: it plans, each group samples the T# its record selects, and that arm faults outside the snapshot.
…nter The two words of the pointer are now walked edge by edge, and an edge whose low word is a constant or a lane mask is skipped with its high word. A high word read from a second buffer stays refused on an edge whose low word is the record word.
Brings boykopovar#8991 (match image-table T# halves offset before and after readfirstlane). ResourceTracker.cpp: main's FirstLaneOffset, ParseFirstLaneOffset and SameFirstLaneOffset go before TryMakeTableColumn, which keeps this branch's signature with the buffer parameter. Main's first-lane base check in the column loop merged on its own.
…ane-masks Brings boykopovar#7395's merge of main bd4d801, with boykopovar#8991. It merged without conflicts.
TryMakeIndirectColumn refused every pointer hop once the record's pointer words were merged, so a T# read through a pointer loaded from a pointer-keyed record pointer stayed unplanned (Gran Turismo 7's World Map compute shaders, issue boykopovar#6191). Only buffer handles still refuse hops: the materializer keys the records by the innermost pointer before it follows the hops, and the plan's parent pointer is that innermost one.
…one-key child From hugodearaujo's change on boykopovar#8939 (Marvel's Spider-Man 2, PPSA03016).
Spider-Man 2's shape: a record keyed by a first-lane read, its dwords 2-3 a pointer, a V# loaded at that pointer plus 0xa0, and the T# read at offset 0 or 0x40 of that V#'s buffer with no second key. Two records point at V#s of different T#s; a moved record pointer and a moved V# must change the result without recompiling.
|
@frankea @hugodearaujo @spiff637, this draft is the next step on #6191's chain for your titles, stacked on #8939 (
Its tests pass on lavapipe. It hasn't run on either title or on real hardware yet. |
|
Other open pull requests touch the same code. Merging one will break the other, or both implement the same thing. If this one builds on them, list them in Depends on.
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.
|
MarcZX10
left a comment
There was a problem hiding this comment.
The new lavapipe tests exercise both reported resource-chain shapes, include negative controls and relocation-without-recompile cases, and the PR reports Windows compilation plus the relevant focused CI results. I cannot treat the AGC/shader validation protocol as complete from the current report: it does not show the same focused tests run on current main and this change with ANYPS5_REQUIRE_VULKAN=1, ANYPS5_NO_SHADER_CACHE=1, and VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation, confirm the requested validation layer loaded in both runs, or compare new VUID- messages. Please attach those paired logs/results and name the GPU/driver/OS as required. Also, this head is based on 0c6a5bd rather than current main (110a18ba01); please rebase and rerun conventions, overlap and the focused validation suite on the updated tree. I did not run local GPU tests.
jotitadev
left a comment
There was a problem hiding this comment.
First run on a hardware GPU: an RTX 3070, plus lavapipe again.
Setup: Ubuntu 26.04, GCC 15.2, Release, head c00cb0f87 merged onto main d6eafa54d (clean merge). ANYPS5_GPU picks the device, ANYPS5_REQUIRE_VULKAN=1, ctest -j1.
- Red: the PR with this PR's two fixes reverted (
668118771and0843cca39, source only, tests kept).agc_driver_pointer_hop_table,agc_driver_pointer_vsharp_fixed_tableandagc_driver_pointer_vsharp_fixed_offset_tablefail on both GPUs with theGetImageResource dword 0 is not a valid runtime valuechains from the description. The other 13nested_/pointer_tests pass. - Green: all 16
agc_driver_(nested_|pointer_)tests pass 3 of 3 on each GPU, none skipped.image_table|pointer|disk_cache|shader_memory|sampler_table(27 tests) passes 3 of 3 on each. - Full
^agcsuite on the 3070 (877 tests, withoutdisplay_buffer_dcc,driver_flip,lds_atomics64): 874 pass, 1 skips (stencil_ref_export). The 3 failures areagc_driver_sample_order,_grid_referenceand_recipe_depth_locations, which fail the same way onmaind6eafa54don this card.
GPUs tested: NVIDIA GeForce RTX 3070 (driver 595.99.02), Mesa lavapipe 26.0.3 (LLVM 21.1.8), Ubuntu 26.04
Written with AI assistance (Claude Code). I ran the builds and tests above on my machine.
|
@jotitadev thanks for the RTX 3070 run with a red control. The three new cases fail with the fixes reverted and pass with them on hardware as well as on lavapipe, which is what this draft needed beyond llvmpipe. It's in Tested and on the GPUs tested line now. |
|
@MarcZX10 thanks. By your review's points:
Both runs are in Tested. |
✅ NVIDIA GPU test: passedPR head
Unstable on main (4, these also failed in recent main runs on this machine; not counted against this PR)Failing on main too (3, not counted against this PR)Validated but not compared (17, not in the main baseline's validation pass)Validation IDs already present on main (4 IDs in 510 tests)Skipped (45)ReproduceAutomated build and test on a contributor's NVIDIA machine; it does not replace upstream CI. A new comment is posted for each new push. Full logs. |
# Conflicts: # core/libs/prx/libSceAgcDriver/tests/cmake/agc_driver_image_table_tests.cmake # core/shader/recompiler/ShaderDiskCache.cpp # core/shader/recompiler/ShaderDiskCache.hpp
…at, 70 boykopovar#9457 is at 67, so this PR takes 70, above it and every other open PR's number.
✅ AMD GPU test: passedPR head
Unstable on main (2, these also failed in recent main runs on this machine; not counted against this PR)Failing on main too (8, not counted against this PR)Passed on retry (4, failed in the parallel run, passed when re-run with a 360 s timeout; not counted against this PR)Validated but not compared (4, not in the main baseline's validation pass)Validation IDs already present on main (4 IDs in 535 tests)Skipped (58)ReproduceAutomated build and test on a contributor's AMD machine; it does not replace upstream CI. A new comment is posted for each new push. Full logs. |
✅ AMD GPU test: passedPR head
Unstable on main (1, these also failed in recent main runs on this machine; not counted against this PR)Failing on main too (8, not counted against this PR)Passed on retry (1, failed in the parallel run, passed when re-run with a 360 s timeout; not counted against this PR)Validated but not compared (3, not in the main baseline's validation pass)Validation IDs already present on main (4 IDs in 527 tests)Skipped (57)ReproduceAutomated build and test on a contributor's AMD machine; it does not replace upstream CI. A new comment is posted for each new push. Full logs. |
XairRrR
left a comment
There was a problem hiding this comment.
Re-checked — approved
Since my last review the branch has only taken new merges of main, the latest being 7aa70b1. The merged tree builds, passes the checks, the focused tests and the validation comparison. Reverting the PR's two planner hunks makes exactly its three new tests fail.
What changed since my last review
The text of my previous review is not available, so I reviewed the whole change again rather than only a delta. Since earlier heads, the branch has gained merges of #8939/#7395/#7223 and of main. The latest is 7aa70b1, a merge of main. This PR's own changes are the same two ResourceTracker.cpp hunks:
- the hop guard, now
if (!hops.empty() && buffer) return false;; - the fixed-offset one-key child (hugodearaujo's commit).
FormatVersion is 67, above main's 52.
What I ran
Head 7aa70b1bd2fcda0a48d036901c3de73ad6c6f739, main 4f41f4c375f5abb487dbd184fbc150f31994d762, merged tree 305bc0a81e4dd874e65b111aa19064ffaa681591. Debian 13 VM, GCC 14.2.0, Release, lavapipe (Mesa 26.1.6, LLVM 19).
git diff --check 4f41f4c375f5abb487dbd184fbc150f31994d762...7aa70b1bd2fcda0a48d036901c3de73ad6c6f739
python3 tools/check_conventions.py --base 4f41f4c375f5abb487dbd184fbc150f31994d762
env ANYPS5_REQUIRE_VULKAN=1 ANYPS5_NO_SHADER_CACHE=1 ctest --test-dir build -j8 --test-load 32 --output-on-failure \
-R "^agc_driver_(pointer_|nested_|image_table)|^agc_shader_(disk_cache|bindless|memory|nested|descriptor_phis)"
# negative control: revert the PR's two hunks in ResourceTracker.cpp
# if (!hops.empty() && buffer) -> if (!hops.empty() && (buffer || merged))
# const bool fixed = !address && !buffer && immediateU32(...) -> const bool fixed = false && immediateU32(...)
ninja -C build -j32 -l32
env ANYPS5_REQUIRE_VULKAN=1 ANYPS5_NO_SHADER_CACHE=1 ctest --test-dir build -j8 --test-load 32 --output-on-failure -R "^agc_driver_(pointer_|nested_)"
git show 305bc0a81e4dd874e65b111aa19064ffaa681591:core/shader/recompiler/Optimization/src/ResourceTracker.cpp > core/shader/recompiler/Optimization/src/ResourceTracker.cpp
ninja -C build -j32 -l32
ctest --test-dir build -R "^agc_driver_pointer_(hop|vsharp_fixed)"
git status --porcelain
Results
| Check | Result |
|---|---|
Merge into main |
Clean |
git diff --check |
Clean |
check_conventions.py |
All checks passed |
Configure, build, libs (script) |
OK |
| Selected tests (script) | 2231 ran, 0 new failures, 0 timeouts. The 7 known failures fail on main too. |
| Focused set, 30 tests | 30/30 pass. Every test finishes in under 9 s, and the new ones take about 1 s. |
| Validation layer (script, 785 tests) | Layer loaded in 784, missing in none, 0 tests with a new VUID- |
| Negative control | Only the 3 new tests fail (see below) |
| Worktree restored | git status --porcelain empty; the 3 tests pass again after the rebuild |
Negative control output (truncated)
agc_driver_pointer_hop_table ....***Failed
GetImageResource dword 0 is not a valid runtime value; chain: LoadAddressU32@pc=0x000000b4(GetAddressResource(LoadAddressU32@pc=0x000000a8(GetAddressResource(Phi(Immediate, Phi(ReadConstBuffer@pc=0x00000074(...), CompositeExtractU32x4(Ballot(LogicalAnd), Immediate)))
agc_driver_pointer_vsharp_fixed_offset_table ....***Failed
GetImageResource dword 0 is not a valid runtime value; chain: ReadConstBuffer@pc=0x0000008c(GetBufferResource(LoadAddressU32@pc=0x00000080(GetAddressResource(ReadConstBuffer@pc=0x00000074(...
agc_driver_pointer_vsharp_fixed_table ....***Failed
(same chain)
80% tests passed, 3 tests failed out of 15
Previous findings
I can't list them one by one because the earlier review text is not available. Instead I checked the points raised by other reviewers on this thread:
- The guard against
main'sUnwrapTableReadpath (adriadam10): the guard is atcore/shader/recompiler/Optimization/src/ResourceTracker.cpp:1201. It runs after the hop walk, and the merged path is taken only whenUnwrapTableReadreturns null. For a pointer-keyed column, the materializer stores each record's pointer before it followspointerHops, and the SPIR-V lookup uses that same record-level pointer (parentPointer). The two sides agree, so allowing hops there is consistent. - A fixed offset under a runtime V#: it still refuses, at
ResourceTracker.cpp:860(if (fixed) return false;). - The refusal pins in the test policy (oneandonlydean, MarcZX10): none of the tests in the diff assert
not a valid runtime valueany more. FormatVersion: 67, abovemain's 52.
New findings
Blocking
None.
Non-blocking
None.
Not verified
- No run on non-lavapipe hardware here. The NVIDIA RTX 2000 Ada and AMD RX 6300 runs at earlier heads and at this head (AMD) are reported by the contributor bots, not reproduced.
- The title results (Gran Turismo 7 replay, Marvel's Spider-Man 2) are author- and tester-reported. I did not launch any title.
- Measured against
main, this PR's diff also carries the still-open #7223, #7395 and #8939. Whether to land the combined branch or the parents first is a maintainer decision, discussed in the thread. My verdict covers the merged tree as a whole.
✅ NVIDIA GPU test: passedPR head
Unstable on main (3, these also failed in recent main runs on this machine; not counted against this PR)Failing on main too (3, not counted against this PR)Validated but not compared (2, not in the main baseline's validation pass)Validation IDs already present on main (4 IDs in 527 tests)Skipped (47)ReproduceAutomated build and test on a contributor's NVIDIA machine; it does not replace upstream CI. A new comment is posted for each new push. Full logs. |
boykopovar#7223 has merged. The conflicts are this branch's additions on top of it: its tests in the image-table test lists, pointerKeyed in the image-table column and its equality check, the plan encoder's field count and list version, and FormatVersion 63. agc_shader_memory_tests.cmake merged without a conflict but registered agc_shader_nested_snapshot_retry twice: boykopovar#7223's block after agc_shader_descriptor_phis and this branch's before it. The merge keeps this branch's block, which adds agc_shader_nested_sampler_snapshot_retry, at boykopovar#7223's place.
e94fb3f is boykopovar#7395 with its merge of main after boykopovar#7223. The two conflicts are this branch's own changes over boykopovar#7395: FormatVersion 66, and its wording of the pointer-keyed image-table debt entry.
4769d4a is boykopovar#8939 with boykopovar#7395's merge of main after boykopovar#7223. The one conflict is this branch's FormatVersion 67.
✅ NVIDIA GPU test: passedPR head
Unstable on main (2, these also failed in recent main runs on this machine; not counted against this PR)Failing on main too (3, not counted against this PR)Validated but not compared (1, not in the main baseline's validation pass)Validation IDs already present on main (13 IDs in 551 tests)Skipped (50)ReproduceAutomated build and test on a contributor's NVIDIA machine; it does not replace upstream CI. A new comment is posted for each new push. Full logs. |
✅ AMD GPU test: passedPR head
Unstable on main (7, these also failed in recent main runs on this machine; not counted against this PR)Failing on main too (11, not counted against this PR)Validated but not compared (84, not in the main baseline's validation pass)Validation IDs already present on main (8 IDs in 780 tests)Skipped (62)ReproduceAutomated build and test on a contributor's AMD machine; it does not replace upstream CI. A new comment is posted for each new push. Full logs. |
…sharp-reuse 6e403b4 is boykopovar#9457 with the stack's merges of boykopovar#7395's main merge after boykopovar#7223. FormatVersion stays this branch's 71. In the debt file, boykopovar#7395 adds a sentence on nested children's registered views to "Nested image tables", which this branch rewrites. The entry keeps this branch's wording, and the sentence moves into its own entry after it, since both together are over the debt files' 1000 characters.
6e403b4 is boykopovar#9457 with the stack's merges of boykopovar#7395's main merge after boykopovar#7223. The conflicts are this branch's own: FormatVersion 70 and its pointer-keyed chase debt entry.
What
Two shapes from #6191's family that the planner still refuses on #8939. Each gets its own commit and test.
1. Pointer hops after a pointer-keyed record pointer (Gran Turismo 7 (PPSA01317), frankea on #6191, comment).
The chain: 28 of the World Map's 29 refused compute shaders read a record (an SRT V#, a
readfirstlanekey in a waterfall loop) whose dwords 2-3 are a pointer P1. P1's words are a Phi of the record read under several keys and aBallotlane-mask word. ThenP2 = [P1 + 0]and the T# at[P2 + 0x340]:Why it refuses:
TryMakeIndirectColumnrefuses any pointer hop once the record pointer is merged:if (!hops.empty() && (buffer || merged)) return false;.What the steps after it already do for a pointer-keyed column: the snapshot stores each record's pointer before it applies
pointerHops. The shader looks the T# up by the record-level pointer (parentPointer).ShaderDiskCachealready serializes and accepts hops on such columns.The change: the guard now refuses hops only for buffer columns.
2. A T# at a fixed offset of a pointer-loaded V# (Marvel's Spider-Man 2 (PPSA03016), hugodearaujo on #8939, comment).
The chain: a record keyed by
readfirstlane << 4, dwords 2-3 a pointer, a V# loaded at that pointer plus an immediate, and the T# read at a fixed offset of that V#'s buffer, with no second key:Why it refuses:
TryMakeTableColumnrefused it, becauseMatchAffineOffsetfails on an immediate offset.The change: hugodearaujo's change, kept as their commit. A fixed offset under a pointer-loaded V# becomes a one-key child of the nested path: key 0, stride the descriptor size, addend the immediate. A fixed offset under a runtime V# still refuses, as before.
Not in this PR:
0x120aed7f00, a table V# carried around a loop that callees overwrite). It looks like the shape fix(shader): split descriptor webs whose paths fold or hold invalid arms #8077 handles.Overlap:
TryMakeIndirectColumnwhen every arm is the same table read. The shapes here have arms under different keys and aBallotword, which fix(shader): resolve table column pointers through Phi nodes #7880 leaves refused. The two compose: an equivalent-arm Phi can take fix(shader): resolve table column pointers through Phi nodes #7880's plain column, and the rest the pointer-keyed one. The textual overlap is in feat(shader): read samplers through nested and pointer-keyed descriptor tables #7395's and fix(shader): take lane-mask arms and a merged high word in a pointer-keyed record pointer #8939's lines, which this PR stacks on.mainis at 56 since feat(shader): resolve nested image tables through runtime pointers #7223. Ours take one number each: feat(shader): raise the image limit to 128 and name the counts in its refusals #10489 57, feat(agc): look up table images at run time through a device image table on the GPU heap (APS5_GPU_PATH) #7642 62, feat(shader): read samplers through nested and pointer-keyed descriptor tables #7395 63, fix(shader): take lane-mask arms and a merged high word in a pointer-keyed record pointer #8939 66, fix(shader): follow pointer hops and fixed-offset V# reads behind a record pointer #9457 67, fix(shader): follow a conditional pointer chase through a V# behind a pointer-keyed record pointer #9633 70, fix(shader): plan several T#s read through one pointer-loaded V#, keeping the V# real for their other uses #9790 71, fix(shader): read a chased pointer's high word at its own offset #9749 72 and fix(shader): index a pointer-loaded V#'s T# array by a word read from the same buffer #9969 73. The other open PRs seen changing it hold 51 (fix(agc): preserve proven base formatted buffer read extents #14944), 53 (fix(shader): serve ds_ordered_count in wave launch order #12944), 56 (perf(agc): GPU descriptor heap on VK_EXT_descriptor_heap (APS5_GPU_HEAP) #9508, the same asmain), 65 (perf(agc): bound instance-indexed guest buffers by the draw's instance range #14032), 68 (fix(shader): narrow a goto junction Phi to the arm its branch allows #14636), 69 (feat(shader): flatten oversized 1D image arrays to 2D #14871) and 74 (fix(shader): skip a bit-field low word in a pointer-keyed table's Phi #14853). fix(shader): follow a conditional pointer chase through a V# behind a pointer-keyed record pointer #9633, fix(shader): read a chased pointer's high word at its own offset #9749, fix(shader): plan several T#s read through one pointer-loaded V#, keeping the V# real for their other uses #9790 and fix(shader): index a pointer-loaded V#'s T# array by a word read from the same buffer #9969 stack on this PR, above its 67. Whichever lands second on a number takes the next free one.Tested
tests/execution/ImageTable.cpp(lavapipe, Linux, CI's flags):agc_driver_pointer_hop_table: Gran Turismo 7's shape, aBallot-merged P1, a hop at +0 and the T# at +0x340, across four key groups. It checks every lane's color. The constant arm and theBallotarm each fault outside the snapshot. A re-pointed link block is followed without a recompile.GetImageResource dword 0 is not a valid runtime value; chain: LoadAddressU32@pc=0x000000b4(GetAddressResource(LoadAddressU32@pc=0x000000a8(GetAddressResource(Phi(Immediate, Phi(ReadConstBuffer@pc=0x00000074(...), CompositeExtractU32x4(Ballot(LogicalAnd), Immediate))), ...agc_driver_pointer_vsharp_fixed_tableandagc_driver_pointer_vsharp_fixed_offset_table: Spider-Man 2's shape, with the T# at offsets 0 and 0x40. A moved record pointer and a moved V# are both followed without a recompile.GetImageResource dword 0 is not a valid runtime value; chain: ReadConstBuffer@pc=0x0000008c(GetBufferResource(LoadAddressU32@pc=0x00000080(GetAddressResource(ReadConstBuffer@pc=0x00000074(...image_table|pointer(23 tests) ×5 and the disk-cache and ShaderMemory tests (10) pass. The full CI ctest gives 1834/1838; the 4 failures areagc_driver_pipelined_fill(a flake on main too) and 3 IPv6 socket tests the machine can't run. Registration and conventions pass.FormatVersion, 67 (see Tested), so a cache written by fix(shader): take lane-mask arms and a merged high word in a pointer-keyed record pointer #8939's recompiler isn't read as this one's. Refusals are never stored, no serialized field changes, and the cache's source version hashesResourceTracker.cpp.precise_wait(libc, Linux), which also failed on both sides in fix(agc): let draw relocation aliases name a cached key, not hold its entry #9396's runs, andguest_raise_in_system_call(libkernel, Windows), a 30 s timeout seen in other runs on that runner.maind6eafa5 (clean).668118771and0843cca39, tests kept), the 3 new ctests fail on both GPUs with the chains above. The other 13nested_/pointer_tests pass.agc_driver_(nested_|pointer_)tests pass 3 of 3 on each GPU, none skipped, andimage_table|pointer|disk_cache|shader_memory|sampler_table(27 tests) passes 3 of 3 on each.^agcsuite on the 3070 (877 tests, withoutdisplay_buffer_dcc,driver_flipandlds_atomics64): 874 pass and 1 skips. The 3 failures,agc_driver_sample_order,_grid_referenceand_recipe_depth_locations, fail the same way onmainon that card.maincc00785 merged in (clean; the PR's own diff is unchanged), on GitHub's runners (run):nested_/pointer_tests and the disk-cache tests pass 10 of 10, none skipped. libkernel's suite passes. libc's one failure,precise_wait, fails the same way withmain's implementation.check_conventions.pypasses on the merged head.mainagainst this head (run): one GitHub Linux runner, Ubuntu 24.04.5, llvmpipe (Mesa 25.2.8, LLVM 20.1.2),ANYPS5_REQUIRE_VULKAN=1,ANYPS5_NO_SHADER_CACHE=1andVK_LAYER_KHRONOS_validation. This head's arm ran 3 times, its 20 tests passing each time, andmain's once, its 4 tests passing; none skipped or failed.main, so its arm runs the image-table tests it has,agc_driver_image_table_vouched_lookupsandagc_driver_image_table_vouch_queued_draws, with the disk-cache tests. This head's arm runs those and the 16.VUID-VkDeviceCreateInfo-pNext-pNext, and this head adds noVUID-message.main0c6a5bd with fix(agc): resolve indexed indirect draws on a queue that never set INDEX_BUFFER_SIZE #9424.ReadConstBuffer@pc=0x8560, at 142 s and 146 s. With fix(shader): take lane-mask arms and a merged high word in a pointer-keyed record pointer #8939 (a7d1e62) added it stops there too, at 137 s in both runs.ReadConstBuffer@pc=0x8fa0overLoadAddressU32@pc=0x8f54.agc_shader_replayof the request that stopped at 0x8560 in a fix(shader): take lane-mask arms and a merged high word in a pointer-keyed record pointer #8939 run refuses at 0x8fa0 as well.main, because the merged head doesn't get that far on this title: since fix(libs): libs funcs abi debt 2026 10 20 #9137 it throws in the title's first 40 s onsceSystemServiceParamGetInt(parameter 100, then 208 and 210). The PR's own diff is the same in both heads.main0db47b2. The only conflict wasShaderDiskCache.hpp'sFormatVersionline:mainmoved to 45 (fix(shader): normalize offset perspective barycentrics after interpolation #7831), and this branch keeps its 46. On GitHub's runners (run), the pointer, nested, image-table and disk-cache sets (25 tests) pass 10 runs in a row on Linux. On Windows the set has 27, with two Windows-only disk-cache tests: they build, 5 pass 10 runs in a row, and the other 22, which need a Vulkan device, skip. The libc and libkernel suites pass on both, run withAPS5_SKIP_TIMING_TESTS=1, which relaxesprecise_wait's median bounds on GitHub's hosted runners. An earlier run linked here didn't run this set, so it's replaced.agc_shader_replay --preparewithANYPS5_NO_SHADER_CACHE=1on the requests the driver dumped at use, RTX 4090, Windows 11. Replay only, on their GT7 integration branch (main513ca7e with the GT7 pull requests in Gran Turismo 7 (PPSA01317) #4697's list and local diagnostics), without and with fix(shader): index a pointer-loaded V#'s T# array by a word read from the same buffer #9969 at 7588a53, which carries this PR at 7f3a25e with fix(shader): plan several T#s read through one pointer-loaded V#, keeping the V# real for their other uses #9790, fix(shader): take lane-mask arms and a merged high word in a pointer-keyed record pointer #8939, feat(shader): read samplers through nested and pointer-keyed descriptor tables #7395 and feat(shader): resolve nested image tables through runtime pointers #7223.Ballotword with arms that are the pointer loaded at 0x20ec, so on some edges the second hop starts from the first hop's result. This PR doesn't plan that shape.0x120aed7f00is unchanged (0x19a0 behind 0x198c), the shader this PR leaves out.main379b1dc). It's clean, and this PR's own diff is unchanged. The planner behaviour changes underneath it: It brings the planner changes of feat(shader): read samplers through nested and pointer-keyed descriptor tables #7395's and fix(shader): take lane-mask arms and a merged high word in a pointer-keyed record pointer #8939's merges: a record pointer counts as merged only when its Phi isn't a single record read; an unmerged pointer's low word is unwrapped as fix(shader): resolve table column pointers through Phi nodes #7880 does, and refused when it isn't a table read; and fix(shader): take lane-mask arms and a merged high word in a pointer-keyed record pointer #8939's new commit refuses a pointer-keyed Phi edge whose two words are both immediates.agc_shader_bindless,agc_shader_memoryand the^agc_driver_pointer_,^agc_driver_nested_,^agc_driver_image_tableand^agc_shader_disk_cachetests. Linux: 27 run, 27 pass, 0 skip, 0 fail. Windows: 29 run, 7 pass, 22 skip (Vulkan device tests; the runner has none), 0 fail.APS5_SKIP_TIMING_TESTS=1, which relaxesprecise_wait's median bounds on GitHub's hosted runners.mainc9b2660). Clean:FormatVersionfollows feat(shader): read samplers through nested and pointer-keyed descriptor tables #7395's 50, and this PR's own diff is unchanged. On GitHub's runners, 10 runs (run) of the pointer, nested, image-table and disk-cache sets (agc_shader_bindless,agc_shader_memory,^agc_driver_pointer_,^agc_driver_nested_,^agc_driver_image_table,^agc_shader_disk_cache): Linux: 27 run, 27 pass, 0 skip, 0 fail. Windows: 29 run, 7 pass, 22 skip (no Vulkan device), 0 fail. The libc and libkernel suites pass on both, run withAPS5_SKIP_TIMING_TESTS=1, which relaxesprecise_wait's median bounds on GitHub's hosted runners.mainc8d34aa). Clean:FormatVersionfollows feat(shader): read samplers through nested and pointer-keyed descriptor tables #7395's 50, and this PR's own diff is unchanged: the merge brings in exactly what feat(shader): read samplers through nested and pointer-keyed descriptor tables #7395's merge did (249 files). On GitHub's runners, 10 runs (run) of the pointer, nested, image-table and disk-cache sets (agc_shader_bindless,agc_shader_memory,^agc_driver_pointer_,^agc_driver_nested_,^agc_driver_image_table,^agc_shader_disk_cache): Linux: 27 run, 27 pass, 0 skip, 0 fail. Windows: 29 run, 7 pass, 22 skip (no Vulkan device), 0 fail. The libc and libkernel suites pass on both (143 and 206 tests on Linux, 170 and 222 on Windows), run withAPS5_SKIP_TIMING_TESTS=1, which relaxesprecise_wait's median bounds on GitHub's hosted runners.mainaeff26b, WinLibs GCC 15.2.0, Release,ANYPS5_REQUIRE_VULKAN=1 ANYPS5_NO_SHADER_CACHE=1, no validation layer.pointer_andnested_table tests,image_table,vouch,disk_cacheand theagc_shader_tests, 66 entries, pass on both GPUs.ResourceTracker.cpphunks of 6681187 and 0843cca reverted,agc_driver_pointer_hop_table,agc_driver_pointer_vsharp_fixed_tableand_fixed_offset_tablefail on both GPUs, the same three as in jotitadev's RTX 3070 control.agc_entries, the same ones fail with and without the stack.main0cd07dc (run).main0cd07dc. One conflict, inTryMakeIndirectColumn(ResourceTracker.cpp): mrfelek's fix(shader): plan an image table for a T# read at a first-lane offset #10228 lets a non-address offset that isn't affine or masked match as a first-lane offset (MatchFirstLaneOffset), on the line where this PR's fixed-offset case (hugodearaujo's 0843cca) branches off. The merge keeps both: an immediate offset on a pointer-loaded V# takes the fixed path first, and otherwise the affine, masked and then first-lane matches run as onmain. This PR's changed lines are the same.agc_shader_memorycarries fix(shader): plan an image table for a T# read at a first-lane offset #10228's first-lane cases) ran 10 times with no failure. Linux: 10 run, 10 pass, 0 skip, 0 fail. Windows: 12 run, 6 pass, 6 skip (the Vulkan device tests), 0 fail.exec_arguments,guest_timed_join_import_libkernel_sysandguest_timed_join_import_libkernel_webfail at their setup in the verify's Windows build (FileNotFoundErrorstarting the title, or copying the libraries they load), and pass inmain's own Windows job at 1829def (job). The suites ran withAPS5_SKIP_TIMING_TESTS=1, which relaxesprecise_wait's median bounds on GitHub's hosted runners.exec_arguments,guest_timed_join_import_libkernel_sysandguest_timed_join_import_libkernel_webfail at their setup in the verify's Windows build (FileNotFoundErrorstarting the title, or copying the libraries they load), and pass inmain's own Windows job at 1829def (job). The suites ran withAPS5_SKIP_TIMING_TESTS=1, which relaxesprecise_wait's median bounds on GitHub's hosted runners.main38ccd50 and with it fix(agc): sample cube descriptors with fewer than six slices as six faces #11507'sFormatVersion49 (run). Clean:FormatVersionstays 53 (see What), and this PR's diff over fix(shader): take lane-mask arms and a merged high word in a pointer-keyed record pointer #8939 is the same. The hop, fixed-offset, vouch, sample-order and nested-sampler tests with the disk-cache, bindless and shader-memory tests and fix(agc): sample cube descriptors with fewer than six slices as six faces #11507'sagc_driver_image_sample_short_cuberan 10 times with no failure. Linux: 12 run, 12 pass, 0 skip, 0 fail. Windows: 14 run, 6 pass, 8 skip (the Vulkan device tests), 0 fail. Suites: libc and libkernel pass on Linux (166 and 265). On Windows libc passes (194), and libkernel passes 284 of 287:exec_arguments,guest_timed_join_import_libkernel_sysandguest_timed_join_import_libkernel_webfail at their setup in the verify's Windows build (FileNotFoundErrorstarting the title, or copying the libraries they load), withmain's code too, and pass inmain's own Windows job at 1829def (job). The suites ran withAPS5_SKIP_TIMING_TESTS=1, which relaxesprecise_wait's median bounds on GitHub's hosted runners.agc_driver_nested_image_table's two checks that a valid shader is refused (a V# with another buffer consumer and a T# with another consumer), feat(shader): read samplers through nested and pointer-keyed descriptor tables #7395's merge of feat(shader): resolve nested image tables through runtime pointers #7223's 0dbf547 (yabanana's merge ofmainf7e84c4) and fix(shader): take lane-mask arms and a merged high word in a pointer-keyed record pointer #8939's format commit. Clean.agc_shader_bindlessandagc_shader_memoryran 10 times with no failure. Linux: 27 run, 27 pass, 0 skip, 0 fail. Windows: 29 run, 8 pass, 21 skip (the Vulkan device tests; the Windows runner has no Vulkan device), 0 fail. The libc and libkernel suites run 191 and 291 tests on Linux and 220 and 314 on Windows, with 0 failed. They ran withAPS5_SKIP_TIMING_TESTS=1, which relaxesprecise_wait's median bounds on GitHub's hosted runners.APS5_SKIP_TIMING_TESTS=1, which relaxesprecise_wait's median bounds on GitHub's hosted runners.main3741ca9, 2,538 of 3,121 tests selected.main, and 2 are unstable onmain.VK_LAYER_KHRONOS_validation, over 945 tests on the GPU, there are no new validation IDs againstmain. 15 of the nested and pointer table tests ran with the layer but aren't inmain's baseline, so they weren't compared.mainb08c539 (run).FormatVersionline, which the next commit replaces, andagc_driver_image_table_tests.cmake, where this PR's registrations already include fix(shader): take lane-mask arms and a merged high word in a pointer-keyed record pointer #8939's.agc_shader_bindlessandagc_shader_memoryran 10 times with no failure. Linux: 29 run, 29 pass, 0 skip, 0 fail. Windows: 31 run, 10 pass, 21 skip, 0 fail; the 21 skip because the runner has no Vulkan device. The libc and libkernel suites run 199 and 308 tests on Linux and 226 and 330 on Windows, with 0 failed. The suites ran withAPS5_SKIP_TIMING_TESTS=1, which relaxesprecise_wait's median bounds on GitHub's hosted runners.VK_LAYER_KHRONOS_validationon GitHub's Linux runner (run),mainb08c539 against this head, for the same tests. The loader inserted the layer 8 times onmainand 23 with this head. The only VUID in either arm isVUID-VkDeviceCreateInfo-pNext-pNext, for a device struct (VkPhysicalDeviceMaintenance8FeaturesKHR) newer than that layer version, so this head adds none.agc_driver_image_tablefails in that mode in both arms, because the mode treats thatmainmessage as a failure.main88e804b (run). Clean:FormatVersionstays 67, and this PR's own diff is unchanged. The shader-memory, nested, pointer, image-table, disk-cache and bindless tests, with fix(shader): split scalar-address descriptor phis #7694'sagc_shader_descriptor_phis, pass 10 runs in a row. Linux: 30 run, 30 pass, 0 skip, 0 fail. Windows: 32 run, 11 pass, 21 skip, 0 fail. Suites: libc and libkernel pass on Linux (210 and 310) and on Windows (237 and 331). The suites ran withAPS5_SKIP_TIMING_TESTS=1, which relaxesprecise_wait's median bounds on GitHub's hosted runners. TechLevelZero's NVIDIA bot ran this head merged ontomain88e804b on an RTX 2000 Ada (report): 2,569 passed, 4 failed, none new (3 also fail onmain, 1 unstable onmain), 45 skipped, with no new validation IDs (988 tests on the GPU).main4f64f81 for feat(agc): sample 1D arrays past maxImageArrayLayers as rows of a 2D image #12246 (run). Clean:FormatVersionstays 67, and this PR's own diff is unchanged since 04d09ee. TheResourceMaterializer.cppresolution, with feat(agc): sample 1D arrays past maxImageArrayLayers as rows of a 2D image #12246's view loop moved back intoSnapshot, comes from feat(shader): read samplers through nested and pointer-keyed descriptor tables #7395's merge (see feat(shader): read samplers through nested and pointer-keyed descriptor tables #7395). The shader-memory, nested, pointer, image-table, disk-cache and bindless tests, with fix(shader): split scalar-address descriptor phis #7694'sagc_shader_descriptor_phis, pass 10 runs in a row. Linux: 30 run, 30 pass, 0 skip, 0 fail. Windows: 32 run, 11 pass, 21 skip (no Vulkan device), 0 fail. Suites: libc and libkernel pass on Linux (217 and 318) and on Windows (244 and 339). The suites ran withAPS5_SKIP_TIMING_TESTS=1, which relaxesprecise_wait's median bounds on GitHub's hosted runners.main4f41f4c (×10, the PR's own tests ×10).ShaderDiskCache.hpp'sFormatVersion, wheremainis now at 52 (feat(shader): raise the sampler and sampled-pair limits past the 32-bit sampler masks #10000) and this PR keeps its 67; anddocs/dev/debt/shader.md, where this PR's entries andmain's new entries are adjacent and both stay. This PR's own lines are unchanged apart from theFormatVersionline's old value.agc_driver_image_table,agc_driver_many_direct_samplersand every test matching^agc_shader_memory,^agc_shader_disk_cache,^agc_shader_sampler_limits,^agc_shader_nestedor^agc_shader_table. Linux: 11 run, 11 pass, 0 skip, 0 fail. Windows: 13 run, 11 pass, 2 skip (no Vulkan device), 0 fail. The libc and libkernel suites run 300 and 322 tests on Linux and 327 and 342 on Windows, with 0 failed. The suites ran withAPS5_SKIP_TIMING_TESTS=1, which relaxesprecise_wait's median bounds on GitHub's hosted runners.^agc_driver_pointer_and^agc_driver_nested_test, the image-table tests in this PR's diff overmain, which the first run's names left out. Linux: 15 run, 15 pass, 0 skip, 0 fail. Windows: 15 run, 0 pass, 15 skip (no Vulkan device), 0 fail.mainc2eafe4 with yabanana's feat(shader): resolve nested image tables through runtime pointers #7223 through feat(shader): read samplers through nested and pointer-keyed descriptor tables #7395 (×10).ShaderDiskCache.hpp'sFormatVersion, which stays 67 (mainis at 56 since feat(shader): resolve nested image tables through runtime pointers #7223). This PR's own lines are unchanged apart from theFormatVersionline's old value.agc_driver_many_direct_samplersand every test matching^agc_driver_pointer_,^agc_driver_nested_,^agc_shader_nested_,^agc_driver_image_table,^agc_shader_memory,^agc_shader_disk_cacheor^agc_shader_sampler_limits, which takes in every test in this PR's diff overmain. Linux: 30 run, 30 pass, 0 skip, 0 fail. Windows: 32 run, 10 pass, 22 skip (no Vulkan device), 0 fail. The libc and libkernel suites run 301 and 325 tests on Linux and 331 and 343 on Windows, with 0 failed. The suites ran withAPS5_SKIP_TIMING_TESTS=1, which relaxesprecise_wait's median bounds on GitHub's hosted runners.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)ReadConstBuffer@pc=0x8560(hugodearaujo's run above); the next stop, 0x8f54/0x8fa0, needs a follow-up. Ratchet & Clank: Rift Apart (PPSA01474, Ratchet & Clank: Rift Apart (PPSA01474) on Linux #2172) gets past 0x10b84 with fix(shader): follow a conditional pointer chase through a V# behind a pointer-keyed record pointer #9633 on top, which builds on this PR's hop and fixed-offset handling. Gran Turismo 7's shape is untested on that titleRelated: #6191