Skip to content

fix(agc): settle registration preparations before a preparation scope locks - #5023

Merged
adriadam10 merged 1 commit into
boykopovar:mainfrom
fdfawef324:fix/agc-shader-prep-wait
Oct 14, 2026
Merged

adriadam10 merged 1 commit into
boykopovar:mainfrom
fdfawef324:fix/agc-shader-prep-wait

Conversation

@fdfawef324

@fdfawef324 fdfawef324 commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

What

A shader preparation transaction takes the process-wide writers lock on its first Read, Edit or Hold and keeps it until the outermost transaction ends (#3159). Read and Edit take the lock before they wait for the snapshot's background registration preparation (AwaitRegisteredPreparation).

sceAgcCreateInterpolantMapping resolves the pixel shader's ABI first, which takes the lock, and then resolves the rectangle ABI, which reads the vertex shader and waits for its registration preparation while holding the lock. sceAgcLinkShaders and sceAgcCreatePrimState wait the same way in ResolveGraphicsStagesAbi. While one such wait lasts, every other RegisterShader and every other ABI resolution in the process waits for the lock.

ShaderPreparationScope now takes the shaders it will resolve. AgcDriverBeginShaderPreparation_nid_postfix(shaders, count) calls Driver::SettleShaderPreparations, which looks up the registered snapshot of each named shader and waits for its registration preparation before the scope's transaction exists, so before it can take the lock. A preparation never becomes pending again once it has settled. If a header is replaced between the settle and the read, the new snapshot is awaited under the lock, as before.

  • sceAgcCreateInterpolantMapping names the vertex and pixel shaders (the vertex shader only when there is a pixel shader). sceAgcLinkShaders names both. sceAgcCreatePrimState now opens a scope around its graphics ABI resolution and names the hull and vertex shaders.
  • When nothing is pending, the settle only looks up the snapshots. A registration preparation that failed is rethrown when the scope starts instead of at the first read of that shader in the same call.
  • Still awaited under the lock: programs that ResolveGraphicsStagesAbi finds by code address and not by header (another header registered for the same code, a tessellation local stage), and fragments linked earlier to the same vertex shader when a rect-list ABI is requested.

Related:

  • perf(agc): resolve static shader ABIs on the background pool #2589 queues static ABI compiles on the pool and waits for a snapshot's ABI jobs before Read and Edit take the lock. It does not move the wait for the registration preparation (pending), which still runs after Hold, so the rectangle ABI read of the vertex shader still waits under the lock. The two merge without conflicts. With both, the settle also runs or waits for the named shaders' queued ABI jobs before the lock.
  • fix(agc): prioritize demanded shader preparation #4404 moves a preparation that a caller waits for to the front of the pool queue. That shortens the wait but does not move it out of the lock. With both, the settle's wait is the one that gets prioritized. The two merge without conflicts.
  • fix(agc): wait for queued registration preparations before accepting a submission #5007 waits for queued registration preparations in Driver::Submit, before a submission is accepted. That is a different path and does not involve the preparation lock. The two merge without conflicts.

Tested

  • Resident Evil 4 (PPSA07411), Windows, integration build. Measured with a local counter per 10 s window. Before: the preparation lock was held 8 to 10 s of every 10 s, almost all of it waiting for registration preparations, and loader threads waited 13 to 45 s per 10 s to take it. After: held 0.4 to 2.6 s per 10 s, and nothing waited for a preparation under it. On its own, the title still shows its black boot screen after 10 minutes on a cold shader cache, because the loader threads now wait for compiles outside the lock instead.
  • New test agc_driver_preparation_scope_settle (tests/execution/PreparationScopeSettle.cpp). It holds every registration pool thread, registers a vertex shader whose preparation is then queued, and starts sceAgcCreateInterpolantMapping for it on another thread. It then checks that another shader can be registered while that call waits.
  • Windows Server 2025, MinGW-w64 GCC 15.2.0, Release with BUILD_TESTING=ON, rebased on main 637ade8:
    • ctest -R "^agc_|^guest_shader_link$" -j 6: 463 tests, no failures, 1 skipped (agc_driver_stencil_ref_export).
    • tools/check_test_registration.py and tools/check_conventions.py --base upstream/main pass.
  • Not tested: Linux.

Checklist

🤖 Generated with Claude Code

@github-actions github-actions Bot added build agc libSceAgc* labels Oct 13, 2026
@xXPBSXx

xXPBSXx commented Oct 13, 2026

Copy link
Copy Markdown
Contributor

Windows test (MinGW GCC 15.2, Release, Windows 10, RTX 4080 SUPER). Built on main 2a2a3dc65 together with nine other open GPU PRs (their own commits applied, no merge commits; one further PR, #5024, conflicted with them and was left out), so only the tests that belong to this PR say something about it:

  • tests/execution/PreparationScopeSettle.cpp, which ctest runs as agc_driver_preparation_scope_settle: 3 of 3 runs passed.

Not tested: no game run. The batch was built once, not per PR; nothing failed, so no bisect was needed.

AI-assisted (Claude Code).

@fdfawef324
fdfawef324 force-pushed the fix/agc-shader-prep-wait branch 3 times, most recently from 3bd81bc to bcec58b Compare October 13, 2026 21:56
@fdfawef324
fdfawef324 force-pushed the fix/agc-shader-prep-wait branch 2 times, most recently from 920721c to 54a10dc Compare October 14, 2026 00:58
… locks

sceAgcCreateInterpolantMapping resolved the pixel shader's ABI, which takes
the process-wide shader preparation lock until the scope ends, and then
waited under that lock for the vertex shader's background registration
preparation. sceAgcCreatePrimState and sceAgcLinkShaders could wait the same
way. Every other shader registration and ABI resolution queued behind that
one compile: on PPSA07411 the lock was held 8 to 10 s of every 10 s, almost
all of it waiting for registration preparations, while its loader threads
waited 13 to 45 s per 10 s to take it.

A preparation scope now names the shaders it resolves and waits for their
registration preparations before it can take the lock.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@fdfawef324
fdfawef324 force-pushed the fix/agc-shader-prep-wait branch from 54a10dc to 11ef8e6 Compare October 14, 2026 02:49
@adriadam10 adriadam10 self-assigned this Oct 14, 2026
@adriadam10

Copy link
Copy Markdown
Collaborator

Checked on Linux: build and scoped ctest (libSceAgc + libSceAgcDriver) pass, and agc_driver_preparation_scope_settle fails without the driver change and passes with it. agc_driver_tessellation segfaults here with and without this PR, so it is not caused by it. Windows run of the test confirmed by @xXPBSXx. Merging once the full Build is green.

@adriadam10
adriadam10 merged commit 0b13048 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* build

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants