Skip to content

fix(shader): put the compute wave index in TG_SIZE[11:6] - #5214

Merged
adriadam10 merged 1 commit into
boykopovar:mainfrom
houcineBen:fix/agc-tg-size-wave-id
Oct 14, 2026
Merged

adriadam10 merged 1 commit into
boykopovar:mainfrom
houcineBen:fix/agc-tg-size-wave-id

Conversation

@houcineBen

@houcineBen houcineBen commented Oct 13, 2026 •

Copy link
Copy Markdown

What

A compute wave with TG_SIZE_EN found its index in the workgroup only at bit 20 of the TG_SIZE SGPR. GCN and RDNA code reads it from bits [11:6]: ACO lowers load_subgroup_id to s_bfe_u32 tg_size, 6 | 6 << 16 (Mesa src/amd/compiler/instruction_selection, GFX10/GFX11 compute path). Every wave of such a shader read 0 there, so it took itself for wave 0.

The prologue now also writes the wave index to [11:6]. The bit-20 copy, the wave count in [5:0] and bit 31 are unchanged.

Seen on a RADV (Mesa 26.2) build running on AnyPS5: the radix sort's prefix sums across waves lost every carry but wave 0's, the sorted keys were garbage, and the PLOC BVH build that reads them spun forever in its task loop (host GPU hang, Windows TDR / VK_ERROR_DEVICE_LOST). With the fix the sort matches a CPU sort and PLOC completes, offline from a captured dispatch and in the title.

Test: agc_driver_tg_size_wave_id runs a 256-thread compute group in wave64 and wave32; every thread stores s_bfe_u32 TG_SIZE, 0x60006 and must read thread / wave size. It fails on main (every thread reads 0) and passes with the change.

Tested

Windows 11, NVIDIA RTX 4060 Ti, MinGW GCC 15.2.

  • agc_driver_tg_size_wave_id: fails before, passes after.
  • Full ctest on this branch: 1073 passed, 7 skipped (offscreen video-out and an unsupported stencil export), 0 failed. patched_libraries and windows_fixed_base failed once under -j8 (DLL load error 127 from the shell PATH, 5 s subprocess timeout) and pass when rerun alone.
  • vkQuake (LibreQuake) homebrew PPSA99010: map load gets past the RADV BVH builds (~517 dispatches that hung before) and the demo plays in-game. It still needs separate fixes (shader compile time) that are not part of this PR.

Not verified on PS5 hardware; the source is the ACO lowering above.

Checklist

  • Based on current main; no other open PR implements the same functions
  • One topic per PR; follow-ups go in a new PR
  • No comments in code except technical debt
  • Unimplemented paths throw (NotImplemented_nid_no_patch); silent stubs are listed under Silent stubs in their library's technical debt file
  • No notes, investigation .md files or images added to the repository (attach them to this PR)
  • New third-party code is a submodule built from source
  • Generic behaviour, not specific to one title
  • Depends on: none
  • Unblocks: none
  • AI-assisted: yes

🤖 Generated with Claude Code

@github-actions github-actions Bot added shader core/shader agc libSceAgc* labels Oct 13, 2026
GCN and RDNA code reads a compute wave's index in its workgroup from
TG_SIZE[11:6] (ACO: s_bfe_u32 tg_size, 6 | 6 << 16). The prologue wrote
it only at bit 20, so every wave read 0 there and cross-wave reductions
such as RADV's radix sort lost the carries of all but wave 0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@houcineBen
houcineBen force-pushed the fix/agc-tg-size-wave-id branch from 1b7350c to 3124895 Compare October 13, 2026 15:42
@iDiesIrae-Req

Copy link
Copy Markdown

Ran this against vkQuake (PPSA99010) with RT shadows on, which builds acceleration structures through the title's RADV port. Setup: Windows 11, RTX 4070 Laptop (driver 32.0.16.1714), WinLibs GCC 15.2.0 r7, Release, main 61b8742 with #5177, this PR and #5180 merged locally, plus a local change that gives unregistered compute shaders their FLOAT_MODE from the live COMPUTE_PGM_RSRC1 (described on #5180). That change gets the title past the #981 s_round_mode throw, so it reaches its RT pass.

On 3 of 3 runs it still stops after 12 presented frames: radv/ps5: the GPU has not reached submission 18 (at 17) in 10 s. It doesn't look like a GPU hang, though:

  • The busy thread: one thread sits at 100% of a core for the whole run. gdb shows it inside NVIDIA's shader compiler (nvgpucomp64.dll), called from vkGetInstanceProcAddr / vkEnumerateInstanceLayerProperties frames in nvoglv64.dll, under AgcDriver::VulkanDevice::dispatch.
  • No sign of finishing: after 180 s that thread had used 172 s of CPU, and the title was still on 12 frames.
  • No driver error: the host reports no device loss or TDR, and fix(agc): print a GPU queue worker failure when it is first stored #5177 prints no [gpu] driver failure.

The last shader prepared before the stall is the RT compute shader 0x20bf82000 (was not registered; preparing its artifact at dispatch). So on this setup the stop is NVIDIA's compiler taking minutes over pipeline creation for that shader. The title's 10 s fence wait runs out first. This is likely the same thing nicolasfalesy saw on ANV on #1578 ("deep in recursive frames inside libvulkan_intel.so (it looks like a shader compile)").

So this PR doesn't change vkQuake's stop here. It may still be needed once the pipeline compiles, but I can't reach that point to check.

AI-assisted: yes (Claude Code); all runs were on my machine.

@houcineBen

Copy link
Copy Markdown
Author

Thanks for testing. That compile stop is the first wall we hit too, before the one this PR fixes. On an RTX 4060 Ti the RADV acceleration-structure compute shaders took 58 s and ~530 s in NVIDIA's compiler. We got past it by letting one run finish those compiles into the pipeline cache (shader_cache/vk-pipelines*, saved periodically, so don't kill the process early). With the cache warm, the acceleration-structure builds pass in milliseconds.

The next stop was a real GPU hang (Windows TDR / VK_ERROR_DEVICE_LOST) in the PLOC BVH build 0x20136db00. Its radix-sort input was garbage, because every wave read wave 0 from TG_SIZE[11:6]. With this PR the sort matches a CPU sort, PLOC completes, and vkQuake gets past its ~517 BVH dispatches. After that it stops on a ~5 min AnyPS5 recompile of 0x20134f400 (structurizer; #5028 plus a small follow-up brings it to 0.7 s), and then the demo plays.

The bug doesn't depend on vkQuake: agc_driver_tg_size_wave_id fails on main (wave64 thread 64 read wave 0 from TG_SIZE[11:6], expected 1) and passes with this PR.

@iDiesIrae-Req

Copy link
Copy Markdown

@houcineBen Thanks, that worked. I reproduced your path on an RTX 4070 Laptop (driver 32.0.16.1714), Windows 11, WinLibs GCC 15.2.0 r7, Release. Build: main 8cf6a0b with this PR, #5180, #5028 and #5177 merged locally (all clean), plus the COMPUTE_PGM_RSRC1 float-mode fallback for unregistered compute shaders from my #5180 comment. vkQuake (PPSA99010) with the shareware pak0.pak, RT shadows on (default settings).

  • Warm-up: 9 launches in a row, each kept running until the title gave up (QUAKE ERROR: vkWaitForFences failed with code -4), with the caches kept between launches. The first two launches each sat in nvgpucomp64 for about 5.5 and 4 min. Every launch after that added one or more entries: the pipeline cache grew from 3.4 MB to 12.8 MB and the AnyPS5 shader disk cache from 21 MB to 35 MB. On the 9th launch the title played through demo1 and started demo2.
  • Warm run: 60 s with RT shadows on, no has not reached, no QUAKE ERROR, no [gpu] driver failure. The title's own PS5 present lines report 33-38 fps (26-30 ms per frame), against 55-57 fps with r_rtshadows 0 on the same machine. The screenshot shows E1M1 lit correctly.

One difference from your description: on this setup the title doesn't reach the acceleration-structure builds without the float-mode part. Without it, 0x20bf82000 throws on s_round_mode 8 at pc 316 (#981). With #5180 alone it throws the "shader without a declared FLOAT_MODE" variant, because that compute shader is unregistered and RegisteredFloatMode returns nullopt (details on #5180).

AI-assisted: yes (Claude Code); all runs were on my machine.

RINNECODER added a commit to RINNECODER/AnyPS5 that referenced this pull request Oct 14, 2026
…t) (#481)

* fix(recompiler): give vertex-path shaders the NGG group info

Ported from upstream PR boykopovar#5081

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* fix(shader): put the compute wave index in TG_SIZE[11:6]

Ported from upstream PR boykopovar#5214

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* fix(shader): take the 32_AR export alpha from channel 1 as GFX10 does

Ported from upstream PR boykopovar#5110

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* fix(shader): order buffer and image memory at s_barrier

Ported from upstream PR boykopovar#5117

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* fix(shader): decode GFX10 scratch offsets as one dword

Ported from upstream PR boykopovar#5426

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* fix(shader): accept MIMG sampler tuples ending in VCC

Ported from upstream PR boykopovar#4996

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* fix(recompiler): name the attribute of an out-of-range interpolation reference

Ported from upstream PR boykopovar#5450

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* fix(shader): decode the high-half result of v_interp_p2_f16

Ported from upstream PR boykopovar#5471. The Vop3InterpDecode unit-test hunk is not ported (that test file is not on main); the execution test InterpolationF16 carries the coverage.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* fix(shader): clear the bits of inactive lanes in VALU carry-out and v_div_scale masks

Ported from upstream PR boykopovar#5162

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* fix(shader): apply the f32 output modifier and denormal flush to v_cvt_f32_f64

Ported from upstream PR boykopovar#5159

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* fix(shader): update per-invocation LDS without atomics

Ported from upstream PR boykopovar#5160. Conflicts resolved against main: kept main's barrier condition for non-LDS shared atomics; the unit-test hunk for SRT read patching (a different upstream change, not on main) is dropped.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* fix(shader): flush ds_add_f32 denormals and NaNs as the hardware does

Ported from upstream PR boykopovar#5492

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* fix(shader): run DS src2 lanes one at a time in lane order

Ported from upstream PR boykopovar#5498

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* fix(agc): compare NOT_EQUAL unordered, reject TRUNC_COORD point sampling and round the array layer half to even in color compare emulation

Ported from upstream PR boykopovar#907 (follow-up to its predecessor). Hand-applied to main's reworked emitter: NOT_EQUAL uses OpFUnordNotEqual, the array layer is clamp(roundEven(z)), and ResourceMaterializer rejects TRUNC_COORD with point filtering. The upstream execution-test rewrite is not ported (it targets a diverged test file).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* chore(shader): bump ShaderDiskCache FormatVersion to 35

The ported DS fixes add MemoryInfo::flushDenormalResults (now encoded in the plan) and new IR opcodes, so cached payloads from format 34 must not load.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* test(shader): run ported upstream execution tests on Metal through a device shim

The upstream execution tests for the ported fixes compile unchanged against a Metal stand-in for the Vulkan test device (guest buffer descriptors are mirrored into shared MTLBuffers). Covers boykopovar#5162 (VALU carry-out masks), boykopovar#5159 (v_cvt_f32_f64 result modes), boykopovar#5492 (ds_add_f32) and boykopovar#5498 (DS src2 lane order). The LdsSrc2 and LdsSrc2Wide tests use device-memory LDS, which the Metal bridge rejects, and are not registered.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* test(shader): run ported decoder and collector unit tests in the Metal build

Registers the upstream tests for boykopovar#4996, boykopovar#5426 and boykopovar#5450 (already on main's tree but not built for Metal) and a high-half decode check for boykopovar#5471.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* test(shader): check per-invocation LDS updates without atomics on the Metal recompiler

Standalone copy of the boykopovar#5160 verifyFunctionLdsUpdates check.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* test(shader): check the TG_SIZE wave index on Metal

Buffer-store variant of the boykopovar#5214 execution test.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* test(shader): run the s_barrier memory-order execution test on Metal

Registers boykopovar#5117's upstream test through the device shim.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* test(shader): draw a 32_AR export on Metal

Guest-replay draw for boykopovar#5110: alpha comes from export channel 1.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* test(shader): draw an NGG vertex shader that reads the group info

Guest-replay draw for boykopovar#5081.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* test(shader): reject TRUNC_COORD point sampling in the color compare emulation

Recompile-level check for boykopovar#907.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* test(shader): run the src2 lane-order test without the Metal debug layer

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* docs(shader): port upstream debt entries and add the FormatVersion 35 history line

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DgW4n3qYgi5jAAohEmXRQj

---------

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
@adriadam10 adriadam10 self-assigned this Oct 14, 2026
@adriadam10

Copy link
Copy Markdown
Collaborator

Checked the emitEntryPrologue change: wave index now also in TG_SIZE[11:6] (max 31 fits in 6 bits), wave count in [5:0], bit 20 and bit 31 unchanged, consistent with ACO's s_bfe_u32 tg_size, 6 | 6 << 16. agc_driver_tg_size_wave_id passes with the change and fails without it (wave64 and wave32). Merging once the full Build is green.

@adriadam10
adriadam10 merged commit ea30c92 into boykopovar:main Oct 14, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agc libSceAgc* shader core/shader

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants