Skip to content

feat(shader): read samplers through nested and pointer-keyed descriptor tables - #7395

Open
EagleBearerYS wants to merge 30 commits into
boykopovar:mainfrom
EagleBearerYS:feat/shader-nested-sampler-tables
Open

EagleBearerYS wants to merge 30 commits into
boykopovar:mainfrom
EagleBearerYS:feat/shader-nested-sampler-tables

Conversation

@EagleBearerYS

@EagleBearerYS EagleBearerYS commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor

What

#7223 has merged. With #7223, Marvel's Wolverine (PPSA03671) and Ratchet & Clank: Rift Apart (PPSA01474) stop on the sampler half of the descriptor chain that #7223 resolves for images (#6191):

#7223 resolves record → pointer → V# → T# and leaves samplers refused. Its nested table representation, pointer dictionary and limits are what this PR builds on. The PR extends them to samplers and to a one-hop pointer whose low word is merged through a Phi.

This PR's first fix, fix(shader): refuse nested table entries whose words have other consumers (0df7d32), is now in #7223 (d132754, with its authorship). On #7223's earlier head, a nested child whose descriptor words another instruction also reads crashed lavapipe inside the shader. Four commits remain here:

  1. feat(shader): resolve S# reads through nested descriptor tables. This is the record → pointer → V# → S# chain of Marvel's Wolverine (PPSA03671)'s stop above (pc=0xbb28) and of the one at pc=0xb600. This PR plans the S# when it sits at a keyed offset of the V#. At pc=0xb600 it sits at a fixed offset, which this PR doesn't plan and fix(shader): follow pointer hops and fixed-offset V# reads behind a record pointer #9457 does (mrfelek's offline replay of fix(shader): index a pointer-loaded V#'s T# array by a word read from the same buffer #9969's head, comment). The pc=0xbb28 line doesn't show its S#'s offset.
  2. feat(shader): look up a Phi-merged record pointer to an S# or T#. This is Ratchet & Clank's shape: record → pointer → S# through an address, with the pointer's low word merged through a Phi.
    • A direct indirect column becomes pointer-keyed and reuses feat(shader): resolve nested image tables through runtime pointers #7223's sorted pointer dictionary.
    • A pointer the snapshot didn't capture faults as outside the snapshot, and a null pointer faults as unmapped. The same path serves T#s.
    • The disk-cache format goes from 42 to 43, and the image-table ABI from 3 to 4.
  3. fix(shader): accept a lane-mask word in a pointer-keyed record pointer. Ratchet & Clank: Rift Apart's next stop (ps54all, #6191): GetImageResource dword 0 is not a valid runtime value. A T# is read through a record pointer whose low word passes six levels of Phi, and one arm is a word of the waterfall loop's Ballot lane mask.
    • A pointer-keyed column now accepts such an arm as one that can't be a record pointer, as it does for constants. It also accepts copies of the record word read under other keys (same table, offset, stride and addend), since the lookup is by the pointer's value.
    • At run time, a pointer built from a lane mask faults as outside the snapshot.
    • This commit leaves the disk-cache format as it is: shaders that planned before plan the same way, and only ones refused before now plan.
  4. fix(shader): check the descriptor epoch for a lone nested sampler table (967f0db). A shader whose only table is a nested S# table now gets the same descriptor-epoch retry as images.
    • The cause: the tracker builds nested S# columns, whose heap source is itself a table column, but TableSnapshotter::Run() still widened hasIndirect for samplers only on column.indirect. Such a shader skipped the snapshot's own epoch check and retry, and relied on the whole-snapshot revalidation alone.
    • The fix: the sampler loop now uses the same test as the image loop.
    • What the old code missed: the per-attempt retry, the budget reset and the forced sync, so the severity is low-medium. It didn't produce a torn snapshot, and no title has shown it.

Ordering. This PR was stacked on #7223, which has merged. Its first three commits sit on #7223's 74700a0, and the branch then merges main a5939f1 (480c25a) and #7223's head, now 7f36e41 (94a16af). The fourth commit sits on top. With 4d820bd, a merge of main c2eafe4, which has #7223, this PR's diff over main shows only its own changes.

Tested

  • The restack (4122094, 9200c3a, f6fb8b6, on feat(shader): resolve nested image tables through runtime pointers #7223's 74700a0), Linux, lavapipe (LLVM 20.1.2), CI's configuration, a cloud worker:
    • each commit builds and passes its own tests;
    • at the head, the nested and pointer-Phi table tests, agc_shader_disk_cache, agc_shader_bindless and the rest of the image-table family (21 tests) pass 10 runs in a row;
    • the ^(agc|shader) tests pass, 838 of 838.
  • The restack merged with current main, as CI builds it (0863efb, main a07e985), on GitHub's runners (run): the nested and pointer-Phi table tests, agc_driver_image_table, agc_shader_disk_cache and agc_shader_bindless pass 5 runs in a row on Linux. On Windows the GPU ones skip and the rest pass, and the libc and libkernel suites pass on both.
  • The runs below are from the heads before the restack. The three commits' own changes are the same, apart from the conflict resolutions.
  • Merged with main 9caecfd (aed137c, the head), on GitHub's runners, at 3730bb8, the same merge with the same tree before the co-author line was added (run): on Linux the ^agc tests pass 3 runs in a row, 715 tests: 667 pass, 48 skip, 0 fail. The libc and libkernel suites pass on both runners. On Windows, of 714 ^agc tests 173 pass 3 runs in a row and 539 skip, since the runner has no Vulkan device; the only failures are agc_driver_pm4_replay_tool and agc_shader_replay_tool, which fail the same way on that runner for an unrelated branch (run).
  • GitHub's Linux (lavapipe, Mesa 25.2.8) and Windows runners (verify run):
    • agc_driver_nested_image_table, agc_driver_nested_sampler_table, agc_driver_pointer_phi_sampler_table, agc_shader_disk_cache and agc_shader_disk_cache_large_file pass 10 of 10 runs on both runners. Three of them skip on the Windows runner.
    • The libc and libkernel suites pass.
    • With feat(shader): resolve nested image tables through runtime pointers #7223's code the new tests don't build, so the red below is from the Linux run.
  • Linux, a run that mirrors CI's Linux job (Ubuntu 24.04, GCC 13.3, lavapipe Mesa 25.2.8 / LLVM 20.1.2): 1376 tests on this branch, with the same 5 IPv6 failures as on feat(shader): resolve nested image tables through runtime pointers #7223's head on that machine. No new failures or skips.
  • New tests, red on feat(shader): resolve nested image tables through runtime pointers #7223's head and green here:
    • agc_driver_nested_sampler_table: S# through record → pointer → V#. It covers independent keys, wave32 against wave64, an edited S#, unmapped and non-buffer parents, shared children, the refusal of an S# with another consumer, captured and uncaptured Phi pointers, the S# budget and the nested key budget. Red: GetSamplerResource dword 0 is not a valid runtime value.
    • agc_driver_pointer_phi_sampler_table: S# through a Phi-merged record pointer. It covers the direct control, captured and uncaptured Phi constants, a constant equal to another record's pointer, a null pointer, a non-buffer record table, an S# with another consumer, and a T# through the same path.
    • agc_driver_nested_image_table gains "a T# with another consumer" (refused). Red is a SIGSEGV on feat(shader): resolve nested image tables through runtime pointers #7223's head.
    • agc_shader_disk_cache round-trips both new plan shapes and rejects a malformed pointer-keyed column.
  • The fourth commit's tests (b91f050), agc_driver_pointer_phi_ballot_table and agc_driver_pointer_phi_copies_table: synthetic wave64 waterfall loops shaped like Ratchet & Clank: Rift Apart's chain, where the lane-mask pointer faults as outside the snapshot. On GitHub's runners (run) both fail in all 3 runs on Linux with the third commit's code (4a4db4b) and pass 10 of 10 with the fourth, with the other nested and pointer tests and agc_shader_disk_cache; the libc and libkernel suites pass. On Windows they skip without a Vulkan device and agc_shader_disk_cache passes. A run that mirrors CI's Linux job gives 1378 tests against 1376 on 4a4db4b, with only the two new tests changing.
  • Repeats: 10 of 10 for each.
  • Ratchet & Clank: Rift Apart (PPSA01474, 01.005.003), run by ps54all on Windows 11 with an NVIDIA GeForce RTX 3080 10 GB (driver 610.74), an i9-10850K, WinLibs GCC 15.2 and a Release build (comment). Their test branch (main 82f0c9a with perf(agc): draw finisher pipeline (APS5_DRAW_PIPELINE) #6946, fix(agc): skip a periodic pipeline cache save while a pipeline creation holds the cache #6958, fix(recompiler): give a dynamic-mip storage image a slot for every level #7238, feat(shader): resolve nested image tables through runtime pointers #7223, fix(recompiler): read lane spills back through relative-addressing window registers #6277, fix(shader): plan image tables through invariant descriptor phis #6417, feat(agc): link calls through the AGC FS table #6160 and fix(ampr): return EBUSY when a command does not fit and EPERM before a buffer is bound #7300) plus this PR's three commits, cold shader cache, one run:
    • the GetSamplerResource stop no longer occurs (0 hits);
    • the title then stops 236 s in, on another compute shader, at an image read whose record pointer goes through six levels of Phi before LoadAddressU32 (GetImageResource dword 0 is not a valid runtime value). That is the title's next stop. The fourth commit (b91f050) addresses that chain; Tamalero has since run the title with it (below).
  • Ratchet & Clank: Rift Apart (PPSA01474, 01.005.003), run by Tamalero on CachyOS (Linux 7.2) with an NVIDIA GeForce RTX 4090 (driver 615.78.08), GCC and a Release build (comment). This PR's head b91f050 against feat(shader): resolve nested image tables through runtime pointers #7223's head f454944 as the control, both on main 66702f1 (feat(shader): resolve nested image tables through runtime pointers #7223's base) with no local patches, fresh shader cache, one run each:
    • the control stops about 480 s in, at GetSamplerResource dword 0 (pc=0x6b74, 3 refusals);
    • with this PR there are no sampler refusals, and neither stop from Tamalero's earlier runs of feat(shader): resolve nested image tables through runtime pointers #7223 recurs: the S# at pc=0x6b74 and the T# at pc=0x7cbc;
    • the title then stops about 470 s in, on another compute shader, at GetImageResource dword 0 (pc=0x99ec, 3 refusals). Its record pointer goes through a deeper Phi nest, with a word of the Ballot lane mask ANDed into it (BitwiseAnd32), a shape the fourth commit doesn't cover. That is the title's next stop.
  • Ratchet & Clank: Rift Apart (PPSA01474), run by ps54all on Windows 11 with an NVIDIA GeForce RTX 3080 (driver 610.74), MinGW GCC 15.2.0 and a Release build (comment). Their test branch (main 82f0c9a with open PRs, already carrying this PR's earlier commits) plus the fourth commit (b91f050), one run each before and after:
    • the stop on compute shader 0x116bb5f500 (LoadAddressU32@pc=0x8fd4, six levels of Phi) no longer occurs;
    • the title then stops about 214 s in, on a black window, on compute shader 0x116bb67000 (GetImageResource dword 0 is not a valid runtime value, LoadAddressU32@pc=0x9a30): a seven-level Phi nest with a Ballot lane-mask word ANDed in and ReadFirstLane(SelectU32 …) arms. That is Tamalero's next stop (above) in a sibling shader: both chains read the record table at pc=0x1aa8, and the stop and the second buffer's reads sit 0x44 later than in Tamalero's (0x9a30, 0x908c and 0x900c against 0x99ec, 0x9048 and 0x8fc8).
  • Hardware test runs by Capmare at aed137c, the head before the merge of main 61d3d30: Rocky Linux 10.2, Release, BUILD_TESTING=ON, 735 graphics tests per GPU, no title (comment):
    • NVIDIA GeForce RTX 4070 SUPER (driver 615.71.09): all 735 pass, agc_driver_nested_sampler_table and agc_driver_pointer_phi_sampler_table among them;
    • AMD Radeon RX 7600 (RADV, Mesa 25.2.7) and llvmpipe (Mesa 25.2.7): both new sampler tests pass 3 of 3 runs. On the RX 7600, agc_pipeline_cache_file fails, which Capmare reports as unrelated;
    • Intel UHD 770 (ANV, Mesa 25.2.7): both new sampler tests fail 3 of 3 runs, each reading the other test's expected sampler result ("lane 0 is 0x3e800000, expected 0x427d0000" and the reverse). On ANV, workgroup 1 gets workgroup 0's sampler through the non-uniform sampler-array pick. Capmare reproduced it in a standalone Vulkan program with no AnyPS5 code (a compute stage with requiredSubgroupSize = 32, local_size_x = 32 and a sampler array of more than 2 elements indexed per workgroup), so it's an ANV issue, filed as Mesa issue 16622 and fixed by Mesa !37394, in Mesa 25.3.0 and later (comment) (comment, comment). The tests stay as they are. The existing nested image-table tests pass on all three GPUs.
  • Intel Arc on Windows, by @BKlaasWerkman (comment), in a run of fix(shader): index a pointer-loaded V#'s T# array by a word read from the same buffer #9969's stack, which carries this PR's commits: Intel Arc Graphics (Meteor Lake, driver 101.9150), Windows 11, with the Khronos validation layer. agc_driver_nested_sampler_table and agc_driver_pointer_phi_sampler_table fail with the same lines as on ANV. @BKlaasWerkman's rerun on the same Intel Arc, of this PR alone merged into main 938812d (comment), and fix(shader): index a pointer-loaded V#'s T# array by a word read from the same buffer #9969's head d01f290 merged into the same main (comment): both tests fail 3 of 3 by default and pass 3 of 3 with APS5_SPANNED_WAVE=1, which spans the program over two full 32-lane subgroups. That switch made both pass on ANV too (comment), so this points to the same cause as there. Xe-LPG is Gfx12 as well. Mesa 25.3's fix doesn't reach Intel's Windows driver (101.9150). On an NVIDIA GeForce RTX 3060 Ti (617.42) in the same run both pass, and neither GPU reports a new VUID- message.
  • Marvel's Wolverine (PPSA03671), by Capmare (comment): this PR at 59b319a (an earlier head) with no local patches, Rocky Linux 10.2, NVIDIA GeForce RTX 4070 SUPER (615.71.09), a cold shader cache, one run of about 9 minutes.
  • Merged with main 61d3d30 (ed4f148), on GitHub's runners (run): the ^agc tests pass on Linux (734, 0 failed, 49 skipped), and the suites' only failure is libc's precise_wait timing test. On Windows, where 551 of the 734 skip without Vulkan, the only failures are agc_driver_pm4_replay_tool and agc_shader_replay_tool (exit code 0xc0000139), which fail the same way on that runner for an unrelated branch (run).
  • Merged with main ff2fc57 (59b319a, the head), on GitHub's runners (run): the ^agc and ^shader tests pass on Linux (739, 0 failed, 49 skipped), and the suites' only failure is again libc's precise_wait timing test. On Windows, where 551 of the 738 skip without Vulkan, the only failures are again agc_driver_pm4_replay_tool and agc_shader_replay_tool (exit code 0xc0000139).
  • 4661f4b, a merge of main 0db47b2. The only conflict was ShaderDiskCache.hpp's FormatVersion line: main moved 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 (16 tests) pass 10 runs in a row on Linux. On Windows the set has 18, with two Windows-only disk-cache tests: they build, 5 pass 10 runs in a row, and the other 13, which need a Vulkan device, skip. The libc and libkernel suites pass on both, run with APS5_SKIP_TIMING_TESTS=1, which relaxes precise_wait's median bounds on GitHub's hosted runners. An earlier run linked here didn't run this set, so it's replaced.
  • Not tested: a title run past Marvel's Wolverine (PPSA03671)'s texture rebuilds above.
  • 319fa1f, a merge of main 379b1dc. main's fix(shader): resolve table column pointers through Phi nodes #7880 changed the indirect-column builder this PR also changes: it reads a record pointer's words through UnwrapTableRead and checks that the offset is available where the handle is (AvailableAt). The conflicts in ResourceTracker.cpp keep both: this PR's record-origin walk, and fix(shader): resolve table column pointers through Phi nodes #7880's unwrap of the high word and its dominance check. FormatVersion goes to 47, above main's 46.
    • The planner behaviour changes with the merge: a record pointer now counts as merged only when its Phi isn't a single record read. A Phi that fix(shader): resolve table column pointers through Phi nodes #7880 reduces to one table read (its Phi-behind-hops case) takes the unmerged path and plans, where this PR's hop guard refused it. Without that change the merge fails fix(shader): resolve table column pointers through Phi nodes #7880's agc_shader_memory and agc_shader_bindless on both runners with GetImageResource dword 0 is not a valid runtime value (run).
    • Focused, ×10 (run): agc_shader_bindless, agc_shader_memory and the ^agc_driver_pointer_, ^agc_driver_nested_, ^agc_driver_image_table and ^agc_shader_disk_cache tests. Linux: 18 run, 18 pass, 0 skip, 0 fail. Windows: 20 run, 7 pass, 13 skip (Vulkan device tests; the runner has none), 0 fail.
    • The full ^agc set once (run): Linux 973 run, 908 pass, 64 skip, 1 fail; Windows 992 run, 272 pass, 718 skip, 2 fail. The failures are agc_driver_sgpr_pattern_fill_keys on Linux ("the dispatch completed 17 times without a pending write over the keys") and agc_driver_pipelined_metadata_pass and its _draw_pipeline variant on Windows (vkCreateInstance returns -9 on the device-less runner). main 379b1dc shows the same three with the same messages (run); agc_driver_sgpr_pattern_fill_keys failed 1 of 4 runs there.
    • The libc and libkernel suites pass on both runners, run with APS5_SKIP_TIMING_TESTS=1, which relaxes precise_wait's median bounds on GitHub's hosted runners. It merges cleanly with current main.
  • 2525821, a merge of main c9b2660. main's fix(shader): answer image_get_resinfo on any T# dimension #7550 took FormatVersion 47, the number this branch had, and git merged the two edits silently, so the merge moves this PR to 50. This PR's own diff is otherwise 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: 18 run, 18 pass, 0 skip, 0 fail. Windows: 20 run, 7 pass, 13 skip (no Vulkan device), 0 fail. The libc and libkernel suites pass on both, run with APS5_SKIP_TIMING_TESTS=1, which relaxes precise_wait's median bounds on GitHub's hosted runners.
  • 71741a7, a merge of feat(shader): resolve nested image tables through runtime pointers #7223's f1cc524 (yabanana's merge of main c8d34aa, which moves feat(shader): resolve nested image tables through runtime pointers #7223 to FormatVersion 48). Two conflicts, each resolved to this PR's side, which already holds the other side's content: FormatVersion stays 50, and in ResourceTracker.cpp the old one-argument PointerRecordOrigin line gives way to this PR's two-argument version and its helpers, at its one call site. The merge brings in exactly main's c9b2660 to c8d34aa changes (249 files, each the same as main's own), so 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: 18 run, 18 pass, 0 skip, 0 fail. Windows: 20 run, 7 pass, 13 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 with APS5_SKIP_TIMING_TESTS=1, which relaxes precise_wait's median bounds on GitHub's hosted runners.
  • 9343a17: 7808540, a merge of feat(shader): resolve nested image tables through runtime pointers #7223's 153400b, then a test-only commit (run).
    • The merge: yabanana's 153400b merges main 0d62324 into feat(shader): resolve nested image tables through runtime pointers #7223 and moves it to FormatVersion 49, above main's 48. That line was the one conflict, and it stays 50 here. This PR's own diff is unchanged.
    • 9343a17 drops agc_driver_nested_sampler_table's check that a V# with another buffer consumer is refused, one of the assertions @oneandonlydean listed on fix(shader): index a pointer-loaded V#'s T# array by a word read from the same buffer #9969, under the rule that tests don't assert that a shape the code doesn't support yet throws. The sampled results, sharing and budget checks stay.
    • The pointer, nested, image-table and disk-cache tests, with agc_pipeline_cache_file and agc_driver_sgpr_pattern_fill_keys, ran 10 times with no failure. Linux: 12 run, 11 pass, 1 skip (agc_pipeline_cache_file), 0 fail. Windows: 14 run, 6 pass, 8 skip (the seven Vulkan device tests, as the runner has no device, and agc_pipeline_cache_file), 0 fail.
    • Suites: libc and libkernel pass on Linux (158 and 217). On Windows libc passes (187), and libkernel has 4 failures of 239. guest_raise_exception failed after "address waking round 20: the handler did not run within 5 s", as main 9fc181d does in the same verify setup (run); that is libkernel (Windows): guest_raise_exception slowed about 3x and sometimes aborts at "address waking" since 540364a24 (#10666) #11813, and this PR doesn't touch libkernel. exec_arguments, guest_timed_join_import_libkernel_sys and guest_timed_join_import_libkernel_web fail at their setup in the verify's Windows build (FileNotFoundError starting the title, or copying the libraries they load), and pass in main's own Windows job at 1829def (job). The suites ran with APS5_SKIP_TIMING_TESTS=1, which relaxes precise_wait's median bounds on GitHub's hosted runners.
  • ca14648, a test-only commit (run). It drops agc_driver_nested_sampler_table's check that an S# with another consumer is refused, with the refused helper it was the last user of, under the rule that tests don't assert that a shape the code doesn't support yet throws. fix(shader): plan several T#s read through one pointer-loaded V#, keeping the V# real for their other uses #9790 plans that S# and checks its sampled result. The sampled results, sharing and budget checks stay. The pointer, nested, image-table and disk-cache tests with agc_pipeline_cache_file and agc_driver_sgpr_pattern_fill_keys ran 10 times with no failure. Linux: 12 run, 11 pass, 1 skip (agc_pipeline_cache_file), 0 fail. Windows: 14 run, 6 pass, 8 skip (the seven Vulkan device tests and agc_pipeline_cache_file), 0 fail. Suites: libc and libkernel pass on Linux (158 and 217). On Windows libc passes (187), and libkernel passes 236 of 239: exec_arguments, guest_timed_join_import_libkernel_sys and guest_timed_join_import_libkernel_web fail at their setup in the verify's Windows build (FileNotFoundError starting the title, or copying the libraries they load), and pass in main's own Windows job at 1829def (job). The suites ran with APS5_SKIP_TIMING_TESTS=1, which relaxes precise_wait's median bounds on GitHub's hosted runners.
  • ca5ba62, a merge of main 38ccd50 (run). main now has fix(agc): sample cube descriptors with fewer than six slices as six faces #11507 (hugodearaujo's short-cube sampling), which takes FormatVersion 49 (b9f4f65); that line was the one conflict, and this PR keeps its 50 (see Version bumps above). fix(agc): sample cube descriptors with fewer than six slices as six faces #11507 also adds an ImageResource field, sampledOnly, which ShaderDiskCache.cpp encodes next to this PR's fields without a conflict. This PR's diff over main is the same apart from the FormatVersion line's old value. The pointer, nested, image-table and disk-cache tests with agc_pipeline_cache_file, agc_driver_sgpr_pattern_fill_keys and fix(agc): sample cube descriptors with fewer than six slices as six faces #11507's agc_driver_image_sample_short_cube ran 10 times with no failure. Linux: 13 run, 12 pass, 1 skip (agc_pipeline_cache_file), 0 fail. Windows: 15 run, 6 pass, 9 skip (the eight Vulkan device tests and agc_pipeline_cache_file), 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_sys and guest_timed_join_import_libkernel_web fail at their setup in the verify's Windows build (FileNotFoundError starting the title, or copying the libraries they load), with main's code too, and pass in main's own Windows job at 1829def (job). The suites ran with APS5_SKIP_TIMING_TESTS=1, which relaxes precise_wait's median bounds on GitHub's hosted runners.
  • e04a705: d908758, a test-only commit, 86d97d9, a merge of feat(shader): resolve nested image tables through runtime pointers #7223's 0dbf547, and e04a705, the format commit (run).
  • 4769d5a, a test-wording commit (run), for the last part of oneandonlydean's item 1 and XairRrR's first non-blocking point. The nested image table and nested sampler table tests no longer check refusals, so their success lines no longer say "and refusals". The nested image table line (ImageTable.cpp:1635) is feat(shader): resolve nested image tables through runtime pointers #7223's own, from Daniele Giovane's ad44bc4; it's in this branch through the merges of feat(shader): resolve nested image tables through runtime pointers #7223, and this commit changes it here. The image-table, nested, pointer, disk-cache, bindless and shader-memory tests ran 10 times with no failure. Linux: 19 run, 19 pass, 0 skip, 0 fail. Windows: 21 run, 8 pass, 13 skip, 0 fail; the 13 skip because the runner has no Vulkan device. The libc and libkernel suites run 191 and 291 tests on Linux and 220 and 314 on Windows, with 0 failed. The suites ran with APS5_SKIP_TIMING_TESTS=1, which relaxes precise_wait's median bounds on GitHub's hosted runners.
  • f4781de: 480c25a, a merge of main a5939f1, 94a16af, a merge of feat(shader): resolve nested image tables through runtime pointers #7223's 7f36e41, and f4781de, the format commit (run).
    • 480c25a: one conflict, FormatVersion. This PR's own diff is unchanged except that its removed line now reads main's 50.
    • 94a16af: clean.
    • f4781de: moves this PR to 63 (Version bumps above).
    • ×10: the image-table, nested, pointer, disk-cache and nested-snapshot tests.
  • 967f0db, the lone nested sampler table's epoch check.
    • The test: agc_shader_nested_sampler_snapshot_retry runs the nested retry check with an S# child column and a sampler as the only table. Its registration gives it libc's directory on PATH on Windows, in the same commit.
    • Red, on f4781de, 3 of 3 runs on both runners: "nested retry: expected inner retry and outer revalidation". Green: 10 of 10 (run).
    • ×10 at this head (run):
      • Linux: 32 run, 32 pass, 0 skip, 0 fail.
      • Windows: 34 run, 25 pass, 8 skip, 1 fail. The new test passes; the one failure is feat(shader): resolve nested image tables through runtime pointers #7223's test above.
      • The libc and libkernel suites run 198 and 306 tests on Linux and 225 and 326 on Windows, with 0 failed. The suites ran with APS5_SKIP_TIMING_TESTS=1, which relaxes precise_wait's median bounds on GitHub's hosted runners.
  • 1f158eb, a merge of main 0836dfd (run, on fc6a89d, which has the same tree). build(agc): register each AGC test executable in its own CMake fragment #12862 moved libSceAgcDriver's test registrations into tests/cmake/; the conflict in CMakeLists.txt is resolved with tools/agc_test_split.py resolve, which moves this PR's registrations into tests/cmake/agc_driver_image_table_tests.cmake (+11) and tests/cmake/agc_shader_memory_tests.cmake (+7). Nothing else conflicted. Apart from the move, this PR's diff is unchanged. With -DBUILD_TESTING=ON, ctest -N gives 3084 tests: main's 3075 plus its 9 tests, each listed once. The 11 tests of this PR's verify set ran 10 times in a row. Linux: 11 run, 11 pass, 0 skip, 0 fail. Windows: 11 run, 2 pass, 8 skip (no Vulkan device), 1 fail: agc_shader_nested_snapshot_retry, feat(shader): resolve nested image tables through runtime pointers #7223's test, which exits with 0xc0000135 before it starts, because its registration doesn't put libc's directory on PATH on Windows. It failed the same way before this merge (run at 967f0db, run at f4781de), and resolve moved its lines byte for byte. Suites: libc and libkernel pass on Linux (199 and 308) and on Windows (226 and 330). The suites ran with APS5_SKIP_TIMING_TESTS=1, which relaxes precise_wait's median bounds on GitHub's hosted runners.
  • 5fdf20f: libc on PATH for both nested snapshot retry tests on Windows, at oneandonlydean's request on fix(agc): span table-reading wave64 programs by default on Intel drivers that share handles across fused threads #10846 (comment). tests/cmake/agc_shader_memory_tests.cmake's Windows set_tests_properties now names feat(shader): resolve nested image tables through runtime pointers #7223's agc_shader_nested_snapshot_retry beside this PR's agc_shader_nested_sampler_snapshot_retry, so the 0xc0000135 failure noted above is gone. It's one line, and nothing else changes.
    • Red (run) at 1f158eb: on Windows, agc_shader_nested_snapshot_retry exits with 0xc0000135 and the sampler retry passes. Linux passes both.
    • Green: both retry tests ×10 (run). Linux: 2 run, 2 pass, 0 skip, 0 fail. Windows: 2 run, 2 pass, 0 skip, 0 fail. The libc and libkernel suites run 199 and 308 tests on Linux and 226 and 330 on Windows, with 0 failed. The suites ran with APS5_SKIP_TIMING_TESTS=1, which relaxes precise_wait's median bounds on GitHub's hosted runners.
    • Upstream CI's Windows job at this head (job), merged onto main d262000: 39 tests, 39 passed, 0 skipped, 0 failed, both retry tests included.
  • NVIDIA RTX 2000 Ada Generation at 5fdf20f, from TechLevelZero's NVIDIA bot (report): merged onto main e6f5730, driver 595.99.02, Ubuntu 26.04.1, 2,543 of 3,148 tests selected.
    • 2,492 passed, 6 failed and 45 skipped. None of the failures is new: 3 also fail on main, and 3 are unstable on main.
    • With VK_LAYER_KHRONOS_validation, there are no new validation IDs against main, over 941 tests on the GPU. 9 tests ran with the layer but aren't in main's baseline, so they weren't compared. Both nested snapshot retry tests passed on the GPU.
  • 3283b23, a merge of main 88e804b (run). main now has Ondra97's fix(shader): split scalar-address descriptor phis #7694 (scalar-address descriptor Phis), which adds DescriptorSource::requiredBlocks to the shader plan encoding, and JJenkx's fix(agc): render layered mesh targets within device limits #6959, which moves FormatVersion to 51. Three conflicts, each keeping both sides. In ShaderDiskCache.cpp the encoder writes this PR's pointerKeyed and then fix(shader): split scalar-address descriptor phis #7694's requiredBlocks, in the order the decoder reads them, and the static checks take both changes: DescriptorSource 224 bytes with 4 fields, TableColumn 120 bytes with 20, and at least 82 bytes per encoded descriptor source. FormatVersion stays 63, and agc_shader_memory_tests.cmake registers this PR's two snapshot-retry tests and fix(shader): split scalar-address descriptor phis #7694's agc_shader_descriptor_phis. This PR's changed lines are the same apart from those numbers, and its #include <unordered_set> in ResourceTracker.cpp leaves the diff because fix(shader): split scalar-address descriptor phis #7694 adds the same line. The shader-memory, nested, pointer, image-table, disk-cache and bindless tests, with fix(shader): split scalar-address descriptor phis #7694's agc_shader_descriptor_phis, pass 10 runs in a row. Linux: 22 run, 22 pass, 0 skip, 0 fail. Windows: 24 run, 11 pass, 13 skip, 0 fail. Suites: libc and libkernel pass on Linux (210 and 310) and on Windows (237 and 331). The suites ran with APS5_SKIP_TIMING_TESTS=1, which relaxes precise_wait's median bounds on GitHub's hosted runners.
  • 6cb37cc, a merge of main 4f64f81, which brings B-Howell's feat(agc): sample 1D arrays past maxImageArrayLayers as rows of a 2D image #12246 (1D array layer rows). feat(agc): sample 1D arrays past maxImageArrayLayers as rows of a 2D image #12246 adds resourceViews, a table's registered image views, to the image-table column snapshot.
  • 63b5c09, a merge of main 4f41f4c (×10, the PR's own tests ×10).
    • The conflicts: ShaderDiskCache.hpp's FormatVersion, where main is now at 52 (feat(shader): raise the sampler and sampled-pair limits past the 32-bit sampler masks #10000) and this PR keeps its 63; and docs/dev/debt/shader.md, where this PR's entries and main's new entries are adjacent and both stay. This PR's own lines are unchanged apart from the FormatVersion line's old value.
    • ×10: agc_driver_image_table, agc_driver_many_direct_samplers and every test matching ^agc_shader_memory, ^agc_shader_disk_cache, ^agc_shader_sampler_limits, ^agc_shader_nested or ^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 with APS5_SKIP_TIMING_TESTS=1, which relaxes precise_wait's median bounds on GitHub's hosted runners.
    • ×10 of every ^agc_driver_pointer_ and ^agc_driver_nested_ test, the image-table tests in this PR's diff over main, which the first run's names left out. Linux: 7 run, 7 pass, 0 skip, 0 fail. Windows: 7 run, 0 pass, 7 skip (no Vulkan device), 0 fail.
  • 014d1e3: 4d820bd, a merge of main c2eafe4, which brings yabanana's feat(shader): resolve nested image tables through runtime pointers #7223, and 014d1e3, a debt-entry sentence (×10).
    • The conflicts: this branch's additions on top of feat(shader): resolve nested image tables through runtime pointers #7223's final code, each resolved to this PR's side, which already holds feat(shader): resolve nested image tables through runtime pointers #7223's content: its tests in the image-table test list (tests/cmake/agc_driver_image_table_tests.cmake), pointerKeyed in the image-table column and its equality check (ResourceMaterializer.cpp), the plan encoder's field count and list version (ShaderDiskCache.cpp), and ShaderDiskCache.hpp's FormatVersion, which stays 63 (main is at 56 since feat(shader): resolve nested image tables through runtime pointers #7223).
    • A registration git doubled without a conflict: in tests/cmake/agc_shader_memory_tests.cmake, git kept both feat(shader): resolve nested image tables through runtime pointers #7223's agc_shader_nested_snapshot_retry block and this PR's, which registers it beside agc_shader_nested_sampler_snapshot_retry, so CMake refused the second add_test. The merge keeps one block, this PR's, at feat(shader): resolve nested image tables through runtime pointers #7223's place.
    • This PR's diff over main is now its own changes only: 15 files, 530 insertions and 45 deletions.
    • 014d1e3 adds a sentence to the "Nested image tables" debt entry: a T# reached through a nested child is materialized from its raw words, without registered resourceViews, so a 1D array past maxImageArrayLayers keeps its raw descriptor there.
    • ×10: agc_driver_many_direct_samplers and every test matching ^agc_driver_pointer_, ^agc_driver_nested_, ^agc_shader_nested_, ^agc_driver_image_table, ^agc_shader_memory, ^agc_shader_disk_cache or ^agc_shader_sampler_limits, which takes in every test in this PR's diff over main. Linux: 22 run, 22 pass, 0 skip, 0 fail. Windows: 24 run, 10 pass, 14 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 with APS5_SKIP_TIMING_TESTS=1, which relaxes precise_wait's median bounds on GitHub's hosted runners.

Checklist

@github-actions github-actions Bot added build shader core/shader docs agc libSceAgc* needs rebase Conflicts with main, rebase needed labels Oct 18, 2026
@github-actions

github-actions Bot commented Oct 18, 2026 •

Copy link
Copy Markdown

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.

Pull request Conflicting files (lines on main) Same exports Same new files
PR 6416 core/shader/recompiler/ShaderDiskCache.hpp L16
PR 10351 core/shader/recompiler/ShaderDiskCache.hpp L16
PR 11551 core/shader/recompiler/ShaderDiskCache.hpp L16
PR 14636 core/shader/recompiler/ShaderDiskCache.hpp L16
PR 14871 core/shader/recompiler/ShaderDiskCache.hpp L16
PR 14904 core/libs/prx/libSceAgcDriver/tests/ShaderDiskCache.cpp L1875

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 907 core/shader/recompiler/Optimization/src/ResourceMaterializer.cpp
core/shader/recompiler/SpirvBackend/src/SpirvImageEmitter.cpp
PR 5021 core/shader/recompiler/Recompiler.cpp
core/shader/recompiler/SpirvBackend/src/SpirvImageEmitter.cpp
docs/dev/debt/shader.md
PR 5371 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/Optimization/src/ResourceMaterializer.cpp
core/shader/recompiler/SpirvBackend/src/SpirvImageEmitter.cpp
docs/dev/debt/shader.md
PR 5609 core/libs/prx/libSceAgcDriver/tests/ShaderDiskCache.cpp
core/shader/recompiler/Recompiler.cpp
core/shader/recompiler/ShaderDiskCache.cpp
PR 5925 core/shader/recompiler/ShaderDiskCache.cpp
core/shader/recompiler/ShaderDiskCache.hpp
PR 6235 core/libs/prx/libSceAgcDriver/tests/ShaderDiskCache.cpp
core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
docs/dev/debt/shader.md
PR 6280 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 6412 core/libs/prx/libSceAgcDriver/tests/ShaderDiskCache.cpp
core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/IntermediateRepresentation/include/IntermediateRepresentation/IrMetadata/ResourcePlan.hpp
core/shader/recompiler/Optimization/src/ResourceMaterializer.cpp
core/shader/recompiler/Recompiler.cpp
core/shader/recompiler/ShaderDiskCache.cpp
core/shader/recompiler/ShaderDiskCache.hpp
docs/dev/debt/shader.md
PR 6481 core/libs/prx/libSceAgcDriver/tests/execution/ImageTable.cpp
PR 6488 core/libs/prx/libSceAgcDriver/tests/ShaderDiskCache.cpp
core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/ImageTableAbi.hpp
core/shader/recompiler/IntermediateRepresentation/include/IntermediateRepresentation/IrMetadata/ControlFlowInfo.hpp
core/shader/recompiler/IntermediateRepresentation/include/IntermediateRepresentation/IrMetadata/ResourcePlan.hpp
core/shader/recompiler/Optimization/src/ResourceMaterializer.cpp
core/shader/recompiler/Optimization/src/ResourceTracker.cpp
core/shader/recompiler/Recompiler.cpp
core/shader/recompiler/ShaderDiskCache.cpp
core/shader/recompiler/ShaderDiskCache.hpp
core/shader/recompiler/SpirvBackend/src/SpirvImageEmitter.cpp
docs/dev/debt/shader.md
PR 6858 core/libs/prx/libSceAgcDriver/tests/ShaderDiskCache.cpp
core/shader/recompiler/Recompiler.cpp
core/shader/recompiler/ShaderDiskCache.cpp
core/shader/recompiler/ShaderDiskCache.hpp
PR 6924 core/libs/prx/libSceAgcDriver/tests/ShaderDiskCache.cpp
core/shader/recompiler/Recompiler.cpp
core/shader/recompiler/ShaderDiskCache.cpp
core/shader/recompiler/ShaderDiskCache.hpp
docs/dev/debt/shader.md
PR 6970 core/libs/prx/libSceAgcDriver/tests/ShaderDiskCache.cpp
core/shader/recompiler/ShaderDiskCache.cpp
PR 7085 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 7392 docs/dev/debt/shader.md
PR 7410 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/Recompiler.cpp
docs/dev/debt/shader.md
PR 7684 core/libs/prx/libSceAgcDriver/tests/ShaderDiskCache.cpp
core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/libs/prx/libSceAgcDriver/tests/execution/ImageTable.cpp
core/shader/recompiler/IntermediateRepresentation/include/IntermediateRepresentation/IrMetadata/ControlFlowInfo.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
docs/dev/debt/shader.md
PR 7689 core/shader/recompiler/Optimization/src/ResourceMaterializer.cpp
core/shader/recompiler/ShaderDiskCache.cpp
PR 8004 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/Recompiler.cpp
docs/dev/debt/shader.md
PR 9020 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/Recompiler.cpp
core/shader/recompiler/ShaderDiskCache.hpp
docs/dev/debt/shader.md
PR 9183 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 9335 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/Recompiler.cpp
core/shader/recompiler/ShaderDiskCache.hpp
docs/dev/debt/shader.md
PR 9356 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/Recompiler.cpp
core/shader/recompiler/ShaderDiskCache.cpp
core/shader/recompiler/ShaderDiskCache.hpp
PR 9387 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/Recompiler.cpp
core/shader/recompiler/ShaderDiskCache.cpp
core/shader/recompiler/ShaderDiskCache.hpp
docs/dev/debt/shader.md
PR 9748 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/Recompiler.cpp
core/shader/recompiler/ShaderDiskCache.hpp
docs/dev/debt/shader.md
PR 9852 core/libs/prx/libSceAgcDriver/tests/ShaderDiskCache.cpp
core/shader/recompiler/Optimization/src/ResourceTracker.cpp
core/shader/recompiler/ShaderDiskCache.cpp
core/shader/recompiler/ShaderDiskCache.hpp
PR 9889 core/libs/prx/libSceAgcDriver/tests/ShaderDiskCache.cpp
core/libs/prx/libSceAgcDriver/tests/ShaderMemory.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 9897 core/libs/prx/libSceAgcDriver/tests/ShaderDiskCache.cpp
core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/libs/prx/libSceAgcDriver/tests/cmake/agc_shader_memory_tests.cmake
core/shader/recompiler/Optimization/src/ResourceTracker.cpp
core/shader/recompiler/Recompiler.cpp
core/shader/recompiler/ShaderDiskCache.cpp
core/shader/recompiler/ShaderDiskCache.hpp
PR 10049 core/libs/prx/libSceAgcDriver/tests/ShaderDiskCache.cpp
core/shader/recompiler/ShaderDiskCache.cpp
core/shader/recompiler/ShaderDiskCache.hpp
PR 10193 core/libs/prx/libSceAgcDriver/tests/ShaderDiskCache.cpp
core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/libs/prx/libSceAgcDriver/tests/cmake/agc_shader_memory_tests.cmake
core/shader/recompiler/ImageTableAbi.hpp
core/shader/recompiler/Optimization/src/ResourceMaterializer.cpp
core/shader/recompiler/Optimization/src/ResourceTracker.cpp
core/shader/recompiler/Recompiler.cpp
core/shader/recompiler/ShaderDiskCache.cpp
core/shader/recompiler/ShaderDiskCache.hpp
core/shader/recompiler/SpirvBackend/src/SpirvImageEmitter.cpp
PR 10233 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/Optimization/src/ResourceMaterializer.cpp
docs/dev/debt/shader.md
PR 10359 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/Recompiler.cpp
PR 10757 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/Recompiler.cpp
PR 10867 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/Optimization/src/ResourceMaterializer.cpp
core/shader/recompiler/SpirvBackend/src/SpirvImageEmitter.cpp
docs/dev/debt/shader.md
PR 11351 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/Recompiler.cpp
PR 11483 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/Recompiler.cpp
docs/dev/debt/shader.md
PR 12324 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/IntermediateRepresentation/include/IntermediateRepresentation/IrMetadata/ControlFlowInfo.hpp
core/shader/recompiler/Recompiler.cpp
PR 12548 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/Recompiler.cpp
docs/dev/debt/shader.md
PR 12790 core/shader/recompiler/Recompiler.cpp
core/shader/recompiler/SpirvBackend/src/SpirvImageEmitter.cpp
docs/dev/debt/shader.md
PR 12828 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/Recompiler.cpp
PR 12944 core/shader/recompiler/Recompiler.cpp
core/shader/recompiler/ShaderDiskCache.cpp
core/shader/recompiler/ShaderDiskCache.hpp
docs/dev/debt/shader.md
PR 13928 core/libs/prx/libSceAgcDriver/tests/ShaderDiskCache.cpp
core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/libs/prx/libSceAgcDriver/tests/cmake/agc_shader_memory_tests.cmake
core/shader/recompiler/ImageTableAbi.hpp
core/shader/recompiler/Optimization/src/ResourceMaterializer.cpp
core/shader/recompiler/Optimization/src/ResourceTracker.cpp
core/shader/recompiler/Recompiler.cpp
core/shader/recompiler/ShaderDiskCache.cpp
core/shader/recompiler/ShaderDiskCache.hpp
core/shader/recompiler/SpirvBackend/src/SpirvImageEmitter.cpp
PR 13929 core/libs/prx/libSceAgcDriver/tests/ShaderDiskCache.cpp
core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/libs/prx/libSceAgcDriver/tests/cmake/agc_shader_memory_tests.cmake
core/shader/recompiler/ImageTableAbi.hpp
core/shader/recompiler/Optimization/src/ResourceMaterializer.cpp
core/shader/recompiler/Optimization/src/ResourceTracker.cpp
core/shader/recompiler/Recompiler.cpp
core/shader/recompiler/ShaderDiskCache.cpp
core/shader/recompiler/ShaderDiskCache.hpp
core/shader/recompiler/SpirvBackend/src/SpirvImageEmitter.cpp
PR 14032 core/libs/prx/libSceAgcDriver/tests/ShaderDiskCache.cpp
core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/libs/prx/libSceAgcDriver/tests/cmake/agc_shader_memory_tests.cmake
core/shader/recompiler/Optimization/src/ResourceTracker.cpp
core/shader/recompiler/Recompiler.cpp
core/shader/recompiler/ShaderDiskCache.cpp
core/shader/recompiler/ShaderDiskCache.hpp
PR 14212 docs/dev/debt/shader.md
PR 14217 core/libs/prx/libSceAgcDriver/tests/ShaderDiskCache.cpp
core/shader/recompiler/Recompiler.cpp
docs/dev/debt/shader.md
PR 14218 core/libs/prx/libSceAgcDriver/tests/ShaderDiskCache.cpp
core/shader/recompiler/Recompiler.cpp
docs/dev/debt/shader.md
PR 14561 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
PR 14621 core/shader/recompiler/SpirvBackend/src/SpirvImageEmitter.cpp
PR 14702 core/shader/recompiler/Optimization/src/ResourceMaterializer.cpp
core/shader/recompiler/SpirvBackend/src/SpirvImageEmitter.cpp
PR 14944 core/libs/prx/libSceAgcDriver/tests/ShaderDiskCache.cpp
core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/libs/prx/libSceAgcDriver/tests/cmake/agc_shader_memory_tests.cmake
core/shader/recompiler/Optimization/src/ResourceTracker.cpp
core/shader/recompiler/Recompiler.cpp
core/shader/recompiler/ShaderDiskCache.cpp
core/shader/recompiler/ShaderDiskCache.hpp

@blawesom

Copy link
Copy Markdown
Contributor

Rebase handoff — rebased onto current main (all six commits, authorship unchanged). The conflicts reconcile main's evolved table-record architecture (DenseScratchMap/tagged scratch records, the selected/selection columns) with this PR's nested/pointer-chained image-table support:

  • ResourceMaterializer.cpp: main's DenseScratchMap records kept, plus a second tagged map for the nested-table codes (the auto-merge had produced a non-compiling try_emplace — the nested/leaf namespaces now index separate maps, with the PR's per-invocation clearing semantics preserved across recursion); your recursive fill(self, …) shape and the growMap budget guards layered on top
  • ControlFlowInfo.hpp/ShaderDiskCache.cpp: additive fields throughout — selected/selection (main) + buffer (yours) + pointerKeyed (commit 5) — the TableColumn field count is now 19, encoder/decoder and the static assert agree
  • ResourceTracker.cpp: main's constant/addend offset logic with your parent-pointer word patch unioned (args 1–2 of a parent-pointer patch take the pointer's words)
  • test coverage: ImageTable's binding-role counts, the --nested*/--pointer-phi* flags, and the disk-cache reject cases all carried

One combination to review when you pick it up: when a selected column and a parent-pointer patch apply together, the args take the pointer's words while remaining args keep main's constant offsets — no test covers that intersection.

Verified on Linux (CachyOS, kernel 7.2.9, GCC 16.2.1, Ninja, Release, BUILD_TESTING=ON, AMD RX 9070 XT / RADV): builds; conventions pass; the image-table and disk-cache tests pass; full suite green apart from the known main regression (agc_driver_tessellation segfault — Mesa, #5444), not this PR.

To pick it up:

git fetch https://github.com/blawesom/AnyPS5 rebase/7395
git checkout <your branch>
git merge --ff-only FETCH_HEAD

Head is fdcf0d57.

@EagleBearerYS

Copy link
Copy Markdown
Contributor Author

@blawesom thank you for the rebase and for reconciling all eight files, including the auto-merge's non-compiling try_emplace. We took your resolution as a merge rather than a rebase, to keep the branch's history without a force-push: aed137c merges main 9caecfd into this branch, its tree is exactly your fdcf0d5's, and you're credited as co-author on it. On GitHub's runners (run) the ^agc tests pass 3 runs in a row on Linux (715, 0 failed); on Windows the only failures are the two replay tools that fail the same way on that runner for unrelated branches. Thanks also for flagging the case where a selected column and a parent-pointer patch apply together; we'll add a test for it.

@EagleBearerYS

Copy link
Copy Markdown
Contributor Author

@blawesom a follow-up on the case you flagged, where a selected column and a parent-pointer patch apply together. We said we'd add a test for it, but no shader can reach that case on this branch, so there's nothing for a test to cover:

  • A leaf column gets a parent pointer only when its heap V# doesn't validate as a runtime source (ResourceTracker.cpp:650-670 at aed137c). The other place that sets one, TryMakeIndirectColumn (825), returns before selected is worked out.
  • A column is selected only when its T#'s dwords validate (692). Those dwords are ReadConstBuffer reads through the heap V#, and validating such a read validates its V# handle and the handle's four dwords (SrtRuntimeValidator.cpp:111-142), the same check line 650 makes.
  • So a selected leaf never takes the nested branch, and a nested leaf is never selected. The materialization loop never takes its selected arguments and its parent-pointer arguments for the same plan.

A Linux run of the ^agc tests (716) with a temporary print logged 211 table-column plans, none with both. A nested-table shader whose keys the CPU evaluates gave a single selected column and no nested table at all. We've left the code as it is.

@ps54all

ps54all commented Oct 18, 2026

Copy link
Copy Markdown

@EagleBearerYS thanks for b91f050. Ratchet & Clank: Rift Apart (PPSA01474) data with it:

  • Base: a local test branch (main 82f0c9a plus open PRs, not clean main) that already carried this PR's earlier commits; b91f050 cherry-picked on top. Windows 11, RTX 3080 (NVIDIA 610.74), MinGW GCC 15.2.0, Release.
  • The stop on compute shader 0x116bb5f500 (LoadAddressU32@pc=0x00008fd4, 6-deep Phi) is gone.
  • The run now stops about 214 s in, still on a black window, on the next compute shader with the same error and a 7-deep Phi chain:
compute shader 0x116bb67000: shader 0x116bb67000 stage 0: ShaderRecompiler::Recompile: GetImageResource dword 0 is not a valid runtime value; chain: LoadAddressU32@pc=0x00009a30(GetAddressResource(Phi(Phi(Phi(Phi(Phi(Phi(Phi, Phi), Phi(Phi, ReadConstBuffer@pc=0x00001aa8)), Phi(Phi(Phi, Phi), CompositeExtractU32x4(Ballot, Immediate))), Phi(Phi(Phi(Phi, ReadConstBuffer@pc=0x00001aa8), Phi(Phi, Phi)), Phi(Phi(ReadConstBuffer@pc=0x00001aa8, Phi), ReadConstBuffer@pc=0x00001aa8(GetBufferResource, ShiftLeftLogical32)))), BitwiseAnd32(Phi(Phi(Phi(Phi, Phi), BitwiseAnd32(Phi, CompositeExtractU32x4)), Phi(Phi(Phi, BitwiseAnd32), Phi(Phi, Phi))), CompositeExtractU32x4(Ballot(Immediate), Immediate))), Phi(Phi(Phi(Phi(Phi(Phi, ReadConstBuffer@pc=0x00001aa8), Phi(Phi, Phi)), Phi(Phi(ReadConstBuffer@pc=0x00001aa8, Phi), ReadConstBuffer@pc=0x00001aa8(GetBufferResource, ShiftLeftLogical32))), Phi(Phi(Phi(Phi, Phi), Phi(Phi, ReadConstBuffer@pc=0x00001aa8)), CompositeExtractU32x4(Ballot(LogicalAnd), Immediate))), Phi(Phi(Phi(Phi(ReadConstBuffer@pc=0x00001aa8, Phi), ReadConstBuffer@pc=0x00001aa8(GetBufferResource, ShiftLeftLogical32)), Phi(Phi(Phi, ReadConstBuffer@pc=0x00001aa8), Phi(Phi, Immediate))), Phi(Phi(ReadConstBuffer@pc=0x00001aa8(GetBufferResource, ShiftLeftLogical32), Phi(ReadConstBuffer@pc=0x00001aa8, Immediate)), ReadConstBuffer@pc=0x00001aa8(GetBufferResource(ReadConst, ReadConst, ReadConst, ReadConst), ShiftLeftLogical32(ReadFirstLane, Immediate)))))), Phi(Phi(ReadConstBuffer@pc=0x00001aa8(GetBufferResource(ReadConst(GetSrtResource, Immediate), ReadConst(GetSrtResource, Immediate), ReadConst(GetSrtResource, Immediate), ReadConst(GetSrtResource, Immediate)), ShiftLeftLogical32(ReadFirstLane(SelectU32(LogicalAnd, IAdd32, Phi), Phi(LogicalAnd, LogicalAnd)), Immediate)), Phi(ReadConstBuffer@pc=0x00001aa8(GetBufferResource(ReadConst(GetSrtResource, Immediate), ReadConst(GetSrtResource, Immediate), ReadConst(GetSrtResource, Immediate), ReadConst(GetSrtResource, Immediate)), ShiftLeftLogical32(ReadFirstLane(SelectU32, Phi), Immediate)), ReadConstBuffer@pc=0x0000908c(GetBufferResource(LoadAddressU32@pc=0x0000900c(GetAddressResource, Immediate, Immediate, Immediate), LoadAddressU32@pc=0x0000900c(GetAddressResource, Immediate, Immediate, Immediate), LoadAddressU32@pc=0x0000900c(GetAddressResource, Immediate, Immediate, Immediate), LoadAddressU32@pc=0x0000900c(GetAddressResource, Immediate, Immediate, Immediate)), Immediate))), ReadConstBuffer@pc=0x00001aa8(GetBufferResource(ReadConst(GetSrtResource, Immediate), ReadConst(GetSrtResource, Immediate), ReadConst(GetSrtResource, Immediate), ReadConst(GetSrtResource, Immediate)), ShiftLeftLogical32(ReadFirstLane(SelectU32(LogicalAnd(INotEqual32, INotEqual32), IAdd32(Phi, Phi), Phi(Phi, Phi)), Phi(LogicalAnd(INotEqual32, INotEqual32), LogicalAnd(Phi, INotEqual32))), Immediate)))), Immediate, Immediate, Immediate)
  • The chain has Ballot / CompositeExtractU32x4(Ballot, Immediate) and ReadFirstLane(SelectU32 ...) arms feeding the Phis, plus a ReadConstBuffer@pc=0x908c whose buffer comes from LoadAddressU32@pc=0x900c(GetAddressResource).
  • One run each, before and after.

I can capture the shader (.req) if that helps.

AI assistance: the run and this summary were made with Claude Code.

@EagleBearerYS

EagleBearerYS commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor Author

@ps54all thanks for running it. On your branch, b91f050 clears the stop on compute shader 0x116bb5f500 (LoadAddressU32@pc=0x8fd4). Your next stop is the one Tamalero reached on Linux (#6191), in a sibling shader: both chains read the same record table at pc=0x1aa8, and every pc after it is 0x44 past theirs (the stop at 0x9a30 against 0x99ec, the second buffer's read at 0x908c against 0x9048, and its V# load at 0x900c against 0x8fc8). So one fix covers both.

No need for the .req, thanks. What's still open is which values those reads return at run time, and the shader's code can't show that. If you, or Tamalero on #6191, can run one diagnostic on that dispatch, it's the one we asked Tamalero for (comment): the dword the read at pc=0x908c returns, next to the high dwords of the records the pc=0x1aa8 reads return, with addresses masked. Whether those are always equal decides how #7395 takes the pointer's high word. The chain's other two parts, the AND with a Ballot word and the high word's Phi of record reads, don't need that data.

@Capmare

Capmare commented Oct 18, 2026

Copy link
Copy Markdown
Contributor

Tested on real hardware, with no title run. Head aed137cae, full build with BUILD_TESTING=ON, Release, Rocky Linux 10.2, ANYPS5_GPU=<name> ANYPS5_REQUIRE_VULKAN=1, 735 graphics tests per GPU.

GPU (driver) Result
RTX 4070 SUPER (NVIDIA 615.71.09) all 735 pass, including agc_driver_nested_sampler_table and agc_driver_pointer_phi_sampler_table
RX 7600 (RADV, Mesa 25.2.7) both new sampler tests pass, 3 of 3 runs each; 1 unrelated failure, agc_pipeline_cache_file
UHD 770 (ANV, Mesa 25.2.7) both new sampler tests fail, 3 of 3 runs each
llvmpipe (Mesa 25.2.7) both new sampler tests pass, 3 of 3 runs each

The Intel failures, run as agc_driver_image_table_tests --nested-sampler and --pointer-phi-sampler:

nested sampler table: the sampler selected through record, pointer and V#: lane 0 is 0x3e800000, expected 0x427d0000
pointer sampler table: the S# read through the record's pointer: lane 0 is 0x427d0000, expected 0x3e800000

The two values are swapped between the two tests. The tests choose between a wrap and a clamp point sampler, so ANV may return the result of the other sampler. I have not found the cause. The existing agc_driver_nested_image_table* tests pass on all three GPUs.

Tested and written by Claude (AI assistant) on a contributor's machine.

@github-actions github-actions Bot added unblocks title Names a title ID on the Unblocks line and removed needs rebase Conflicts with main, rebase needed labels Oct 18, 2026
@EagleBearerYS

Copy link
Copy Markdown
Contributor Author

@Capmare thank you for running all four devices, and for repeating the ANV failures three times.

The tests can't confuse the two samplers. Every lane samples past the right edge, so a wrap sampler reads texel x (0x3e800000, 0.25, at lane 0) and a clamp sampler reads texel 63 (0x427d0000, 63.25).

Both failures come from the first check of the first dispatch. That check walks the workgroups in order and stops at the first one that differs, so your two lines say this:

  • --nested-sampler: workgroup 0 selects the wrap S# and matches. Workgroup 1 selects the clamp S# and reads the wrap result.
  • --pointer-phi-sampler: workgroup 0 selects the clamp S# and matches. Workgroup 1 selects the wrap S# and reads the clamp result.

So on ANV the second workgroup gets the first workgroup's sampler. Workgroups 2 and 3 never ran through the check.

The agc_driver_nested_image_table* tests go through the same records and keys, and they pass there. So the difference is in how the sampler is picked. Each workgroup indexes a VK_DESCRIPTOR_TYPE_SAMPLER array with its own index, decorated NonUniform, with shaderSampledImageArrayNonUniformIndexing enabled. We haven't found yet whether the fault is in our SPIR-V or in ANV, so the tests stay as they are and we're keeping this open.

If you have time for one more run: the same two tests with the Khronos validation layer (VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation, if it's installed) would show whether it reports anything for those dispatches.

@Capmare

Capmare commented Oct 18, 2026

Copy link
Copy Markdown
Contributor

@EagleBearerYS I ran the two tests with the Khronos validation layer, and I found a trigger on ANV that does not involve our SPIR-V. Details below, including what I could not prove.

Summary

  • The validation layer is silent, and spirv-val accepts the module.
  • The failing shader is valid and selects the sampler correctly. ANV returns the sampler of workgroup 0 for workgroup 1.
  • I reproduced the same behaviour in a standalone Vulkan program with no AnyPS5 code. The trigger is a compute stage with requiredSubgroupSize = 32, local_size_x = 32 and a sampler array with more than 2 elements, indexed per workgroup.
  • APS5_SPANNED_WAVE=1 makes both tests pass on ANV. It changes no other registered test result on the Intel GPU.
  • I do not know why ANV does this. I did not look at the Mesa source.

Setup

  • Intel RPL-S (the iGPU of an i7-14700K), Mesa 25.2.7 (ANV), Vulkan 1.4.318. The same PC also has an RTX 4070 SUPER (driver 615.71.09), an RX 7600 (RADV) and llvmpipe (LLVM 21.1.8).
  • Local build of this PR head (aed137cae) merged with origin/main at c4c2b3aa7, plus some local patches (see "Caveats").
  • Command: ANYPS5_GPU=Intel ANYPS5_NO_SHADER_CACHE=1 ./agc_driver_image_table_tests --nested-sampler (and --pointer-phi-sampler), from the source directory. I ran the binary directly and did not use ctest.

Results of the two tests

Device --nested-sampler --pointer-phi-sampler
Intel RPL-S (ANV) fail fail
AMD RX 7600 (RADV) pass pass
NVIDIA RTX 4070 SUPER pass pass
llvmpipe pass pass

The two Intel failures are the lines from your comment:

  • --nested-sampler: group 1 lane 0 is 0x3e800000, expected 0x427d0000 (the wrap result instead of clamp).
  • --pointer-phi-sampler: lane 0 is 0x427d0000, expected 0x3e800000 (the clamp result instead of wrap).

I added the group number to the failure message locally. It confirms your reading: the first mismatch is workgroup 1, and workgroup 1 gets the sampler of workgroup 0. The failure does not depend on the validation layer, on APS5_NO_GPL, on APS5_NO_PROC_TABLE, on APS5_NO_TIMELINE, on APS5_NO_HOST_IMPORT, or on APS5_NO_SAMPLER_CACHE. I ran each of these on Intel, and the result did not change. All my runs used ANYPS5_NO_SHADER_CACHE=1; I did not test with the shader cache on.

Validation layer

VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation loads (VK_LOADER_DEBUG=layer shows Insert instance layer "VK_LAYER_KHRONOS_validation"). It prints no message for either test on any device. spirv-val --target-env vulkan1.3 accepts the captured compute module (5,656 words). I built spirv-val and spirv-dis from the repo's SPIRV-Tools source for this.

The SPIR-V of the failing dispatch

I captured the pipeline with APS5_DUMP_COMPUTE_PIPELINES. Facts about the module:

  • LocalSize 32 1 1. The guest wave is 64, and the module has two OpImageSampleExplicitLod. I read this as two guest lanes per host invocation, but I did not verify that in the emitter.
  • The sampler is loaded with OpLoad from table_samplers[element] (a runtime array of OpTypeSampler), then OpSampledImage combines it with the image. The element comes from table_map. There is no NonUniform decoration, because the emitter treats the index as uniform per workgroup when the workgroup is one subgroup.

What I tried on the real test, with the real buffers

I added a local diagnostic hook that replaces the compute module with an edited file, so the driver, the buffers and the descriptors stay real. Results on the Intel GPU:

Change Result
unmodified module same failure
sampler element forced to 0 group 1 gets wrap (as in the failure)
sampler element forced to 4 group 0 gets clamp (so the index is honoured)
sampler element computed from gl_WorkGroupID only, with the expected pattern wrap/clamp/clamp/wrap group 1 still gets wrap
NonUniform forced on the index (emitter switch) no change
OpGroupNonUniformBroadcastFirst on the index (emitter switch) no change

The row with the workgroup id is the important one. It means the key, the record and the pointer chain are not the cause.

Standalone reproduction (no AnyPS5 code)

A C program (about 300 lines) and one GLSL compute shader. It makes two samplers (REPEAT and CLAMP_TO_EDGE) and a 64x1 R32_SFLOAT texture with texel i = i. It dispatches 4 workgroups of 32 threads. Workgroup g samples at u = 1.2578125 through sampler g & 1. Wrap gives texel 16, clamp gives texel 63. Expected output per workgroup: 16 63 16 63.

On the Intel GPU:

Pipeline stage setup Sampler array Result
default subgroup size [2], [8], [1024], runtime, with and without nonuniformEXT, with a branch, with 2 samples per invocation, with a two-level index all pass
requiredSubgroupSize = 32 [2] fixed pass
requiredSubgroupSize = 32 [8], [1024] or runtime (8 to 1024 descriptors, partially bound), index from a buffer, from a subgroup broadcast, with a branch, with 2 samples all fail: wg0=16 wg1=16 wg2=16 wg3=16
requiredSubgroupSize = 32 + REQUIRE_FULL_SUBGROUPS same same result as above
requiredSubgroupSize = 8 or 16 runtime, index from a buffer pass

NVIDIA, RADV and llvmpipe pass every variant. The validation layer reports nothing for the program.

The trigger is therefore: required subgroup size 32, a workgroup of exactly 32 threads (one SIMD32 thread), and a sampler array with more than 2 elements indexed per workgroup. The driver creates our compute stages with requiredSubgroupSize = 32 for wave32 programs, which is why the tests hit it.

The compute shader of the reproduction
#version 450
#extension GL_EXT_nonuniform_qualifier : require
#extension GL_KHR_shader_subgroup_ballot : require
layout(local_size_x = 32) in;
layout(set = 0, binding = 0) uniform texture2D tex;
layout(set = 0, binding = 1) uniform sampler samplers[];   // compiled with -DRUNTIME_ARRAY
layout(set = 0, binding = 2) readonly buffer Indices { uint indices[]; };
layout(set = 0, binding = 3) writeonly buffer Results { float results[]; };
void main() {
    uint index = indices[gl_WorkGroupID.x];
    float value = textureLod(sampler2D(tex, samplers[index]), vec2(1.2578125, 0.5), 0.0).x;
    results[2u * gl_GlobalInvocationID.x] = value;
}

Workarounds I tested on the Intel GPU

  1. APS5_SPANNED_WAVE=1: works. Both tests pass, 3 runs each. The program then runs as LocalSize 64 with two 32-lane subgroups, so a workgroup is no longer one SIMD32 thread.
  2. Not requiring the subgroup size (diagnostic switch in computeSubgroupSize): not enough. The sampler check then passes, but both tests fail at a later check: a captured pointer selected through Phi faulted (--nested-sampler) and a captured pointer selected through Phi changed the result (--pointer-phi-sampler). The wave32 logic needs a subgroup of 32 lanes.
  3. A fixed-size array instead of a runtime array: not a fix. Arrays of 8 and 1024 elements fail the same way.

Effect of APS5_SPANNED_WAVE=1 on the other registered tests

I ran all 235 registered libSceAgcDriver tests directly (121 test executables, with the environment, timeout and working directory from CMakeLists.txt), on each GPU:

Run pass skip fail
Intel, default 217 3 15
Intel, APS5_SPANNED_WAVE=1 219 3 13
RTX 4070 SUPER, default 220 2 13
RX 7600, default 218 3 14

Between the two Intel runs only agc_driver_nested_sampler_table and agc_driver_pointer_phi_sampler_table change, from fail to pass. No test goes from pass to fail.

Tests that fail on every device

These 13 tests fail on Intel, NVIDIA and RADV alike, with and without the spanned-wave switch: agc_buffer_pool, agc_driver_stencil_replay_no_gpl, agc_host_import_second_mapping, agc_import_settle_deferred, agc_import_settle_deferred_other_family, agc_import_settle_earlier_import, agc_import_settle_first_use, agc_import_settle_retire, agc_import_settle_storage_image, agc_shader_bindless, agc_shader_frontend_pair, agc_storage_cpu_snapshot, agc_vertex_barrier. RADV also fails agc_pipeline_cache_file. I did not investigate them. They may come from my merge of origin/main, from my local patches, or they may exist upstream. I did not run them on a clean checkout of the PR head.

Caveats

  • This is not a clean PR head. My tree has local patches for a different goal (running a game). They do not touch the sampler-table code, but the local build has a diagnostic fallback in the resource tracker that replaces a sampler reached through a runtime pointer chain. With it, --nested-sampler fails on every device with a V# with another buffer consumer was not refused by resource planning. I turned it off with APS5_NO_DESCRIPTOR_SUBSTITUTE=1 for all runs above. A clean PR head does not have this fallback.
  • I tested only the Intel iGPU of this PC. I did not test other Intel GPUs or other Mesa versions.
  • I did not read the Mesa source. I cannot say which ANV code path causes the behaviour.
  • The test comparison covers the registered unit tests. I did not test game workloads with the spanned-wave mode.

Suggestion

I did not change the tests or the driver. If you want a driver change, enabling the spanned-wave mode on ANV is the smallest one I found. It changes how every single-wave wave64 compute shader runs on that driver, so I leave the decision to you. Separately, the standalone program is a clean bug report for Mesa. I can attach the source and a short write-up, or file the Mesa report myself if you prefer.

@EagleBearerYS

Copy link
Copy Markdown
Contributor Author

@Capmare thank you, this settles it, and the standalone program is the strongest part. With no AnyPS5 code, ANV gives workgroup 1 workgroup 0's sampler whenever the stage has requiredSubgroupSize = 32 and the sampler array has more than 2 elements. A fixed [2] array passes, and so does the default subgroup size. The validation layer and spirv-val report nothing. So it's an ANV issue, not our SPIR-V.

A correction to my last comment: the module carries no NonUniform on that index, as you found. The emitter treats the index as uniform when the workgroup is one subgroup, and your forced-NonUniform run shows the decoration makes no difference.

The two tests stay as they are, since they're what caught it. APS5_SPANNED_WAVE=1 passing on ANV is a useful lead for a workaround on our side. We aren't changing anything for it yet.

If you want to report it, your program looks ready to post as a Mesa issue as it stands (https://gitlab.freedesktop.org/mesa/mesa/-/issues). That's entirely up to you.

@github-actions github-actions Bot added the needs rebase Conflicts with main, rebase needed label Oct 18, 2026
@Capmare

Capmare commented Oct 18, 2026

Copy link
Copy Markdown
Contributor

@EagleBearerYS thank you for the careful review and for the clear questions. They pointed me to the validation layer and to the exact failing dispatch, which is how I found the cause.

I posted the standalone program as a Mesa issue: https://gitlab.freedesktop.org/mesa/mesa/-/work_items/16622

I agree with leaving the two tests as they are and with not changing the driver yet. If Mesa answers, I will post the result here.

@TechLevelZero

Copy link
Copy Markdown
Contributor

✅ NVIDIA GPU test: passed

PR head 6cb37cc merged onto main 1d91f29 · tested 2026-11-02 19:35 UTC · 34 min

GPU NVIDIA RTX 2000 Ada Generation, driver 595.99.02, Vulkan 1.4.329
Host Ubuntu 26.04.1 LTS, kernel 7.0.0-38-generic, container ubuntu:24.04
Logs build and test logs for this run
Build ✅ passed (Release, -DANYPS5_ENABLE_SPIRV_TOOLS=ON)
Tests ✅ 2,687 passed · 6 failed (0 new, 3 also fail on main, 3 unstable on main) · 45 skipped (ANYPS5_REQUIRE_VULKAN=1)
Test setup CPU-only tests without a GPU; GPU tests (and any CPU-only test that failed or skipped without one) once on the GPU with VK_LAYER_KHRONOS_validation and ANYPS5_NO_SHADER_CACHE=1; main ran the same way
Test selection 2,738 of 3,544 tests run: the ones this change can reach, chosen by tools/select_tests.py from main's build graph
Vulkan validation ✅ no new validation IDs vs main (993 tests run on the GPU)
Slow tests (>30 s, GPU tests timed with validation layers) ⚠️ agc_driver_pipeline_journal 120.1 s, ⚠️ agc_driver_graphics_maps_fallback 30.6 s
Unstable on main (3, these also failed in recent main runs on this machine; not counted against this PR)
agc_driver_pipeline_journal: failed in 3 of the last 10 main runs
agc_submit_progress: failed in 8 of the last 10 main runs
agc_submit_progress_no_timeline: failed in 7 of the last 10 main runs
Failing on main too (3, not counted against this PR)
agc_driver_image_table
guest_mmap_executable
guest_socket_options_multicast
Validated but not compared (9, not in the main baseline's validation pass)
agc_driver_nested_image_table
agc_driver_nested_image_table_budget
agc_driver_nested_image_table_large
agc_driver_nested_sampler_table
agc_driver_pointer_phi_ballot_table
agc_driver_pointer_phi_copies_table
agc_driver_pointer_phi_sampler_table
agc_shader_nested_sampler_snapshot_retry
agc_shader_nested_snapshot_retry
Validation IDs already present on main (4 IDs in 510 tests)
VUID-VkDeviceCreateInfo-pNext-pNext (510 tests): agc_driver, agc_driver_address_passes, agc_driver_alias_copy_label, agc_driver_alpha_to_coverage, agc_driver_array_layer_target, agc_driver_bc_block_copy, agc_driver_bda_anchor_reads, agc_driver_bda_span_reads, and 502 more
VUID-vkCmdCopyImage-srcImage-01548 (7 tests): agc_driver_depth_clear_hle, agc_driver_depth_plane_buffer_memory, agc_driver_depth_plane_partial_store, agc_driver_depth_plane_sampling, agc_driver_depth_storage_dispatch, agc_driver_depth_surface_from_storage, agc_driver_dispatch_move_depth
VUID-vkCmdCopyImage-srcImage-01551 (7 tests): agc_driver_depth_clear_hle, agc_driver_depth_plane_buffer_memory, agc_driver_depth_plane_partial_store, agc_driver_depth_plane_sampling, agc_driver_depth_storage_dispatch, agc_driver_depth_surface_from_storage, agc_driver_dispatch_move_depth
VUID-VkPipelineColorBlendStateCreateInfo-pAttachments-00605 (1 test): agc_driver_prepared_exports
Skipped (45)
agc_driver_bda_reads_shadowed_results: skipped, the device reports watched host memory written when it imports or reads it
agc_driver_bda_reads_shadowed_results_per_build: skipped, the device reports watched host memory written when it imports or reads it
agc_driver_sample_order_grid_reference: skipped, the device does not keep depth drawn at custom sample locations at those locations, even after a transition that names them: the composite of uniform renders holds the guest's depth in 0 of 3005 sloped samples, so no path can be compared with it bit for bit
agc_host_import_sparse: skipped, host imports are unavailable: /dev/udmabuf is not accessible
agc_import_settle_initial_dcc: skipped, the device has no deferred settle of host imports: imports under 1 MiB wait for one only on Windows
agc_unit_shadow_completion_store: skipped, the device reports watched host memory written when it imports or reads it
guest_http_uri_locale: 
guest_net_ctl: skipped, the host has no IPv4 address
guest_video_out_color_space: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
guest_video_out_hdr: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
guest_video_out_high_frame_rate: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
guest_video_out_output_mode: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
guest_video_out_resolution_status: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
guest_video_out_wqhd_detection: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
video_out_flip_aftergpu: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_backtoback: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_controls: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_cpuflip: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_cpuflip_in_order: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_dcc: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_deferred: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_eop: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_eop_aftergpu: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_eop_main: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_fps_limit: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_o
Reproduce
git fetch origin 6cb37cc9eda523074d5fd844537c28ce2bbe6907 1d91f2966d0eef82a021628a7aa8e78e615ac807
git checkout 1d91f2966d0eef82a021628a7aa8e78e615ac807 && git merge --no-ff 6cb37cc9eda523074d5fd844537c28ce2bbe6907
git submodule update --init --recursive
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=ON -DANYPS5_ENABLE_SPIRV_TOOLS=ON
cmake --build build && cmake --build build --target libs
VK_DRIVER_FILES=/nonexistent/icd.json ctest --test-dir build -E '^(agc|shader|recompiler|videoout|video_out|guest_video_out|vulkan)|gpu' --timeout 120 --parallel 32 --output-on-failure
ANYPS5_REQUIRE_VULKAN=1 ANYPS5_NO_SHADER_CACHE=1 VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation \
  ctest --test-dir build -R '^(agc|shader|recompiler|videoout|video_out|guest_video_out|vulkan)|gpu' --timeout 120 --parallel 4 --output-on-failure
# failures are then re-run alone: --timeout 360 --parallel 2; new validation IDs: the test alone, twice, --parallel 1

Automated 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.

@github-actions github-actions Bot added the needs rebase Conflicts with main, rebase needed label Nov 3, 2026

@XairRrR XairRrR left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed — changes requested

This pull request does not merge cleanly into main (4f41f4c): head 6cb37cc conflicts in

  • core/shader/recompiler/ShaderDiskCache.hpp
  • docs/dev/debt/shader.md

Please rebase it onto current main. I will review the change once it merges cleanly.

@github-actions github-actions Bot removed the review queue Next in the maintainer review queue: checks pass, no open change request, no conflict label Nov 3, 2026
@github-actions github-actions Bot removed the needs rebase Conflicts with main, rebase needed label Nov 3, 2026

@XairRrR XairRrR left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-checked — approved

Since e04a705 the PR has fixed the test wording, extended the per-snapshot descriptor-epoch check to a nested S# table that is the shader's only table (with a new test), put libc on PATH for both nested retry tests on Windows, moved to FormatVersion 63, and resolved #12246's resourceViews loop in a merge. The checks pass, the focused tests pass, and the new test fails without the fix. I found nothing blocking.

What changed since my last review

  • 4769d5a: removes "and refusals" from the nested image and nested sampler success lines.
  • 967f0db: TableSnapshotter::Run() now sets hasIndirect for a sampler when its column is indirect or its heap source is itself a table column. This is the same test the image loop already used. The commit adds agc_shader_nested_sampler_snapshot_retry.
  • 5fdf20f: on Windows, puts libc's directory on PATH for both agc_shader_nested_snapshot_retry and agc_shader_nested_sampler_snapshot_retry.
  • f4781de: sets ShaderDiskCache::FormatVersion to 63. main is at 52, so this stays above it.
  • Merges of main and of #7223's 7f36e41: 6cb37cc moves #12246's resourceViews loop out of CopyRecords and back into Snapshot(). #7223's own budget-reset commit is out of this review's scope, as before.
  • Description: the version and ordering notes are updated.

What I ran

  • Head: 63b5c09df9776ccd7d0ce018dfd676931e2d7639
  • main: 4f41f4c375f5abb487dbd184fbc150f31994d762
  • Merged tree: fbf279248cc3902f161e51a442c76155374f0f4b
  • Machine: Debian 13 VM (32 vCPU, Xeon Gold 6136), GCC 14.2.0, lavapipe (Mesa 26.1.6, LLVM 19)
git diff --check 4f41f4c375f5abb487dbd184fbc150f31994d762...63b5c09df9776ccd7d0ce018dfd676931e2d7639
python3 tools/check_conventions.py --base 4f41f4c375f5abb487dbd184fbc150f31994d762
ctest --test-dir build -j8 --test-load 32 --output-on-failure \
  -R "^(agc_shader_nested_.*snapshot_retry|agc_shader_disk_cache|agc_shader_bindless|agc_shader_memory|agc_driver_image_table|agc_driver_nested_.*|agc_driver_pointer_phi_.*)$"
# negative control: in ResourceMaterializer.cpp, the sampler loop's hasIndirect line reverted to `hasIndirect |= column.indirect;`
ninja -C build -j32 -l32 agc_shader_memory_tests
ctest --test-dir build --output-on-failure -R "^agc_shader_nested_(sampler_)?snapshot_retry$"
git show fbf279248cc3902f161e51a442c76155374f0f4b:core/shader/recompiler/Optimization/src/ResourceMaterializer.cpp > core/shader/recompiler/Optimization/src/ResourceMaterializer.cpp
ninja -C build -j32 -l32 agc_shader_memory_tests
ctest --test-dir build -R "^agc_shader_nested_(sampler_)?snapshot_retry$"
git status --porcelain   # empty
Check Result
git diff --check No output
check_conventions.py All conventions checks passed.
Build and selected tests (script, merged tree) Build OK; 2223 run, no new failures and no timeouts. The 7 known failures also fail on main.
Validation layer (script) Loaded in 776 of 777 tests; 0 tests with new VUID- lines; layer_missing_in empty
Focused set (13 tests) 13 of 13 pass. The slowest is agc_shader_disk_cache at 6.4 s.
Negative control agc_shader_nested_sampler_snapshot_retry fails with nested retry: expected inner retry and outer revalidation. #7223's agc_shader_nested_snapshot_retry still passes. After the restore, both pass and the worktree is clean.

Previous findings

  1. Summary lines claimed refusal checks — Resolved. 4769d5a removes "and refusals" from both lines. grep refusals finds nothing in ImageTable.cpp at the head.
  2. Stale version and ordering notes in the description — Resolved. The description now says 63 (the code has 63, and main has 52) and names #7223's 7f36e41 in the Ordering paragraph. Two small leftovers: the first checklist line still says "merged with #7223's head 0dbf547 (main f7e84c4)", and the Version bumps paragraph still says main is at 51 (it is at 52). Neither needs to block.

New findings

Blocking

None.

Non-blocking

  1. Nested child T#s skip #12246's registered 1D-array view normalization. CopyRecords builds nested children (core/shader/recompiler/Optimization/src/ResourceMaterializer.cpp:1490), and only Snapshot() fills resourceViews (:1502-1510). For an image reached through a nested child, the materializer therefore always uses the child's raw words (:2132-2133). The merge commit argues this is exact because image.table only indexes top-level tables. However, layerRowsCompatible is set without regard to how the T# is reached (core/shader/recompiler/Optimization/src/ResourceTracker.cpp:2402). So a sampled Dim1DArray T# read through record → pointer → V# would be planned as layer-rows compatible while its descriptor is neither normalized nor registered. No test covers that combination, and I did not check what the emitter does in that case.
    • Suggested fix: either compute resourceViews for nested children of a candidate image, or clear layerRowsCompatible for images whose column has a table-column heap source. Alternatively, list the gap in docs/dev/debt/shader.md.

Notes on the new code, with no change requested:

  • 967f0db mirrors the image loop exactly (ResourceMaterializer.cpp:755-763 against :746-754). plan.descriptorSources.at(column.heapSource) throws on an out-of-range source instead of reading past the end.
  • The PATH change for Windows is test registration only.

Not verified

  • Windows. I did not check the PATH fix, and the description's runs are author-reported.
  • GPUs other than lavapipe. The ANV and Intel Windows sampler-array issue (Mesa issue 16622) is unchanged since my last review.
  • #7223's own code, including its 7f36e41 budget reset, which is part of this PR's diff against main until #7223 merges.
  • Any title. Following the review rules, I launched no game.
  • Repeated runs: each test ran once.

@EagleBearerYS

Copy link
Copy Markdown
Contributor Author

Thanks for the re-check.

@TechLevelZero

Copy link
Copy Markdown
Contributor

✅ NVIDIA GPU test: passed

PR head 63b5c09 merged onto main 4f41f4c · tested 2026-11-03 15:17 UTC · 24 min

GPU NVIDIA RTX 2000 Ada Generation, driver 595.99.02, Vulkan 1.4.329
Host Ubuntu 26.04.1 LTS, kernel 7.0.0-38-generic, container ubuntu:24.04
Logs build and test logs for this run
Build ✅ passed (Release, -DANYPS5_ENABLE_SPIRV_TOOLS=ON)
Tests ✅ 2,769 passed · 7 failed (0 new, 3 also fail on main, 4 unstable on main) · 48 skipped (ANYPS5_REQUIRE_VULKAN=1)
Test setup CPU-only tests without a GPU; GPU tests (and any CPU-only test that failed or skipped without one) once on the GPU with VK_LAYER_KHRONOS_validation and ANYPS5_NO_SHADER_CACHE=1; main ran the same way
Test selection 2,824 of 3,811 tests run: the ones this change can reach, chosen by tools/select_tests.py from main's build graph
Vulkan validation ✅ no new validation IDs vs main (940 tests run on the GPU)
Slow tests (>30 s, GPU tests timed with validation layers) ⚠️ agc_driver_pipeline_journal 120.1 s
Unstable on main (4, these also failed in recent main runs on this machine; not counted against this PR)
agc_driver_pipeline_journal: failed in 4 of the last 10 main runs
agc_driver_submit_progress: failed in 5 of the last 10 main runs
agc_submit_progress: failed in 6 of the last 10 main runs
agc_submit_progress_no_timeline: failed in 5 of the last 10 main runs
Failing on main too (3, not counted against this PR)
agc_driver_image_table
guest_mmap_executable
guest_socket_options_multicast
Validated but not compared (2, not in the main baseline's validation pass)
agc_shader_nested_sampler_snapshot_retry
agc_shader_nested_snapshot_retry
Validation IDs already present on main (4 IDs in 519 tests)
VUID-VkDeviceCreateInfo-pNext-pNext (519 tests): agc_driver, agc_driver_address_passes, agc_driver_alias_copy_label, agc_driver_alpha_to_coverage, agc_driver_array_layer_target, agc_driver_bc_block_copy, agc_driver_bda_anchor_reads, agc_driver_bda_span_reads, and 511 more
VUID-vkCmdCopyImage-srcImage-01548 (9 tests): agc_driver_depth_clear_hle, agc_driver_depth_plane_buffer_memory, agc_driver_depth_plane_partial_store, agc_driver_depth_plane_sampling, agc_driver_depth_storage_dispatch, agc_driver_depth_surface_from_storage, agc_driver_dispatch_move_depth, agc_driver_stencil_null_feedback, and 1 more
VUID-vkCmdCopyImage-srcImage-01551 (9 tests): agc_driver_depth_clear_hle, agc_driver_depth_plane_buffer_memory, agc_driver_depth_plane_partial_store, agc_driver_depth_plane_sampling, agc_driver_depth_storage_dispatch, agc_driver_depth_surface_from_storage, agc_driver_dispatch_move_depth, agc_driver_stencil_null_feedback, and 1 more
VUID-VkPipelineColorBlendStateCreateInfo-pAttachments-00605 (1 test): agc_driver_srgb8_color_target
Skipped (48)
agc_driver_bda_reads_shadowed_results: skipped, the device reports watched host memory written when it imports or reads it
agc_driver_bda_reads_shadowed_results_per_build: skipped, the device reports watched host memory written when it imports or reads it
agc_driver_sample_order_grid_reference: skipped, the device does not keep depth drawn at custom sample locations at those locations, even after a transition that names them: the composite of uniform renders holds the guest's depth in 0 of 3005 sloped samples, so no path can be compared with it bit for bit
agc_driver_scattered_runs: skipped, host imports are unavailable: /dev/udmabuf is not accessible
agc_driver_sparse_dma_buf_import: skipped, host imports are unavailable: /dev/udmabuf is not accessible
agc_driver_stencil_ref_export: skipped, the device lacks VK_EXT_shader_stencil_export
agc_host_import_sparse: skipped, host imports are unavailable: /dev/udmabuf is not accessible
agc_import_settle_initial_dcc: skipped, the device has no deferred settle of host imports: imports under 1 MiB wait for one only on Windows
agc_unit_shadow_completion_store: skipped, the device reports watched host memory written when it imports or reads it
guest_http_uri_locale: 
guest_net_ctl: skipped, the host has no IPv4 address
guest_video_out_color_space: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
guest_video_out_hdr: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
guest_video_out_high_frame_rate: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
guest_video_out_output_mode: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
guest_video_out_resolution_status: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
guest_video_out_wqhd_detection: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
video_out_flip_aftergpu: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_backtoback: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_controls: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_cpuflip: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_cpuflip_in_order: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_dcc: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_deferred: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_eop: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_eop_aftergpu: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_eop_main: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not co
Reproduce
git fetch origin 63b5c09df9776ccd7d0ce018dfd676931e2d7639 4f41f4c375f5abb487dbd184fbc150f31994d762
git checkout 4f41f4c375f5abb487dbd184fbc150f31994d762 && git merge --no-ff 63b5c09df9776ccd7d0ce018dfd676931e2d7639
git submodule update --init --recursive
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=ON -DANYPS5_ENABLE_SPIRV_TOOLS=ON
cmake --build build && cmake --build build --target libs
VK_DRIVER_FILES=/nonexistent/icd.json ctest --test-dir build -E '^(agc|shader|recompiler|videoout|video_out|guest_video_out|vulkan)|gpu' --timeout 120 --parallel 32 --output-on-failure
ANYPS5_REQUIRE_VULKAN=1 ANYPS5_NO_SHADER_CACHE=1 VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation \
  ctest --test-dir build -R '^(agc|shader|recompiler|videoout|video_out|guest_video_out|vulkan)|gpu' --timeout 120 --parallel 4 --output-on-failure
# failures are then re-run alone: --timeout 360 --parallel 2; new validation IDs: the test alone, twice, --parallel 1

Automated 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.

@github-actions github-actions Bot added the needs rebase Conflicts with main, rebase needed label Nov 4, 2026
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.
@github-actions github-actions Bot removed the needs rebase Conflicts with main, rebase needed label Nov 4, 2026
@TechLevelZero

Copy link
Copy Markdown
Contributor

✅ NVIDIA GPU test: passed

PR head 014d1e3 merged onto main 5b1d381 · tested 2026-11-04 09:40 UTC · 38 min

GPU NVIDIA RTX 2000 Ada Generation, driver 595.99.02, Vulkan 1.4.329
Host Ubuntu 26.04.1 LTS, kernel 7.0.0-38-generic, container ubuntu:24.04
Logs build and test logs for this run
Build ✅ passed (Release, -DANYPS5_ENABLE_SPIRV_TOOLS=ON)
Tests ✅ 2,840 passed · 5 failed (0 new, 3 also fail on main, 2 unstable on main) · 49 skipped (ANYPS5_REQUIRE_VULKAN=1)
Test setup CPU-only tests without a GPU; GPU tests (and any CPU-only test that failed or skipped without one) once on the GPU with VK_LAYER_KHRONOS_validation and ANYPS5_NO_SHADER_CACHE=1; main ran the same way
Test selection 2,894 of 3,883 tests run: the ones this change can reach, chosen by tools/select_tests.py from main's build graph
Vulkan validation ✅ no new validation IDs vs main (980 tests run on the GPU)
Slow tests (>30 s, GPU tests timed with validation layers) ⚠️ agc_driver_pipeline_journal 120.1 s
Unstable on main (2, these also failed in recent main runs on this machine; not counted against this PR)
agc_driver_pipeline_journal: failed in 3 of the last 10 main runs
agc_submit_progress_no_timeline: failed in 3 of the last 10 main runs
Failing on main too (3, not counted against this PR)
agc_driver_image_table
guest_mmap_executable
guest_socket_options_multicast
Validated but not compared (1, not in the main baseline's validation pass)
agc_shader_nested_sampler_snapshot_retry
Validation IDs already present on main (13 IDs in 544 tests)
VUID-VkDeviceCreateInfo-pNext-pNext (544 tests): agc_driver, agc_driver_address_passes, agc_driver_alias_copy_label, agc_driver_alpha_to_coverage, agc_driver_array_layer_target, agc_driver_bc_block_copy, agc_driver_bda_anchor_reads, agc_driver_bda_span_reads, and 536 more
VUID-VkShaderModuleCreateInfo-pCode-08737 (8 tests): agc_driver_dpp16_operands, agc_driver_dpp8_pk_fmac, agc_driver_dx10_clamp, agc_driver_float16_fma_rounding, agc_driver_float16_unused_nan_payloads, agc_driver_packed_alu, agc_driver_packed_f16_denormal_modes, agc_driver_packed_float16_native
VUID-VkShaderModuleCreateInfo-pCode-08739 (8 tests): agc_driver_dpp16_operands, agc_driver_dpp8_pk_fmac, agc_driver_dx10_clamp, agc_driver_float16_fma_rounding, agc_driver_float16_unused_nan_payloads, agc_driver_packed_alu, agc_driver_packed_f16_denormal_modes, agc_driver_packed_float16_native
VUID-VkShaderModuleCreateInfo-pCode-08741 (8 tests): agc_driver_dpp16_operands, agc_driver_dpp8_pk_fmac, agc_driver_dx10_clamp, agc_driver_float16_fma_rounding, agc_driver_float16_unused_nan_payloads, agc_driver_packed_alu, agc_driver_packed_f16_denormal_modes, agc_driver_packed_float16_native
VUID-vkCmdCopyImage-srcImage-01548 (7 tests): agc_driver_depth_clear_hle, agc_driver_depth_plane_buffer_memory, agc_driver_depth_plane_partial_store, agc_driver_depth_plane_sampling, agc_driver_depth_storage_dispatch, agc_driver_depth_surface_from_storage, agc_driver_dispatch_move_depth
VUID-vkCmdCopyImage-srcImage-01551 (7 tests): agc_driver_depth_clear_hle, agc_driver_depth_plane_buffer_memory, agc_driver_depth_plane_partial_store, agc_driver_depth_plane_sampling, agc_driver_depth_storage_dispatch, agc_driver_depth_surface_from_storage, agc_driver_dispatch_move_depth
VUID-VkPipelineColorBlendStateCreateInfo-pAttachments-00605 (2 tests): agc_driver_prepared_exports, agc_driver_srgb8_color_target
VUID-VkPipelineShaderStageCreateInfo-module-parameter (1 test): agc_driver_float16_unused_nan_payloads
VUID-VkPipelineShaderStageCreateInfo-pSpecializationInfo-06849 (1 test): agc_driver_float16_unused_nan_payloads
VUID-VkSamplerCreateInfo-addressModeU-01079 (1 test): agc_driver_image_gather_volume
VUID-VkSamplerCreateInfo-addressModeU-parameter (1 test): agc_driver_image_gather_volume
VUID-VkSamplerCreateInfo-addressModeV-parameter (1 test): agc_driver_image_gather_volume
VUID-VkSamplerCreateInfo-addressModeW-parameter (1 test): agc_driver_image_gather_volume
Skipped (49)
agc_driver_bda_reads_shadowed_results: skipped, the device reports watched host memory written when it imports or reads it
agc_driver_bda_reads_shadowed_results_per_build: skipped, the device reports watched host memory written when it imports or reads it
agc_driver_gcn_display_present: skipped, no display: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
agc_driver_sample_order_grid_reference: skipped, the device does not keep depth drawn at custom sample locations at those locations, even after a transition that names them: the composite of uniform renders holds the guest's depth in 0 of 3005 sloped samples, so no path can be compared with it bit for bit
agc_driver_scattered_runs: skipped, host imports are unavailable: /dev/udmabuf is not accessible
agc_driver_sparse_dma_buf_import: skipped, host imports are unavailable: /dev/udmabuf is not accessible
agc_driver_stencil_ref_export: skipped, the device lacks VK_EXT_shader_stencil_export
agc_host_import_sparse: skipped, host imports are unavailable: /dev/udmabuf is not accessible
agc_import_settle_initial_dcc: skipped, the device has no deferred settle of host imports: imports under 1 MiB wait for one only on Windows
agc_unit_shadow_completion_store: skipped, the device reports watched host memory written when it imports or reads it
guest_http_uri_locale: 
guest_net_ctl: skipped, the host has no IPv4 address
guest_video_out_color_space: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
guest_video_out_hdr: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
guest_video_out_high_frame_rate: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
guest_video_out_output_mode: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
guest_video_out_resolution_status: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
guest_video_out_wqhd_detection: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
video_out_flip_aftergpu: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_backtoback: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_controls: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_cpuflip: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_cpuflip_in_order: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_dcc: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_deferred: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_eop: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_eop_aftergpu: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not av
Reproduce
git fetch origin 014d1e30c3a298376e60842b641e9fbb69e186b6 5b1d381d5ad5d9f923326b18479c3bd889cdd588
git checkout 5b1d381d5ad5d9f923326b18479c3bd889cdd588 && git merge --no-ff 014d1e30c3a298376e60842b641e9fbb69e186b6
git submodule update --init --recursive
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=ON -DANYPS5_ENABLE_SPIRV_TOOLS=ON
cmake --build build && cmake --build build --target libs
VK_DRIVER_FILES=/nonexistent/icd.json ctest --test-dir build -E '^(agc|shader|recompiler|videoout|video_out|guest_video_out|vulkan)|gpu' --timeout 120 --parallel 32 --output-on-failure
ANYPS5_REQUIRE_VULKAN=1 ANYPS5_NO_SHADER_CACHE=1 VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation \
  ctest --test-dir build -R '^(agc|shader|recompiler|videoout|video_out|guest_video_out|vulkan)|gpu' --timeout 120 --parallel 4 --output-on-failure
# failures are then re-run alone: --timeout 360 --parallel 2; new validation IDs: the test alone, twice, --parallel 1

Automated 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.

hugodearaujo pushed a commit to hugodearaujo/AnyPS5 that referenced this pull request Nov 4, 2026
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.
hugodearaujo pushed a commit to hugodearaujo/AnyPS5 that referenced this pull request Nov 4, 2026
4769d4a is boykopovar#8939 with boykopovar#7395's merge of main after boykopovar#7223. The one
conflict is this branch's FormatVersion 67.
hugodearaujo pushed a commit to hugodearaujo/AnyPS5 that referenced this pull request Nov 4, 2026
…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.
hugodearaujo pushed a commit to hugodearaujo/AnyPS5 that referenced this pull request Nov 4, 2026
b41beed is boykopovar#9790 with the stack's merges of boykopovar#7395's main merge after
boykopovar#7223. FormatVersion stays this branch's 73, and the debt file keeps this
branch's three entries, with boykopovar#7395's "Nested image table children" entry
added after "Nested image tables".
liskeee pushed a commit to liskeee/AnyPS5 that referenced this pull request Nov 5, 2026
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.
liskeee pushed a commit to liskeee/AnyPS5 that referenced this pull request Nov 5, 2026
…ords-on-c2

f498717 is boykopovar#9633 with the stack's merges of boykopovar#7395's main merge after
boykopovar#7223. The conflicts are this branch's own: FormatVersion 72 and its
wording of the pointer-keyed chase debt entry.
@mrfelek

mrfelek commented Nov 6, 2026

Copy link
Copy Markdown
Contributor

PPSA03671: head 014d1e30c3 doesn't resolve the S# in compute shader 0x11d049aa00 (pc=0xb600)

RTX 3080 Ti, NVIDIA 615.71.09, Linux, PPSA03671 01.001.005, from launch with no input.

The tree: main c36ab99c74 + #12575 + #12746, plus this PR at 014d1e30c3 (clean merge, one conflict in ImageTableAbi.hpp's Version, taken as 4). To get this far on NVIDIA I also need local changes:

  • for the stencil-export replay;
  • for an image-table prototype (driver-side table resolution, plus a usage write in the SPIR-V emitter's table access).

None of them touches the recompiler's descriptor planning. I can't check this shader without them, because the run stops earlier on the stencil export.

The result: with the shader cache off, the run stops about 150 s in, after the intro logos, with the same error with and without this PR:

compute shader 0x11d049aa00: shader 0x11d049aa00 stage 0: ShaderRecompiler::Recompile: GetSamplerResource dword 0 is not a valid runtime value; chain: ReadConstBuffer@pc=0x0000b600(GetBufferResource(LoadAddressU32@pc=0x0000b5f0(GetAddressResource(ReadConstBuffer@pc=0x00002454(GetBufferResource(ReadConst(GetSrtResource, Immediate) x4), ShiftLeftLogical32(ReadFirstLane(SelectU32(LogicalAnd, IAdd32, Phi), Phi(LogicalAnd, LogicalAnd)), Immediate)), ReadConstBuffer@pc=0x00002454(...same...)), Immediate, Immediate, Immediate), LoadAddressU32@pc=0x0000b5f0(...same...), ...

How it compares with your example. The PR's Wolverine example has the S# read at pc=0x0000bb28 through LoadAddressU32@pc=0x0000bb18. Here it's pc=0x0000b600 through LoadAddressU32@pc=0x0000b5f0, with the same table read at pc=0x00002454. The key is ShiftLeftLogical32(ReadFirstLane(SelectU32(LogicalAnd, IAdd32, Phi), Phi(LogicalAnd, LogicalAnd)), Immediate):

  • the selected value is an IAdd32 or a Phi;
  • the ReadFirstLane's second argument (the EXEC it reads under) is itself a Phi of two LogicalAnds.

So it may be the same shader at another variant, or a second copy of the sampler path the PR doesn't match yet. The same shader is the one j2m304 reported on Windows in #5516 (the freeze "while preparing compute shader 11d049aa00").

I can capture the shader with APS5_DUMP_SHADERS or dump its IR if that helps.

AI-assisted.

@EagleBearerYS

Copy link
Copy Markdown
Contributor Author

@mrfelek thanks for the run. This is the shape the PR's first commit targets. The S# read at pc=0xb600 comes from a V# loaded at pc=0xb5f0 through the record pointer read at pc=0x2454: the same record → pointer → V# → S# chain as Capmare's pc=0xbb28 line in the description. Capmare's run of an earlier head (59b319a) had no GetSamplerResource refusal. So I'm checking whether this key, SelectU32(LogicalAnd, IAdd32, Phi) read under a Phi EXEC, or something that changed on this branch since then, keeps this one from planning. The log line is enough for that, so no shader capture is needed.

@EagleBearerYS

EagleBearerYS commented Nov 6, 2026 •

Copy link
Copy Markdown
Contributor Author

@mrfelek here's what the check found. It's not the key, and it isn't a regression on this branch.

If you have the time, two things would tell them apart:

No shader capture is needed for either.

Edit, 2026-11-06 14:43 UTC: the last bullet used to say that case 2 crashes at dispatch on lavapipe after planning, and that a crash after the stop clears would point at case 2. That crash came from our test, not from the PR: the test hadn't mapped the record's memory for that read. With it mapped, case 2 and its T# counterpart plan and sample correctly on both heads.

@mrfelek

mrfelek commented Nov 6, 2026 •

Copy link
Copy Markdown
Contributor

@EagleBearerYS thanks. I did both checks offline. I captured the shader with APS5_DUMP_SHADERS=11d049aa00, and its .prepare.req reproduces the stop with agc_shader_replay in about a second.

On #9969's head (c147aa8647), the pc=0xb600 S# stop is gone. The same request now stops later, at a T#:

resource analysis failed: GetImageResource dword 0 is not a valid runtime value; chain: ReadConstBuffer@pc=0x0000b9f8(GetBufferResource(LoadAddressU32@pc=0x0000b9cc(GetAddressResource(Phi(Phi(ReadConstBuffer@pc=0x00002454(GetBufferResource(ReadConst, ReadConst, ReadConst, ReadConst), ShiftLeftLogical32(ReadFirstLane, Immediate)), Phi(ReadConstBuffer@pc=0x00002454(GetBufferResource, ShiftLeftLogical32), Phi(ReadConstBuffer@pc=0x00002454, LoadAddressU32@pc=0x0000b6a0))), ReadConstBuffer@pc=0x00002454(...), ShiftLeftLogical32(ReadFirstLane(SelectU32, Phi), Immediate))), ...

The rest of the original line. The S#'s own offset is an immediate. In the IR after the srt pass (dumped on the tree from my first comment):

%11455 = GetAddressResource %7684, %7685                                    P = record words 2..3 (pc=0x2454, off 0x8/0xc)
%11456..%11459 = LoadAddressU32 %11455  [pc=0xb5f0 off=0x20..0x2c]         V# at P+0x20
%11464 = GetBufferResource %11456..%11459                                   uses=4
%11465..%11468 = ReadConstBuffer %11464, 0  [pc=0xb600 off=0x30..0x3c]     the S#, one use per word
%11571 = GetSamplerResource %11465..%11468                                  sampled at pc=0xb674

From the IR, it doesn't look like any of your three cases:

  • The V# isn't also read as a plain buffer: its 4 uses are the 4 S# word reads.
  • No S# word has a second user.
  • The T# sampled with it comes from a different V#: that one is loaded at pc=0xb65c from P+0x10 and read at offset ReadFirstLane(...) << 5.

Yet #9969 plans it, so one of the stacked PRs covers it in a way I can't see from the IR.

The new stop at pc=0xb9f8:

%12257 = Phi [%12206, ...], [%7684, ...]                                    pointer low word
         %12206 = Phi [%7684, ...], [%12163, ...]
%12465 = GetAddressResource %12257, %12256                                  P'
%12466..%12469 = LoadAddressU32 %12465  [pc=0xb9cc off=0x20..0x2c]         V# at P'+0x20
%12492..%12499 = ReadConstBuffer %12491, 0  [pc=0xb9f8 off=0xe0..0xfc]     the T#, immediate offset

It's the same record → pointer → V# → descriptor shape, but the pointer is now a Phi:

  • either the record's own pointer, P;
  • or a pointer read from the record's data, the LoadAddressU32@pc=0x0000b6a0 words at P+0x30/0x34.

So it looks like a child or linked record, reached through a pointer stored in the record.

I can re-run the request locally on any head you'd like me to try.

AI-assisted.

@EagleBearerYS

Copy link
Copy Markdown
Contributor Author

@mrfelek thanks, that's very useful. The IR excerpts answer what the log line couldn't. There's no need to attach the .prepare.req, here or in #9969: the excerpts you posted are enough for us to work from. We'll look at why #9969 plans the pc=0xb600 S# when none of the three cases apply, and at the new pc=0xb9f8 stop.

@EagleBearerYS

Copy link
Copy Markdown
Contributor Author

@mrfelek thanks, your IR answers both questions.

Why pc=0xb600 plans on #9969 but not on this PR alone. The S# sits at a fixed offset of its V#: ReadConstBuffer %11464, 0 reads 0x30..0x3c. It isn't at a keyed offset. This PR's nested path takes a child descriptor only at a keyed offset (a key times a stride, plus an addend). An immediate offset matches none of those shapes, so the S# falls back to the refusal you saw.

#9457's second commit (0843cca, hugodearaujo's change from Marvel's Spider-Man 2 (PPSA03016)) reads a descriptor at a fixed offset of a pointer-loaded V# as a one-key child: key 0, the descriptor size as stride, the immediate as addend. It does that for T#s and S#s alike, and that's what plans this S# on #9969's head. #8939 and #9790 deal with pointer words merged through Phis and with descriptors that have other users, and your IR has neither. So none of the three cases in my earlier comment applied. The difference was the S#'s own offset, the part the synthetic shader had to guess. That attribution comes from reading the code; your replay on #9969 is what shows it plans.

The new stop at pc=0xb9f8. The T# there is the same kind of fixed-offset child (0xe0..0xfc of the V# at P'+0x20), which #9457 also handles. What refuses is the pointer P'. It's either the record's own pointer P, or the pointer stored at P+0x30/0x34 and loaded directly through P (LoadAddressU32@pc=0x0000b6a0). The stack has two neighbouring pieces, and neither takes this shape:

Taking it would need a third kind of chase step in the planner, in the snapshot that follows pointers at dispatch, and in the disk cache, so it isn't a small change. None of our open PRs covers it yet. We've noted it as Marvel's Wolverine (PPSA03671)'s next stop on this stack.

@mrfelek

mrfelek commented Nov 6, 2026

Copy link
Copy Markdown
Contributor

Thanks. For the record, the game agrees with the replay. On #9969's head plus our local stencil and image-table changes, PPSA03671 gets past pc=0xb600 and stops 148 s in on the RTX 3080 Ti at the pc=0xb9f8 T#. I also merged #9633 and #9749 onto #9969 locally, and the replay stops at the same place, as you expected. I'll re-test as soon as there's a head with the new chase step.

AI-assisted.

@mrfelek

mrfelek commented Nov 6, 2026

Copy link
Copy Markdown
Contributor

@EagleBearerYS I tried the chase step locally to see what's behind it. Here's what I found, in case it saves you time. It's only a prototype, on #9969 + #9633 + #9749 (merged locally) and our local stencil and image-table changes. It's checked with agc_shader_replay on the captured request, and in the game on the RTX 3080 Ti.

1. pc=0xb9f8: a direct chase step is enough. I gave PointerChase a direct flag. The next pointer is then two LoadAddressU32s straight through the current pointer, the low word at (offset, immediate) and the high word at (offset, readHighImmediate), with no V# in between:

  • The tracker: PointerRecordPairs' walk takes such a pair as a chase arm, before it tries ChaseRead. The site's pointer is the GetAddressResource itself, so the inner walk goes on from its words.
  • Chase(): a direct step reads the two words at ScalarAddressDword(pointer, offset, immediate / readHighImmediate) and adds both to the snapshot ranges.
  • The disk cache: the flag is carried.

About 40 lines. With it, the replay gets past pc=0xb9f8. So does the game: it stopped 168 s in, at the next T#, pc=0xd0f0.

2. pc=0xd0f0: linked records. The pointer there is P'' = P' or the pointer at P'+0x10 (LoadAddressU32@pc=0x0000baa8), another direct step that (1) now takes. The T# is keyed in the V# at P''+0x10 (pc=0xd0cc). What refuses is in TryMakeTableColumn: a user of a parent V# word that isn't a GetBufferResource.

%20169..%20172 = LoadAddressU32 %20168  [pc=0xd0cc off=0x10..0x1c]   V# at P''+0x10
%20180 = GetBufferResource %20169, %20170, %20171, %20172
%20614 = Phi [%20170, ...], [%20392, ...]
%21191 = Phi [%13015, ...], [%20614, ...]                           %13015: the high word of P''

So the words at +0x10/0x14 are both this V#'s base and the next node's pointer: the shader walks a linked list of records. Locally, I let that check accept a Phi user. With that, the replay gets past pc=0xd0f0. That's only a hack: a real version would have to prove that the Phi feeds a chased pointer.

3. pc=0xef7c: pointers from a second record table. This is the stop I can't take with small changes. One arm of that pointer's Phi is a record read like pc=0x2454's, but from a different table:

%15993 = GetAddressResource %13016, %13015                           P''
%15994..%15997 = LoadAddressU32 %15993  [pc=0xc948 off=0x60..0x6c]   V# at P''+0x60
%16000..%16003 = ReadConstBuffer %15999, 0  [pc=0xc954 off=0x560..0x56c]   a V# read from that buffer
%21742 = GetBufferResource %16000..%16003
%21743, %21744 = ReadConstBuffer %21742, %16223 << 4  [pc=0xdcec off=0x8, 0xc]   pointer from its 16-byte records

PointerRecordRead keeps the pointer-keyed column to one record table, and refuses this one as another column. I see two ways to take it:

  • a column that collects its pointers from several tables, one of them nested behind a chased pointer;
  • a separate nested column whose pointers feed the first one.

Either is more than I'd want to try in a prototype.

The prototype is on a local branch. I can push it to our fork if you'd like to see it, or test anything you push on the captured request first and then in the game.

AI-assisted.

@EagleBearerYS

EagleBearerYS commented Nov 6, 2026 •

Copy link
Copy Markdown
Contributor Author

@mrfelek thank you, that's a clear map of what sits behind pc=0xb9f8 in Marvel's Wolverine (PPSA03671). It also shows that the chase step on its own isn't enough. After it, the game stops at pc=0xd0f0, the linked records, which your local Phi change gets past without proving that the Phi feeds a chased pointer, as you say. Then it stops at pc=0xef7c, which needs a column that takes its pointers from more than one record table.

That's more than we can take on right now. Our current work is keeping the open PRs up to date, so please don't wait for a head with the chase step from us. There's no need to push the prototype for us.

If you'd like to take the direct step further yourself, it would fit as your own PR on top of #9749: PointerChase comes from #9633, and #9749 adds readHighImmediate. It would take Depends on: #9749, tested with #9969 merged on so that it gets past pc=0xb600. If you open one, link it here and we'll mention it in #7395's description next to these stops.

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 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.