Skip to content

Upstream sync 11D: shader recompiler (13 commits) - #511

Merged
RINNECODER merged 13 commits into
mainfrom
sync/upstream-11-shader-recompiler
Oct 15, 2026
Merged

RINNECODER merged 13 commits into
mainfrom
sync/upstream-11-shader-recompiler

Conversation

@RINNECODER

@RINNECODER RINNECODER commented Oct 15, 2026 •

Copy link
Copy Markdown
Owner

Cherry-picks (-x) from 63fb0cd92..upstream/main (head d92a8dad3), scope shader recompiler (core/shader, plus the shared libSceAgcDriver hunks that drive it). 13 of the 39 listed commits are picked. The other 26 are skipped: 18 are already on main (from the batch-1 U3/U6/U7/U8a ports and #473), 6 depend on series the fork lacks, and 2 only move debt notes. There are no fork-only commits. One commit message was reworded: the GDS ordered-count commit named a title and its ID, and now says "a shipping title". docs/dev/debt/shader.md hunks were ported into docs/dev/TechnicalDebt.md. Hunks for docs/dev/debt/libSceAgcDriver.md went into that file, which main has.

Cache formats: ShaderDiskCache::FormatVersion stays at 37 because no picked commit changes the payload layout; the static_asserts are unchanged and the build passes. The source version already changes with every recompiler source. The recompile-request serializer goes from fork version 24 to fork version 25, which adds linkedCallFallbacks. Upstream calls this field version 26, because its own 25 is dithered alpha coverage, which the fork lacks. Fork and upstream request version numbers now differ by one. Any later port of an upstream request field must bump the fork's number and must not reuse upstream's number.

Ported

  • 907d1360d feat(shader): track MODE rounding changes through the control flow graph (new RoundingMode.cpp; debt line ported).
  • 99b7c63bb perf(shader): reuse packed f16 operand lanes.
  • 09b70d001 build(recompiler): generate the shader cache version as a source file (same hash inputs; ShaderDiskCache.cpp no longer rebuilds on every recompiler edit).
  • 2bfa0b736 refactor(recompiler): emit the v_fma_mixlo/hi and v_interp_*_f16 emulation once per module. Conflicts: the CMake test list keeps main's list and adds only agc_fma_mix_once_tests. SpirvEmitterState keeps both bvhIntersectFunctions and the new interpolateFunctions.
  • 464925a2b fix(build): preserve UTF-8 shader cache source paths.
  • f45630177 fix(shader): group compute derivatives by four consecutive lanes.
  • 31f1deb65 feat(shader): link callees of calls whose target is loaded from a table. FaultReason gains UnlinkedCall only, not upstream's ImageTable, which belongs to the image-table series the fork lacks. The <malloc.h> glibc include was not taken.
  • e84e53d10 fix(shader): fault only where a table call misses its linked callees. The request serializer change goes in as fork version 25 (see above). The LinkGraphicsUserDataTail fallback was dropped because main has no user-data tail linking. The serializer tests keep main's fixtures, with the version strings moved to 25 and the fallback round-trip checks added.
  • f31deebcd feat(recompiler): load prebuilt shader packs before the writable cache. Main's DecodeEntry has no mapped-file owner argument, so the pack lookup runs before main's existing loose-file load.
  • b3d676dc1, 44b8b7673 feat/fix(shader): GDS ordered counts and ordered-append dispatches (shared Pm4.cpp decode included).
  • d46a32c13 fix(shader): name the buffer and its V# when a descriptor type is unsupported. The Vulkan BufferDescriptorRuntime.cpp execution test does not exist on main and was not taken.
  • 9114ea14c fix(shader): read explicit-LOD 2D samples through 1D T#s as measured.

Skipped

Evidence

  • agent_build.sh rosetta (x86_64 ANYPS5_ROSETTA_LIBS=ON): rosetta_libs rosetta_engine anyps5_agc_replay libSceAgcDriver built.

  • agent_build.sh shader-bridge: built; ctest 4/4 passed.

  • agent_build.sh guest-replay: built; ctest 59/59 passed (excluding the GUI anyps5_metal_presentation_replay).

  • core/shader/recompiler/tests/RequestSerializerTests.cpp was built against the guest-replay recompiler library and exits 0. ShaderMemory.cpp, FmaMixOnce.cpp, ScalarCall.cpp and ScalarSwappc.cpp pass -fsyntax-only with the recompiler flags. These tests sit in the Vulkan driver test tree, which the fork's configs do not build.

  • Not run: the agc_driver_* Vulkan execution tests (they need a Vulkan test device), and game smoke. Rebased onto main after metal: cheap conversion-cache hits and per-draw lookups (-51% worker instructions on the live map) #507 (the rebase was clean). On the rebased branch, guest-replay ctest passed 59/59 (without anyps5_metal_presentation_replay), and the rosetta anyps5_agc_replay was rebuilt.

  • AGC frame replay (x86_64 anyps5_agc_replay), main 8f8c56e94 vs this branch:

    check main this branch
    live map --expect-hash 5e5670079f1ae58a (--repeat 4) match, stable match, stable
    menu --expect-png replay-ref.png --max-diff-pixels 8 (--repeat 3) 2 px differ: match 1 px differ: match
    live map worker M instructions, median 4548 4402
    menu worker M instructions, median 1315 1209

    The instruction numbers are indicative only. Each comes from a single short run, made without the exclusive replay lock while other replays were running. They are not a performance claim.

  • No performance claims.

Review findings (chatgpt-codex-connector)

sev location finding action
- - The connector review of this PR reported Failed. Its commits are also in #512, whose review raised one P2 in this slice: SpirvMemoryInstructions.cpp:1291, where a wave64 ds_ordered_count whose first active lane is in the upper half shuffles from the lower half Not fixed: P2, carried as upstream wrote it; recorded as a followup

🤖 Generated with Claude Code

https://claude.ai/code/session_01DgW4n3qYgi5jAAohEmXRQj

@coderabbitai

coderabbitai Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 3f57d93d-8e6a-46dd-8b2d-b45d2e9877c0
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ⚠️ Failed 2026-10-15T05:33:31.051419Z 9114ea1 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

semirkabir and others added 13 commits October 15, 2026 01:22
ShaderCacheVersion.cmake wrote the source version and the APS5_* switch
list into a generated ShaderCacheVersion.hpp that ShaderDiskCache.cpp
included. The version hashes every recompiler source, so any content
change under core/shader/recompiler rewrote that header and recompiled
ShaderDiskCache.cpp next to the file actually edited.

The script now writes ShaderCacheVersion.cpp, which defines
Generated::SourceVersion and Generated::RecompilerSwitches (a span over
the same sorted switch list) with constinit. They are declared in the
new ShaderCacheSourceVersion.hpp in the source tree, which
ShaderDiskCache.cpp includes; the generated directory is no longer an
include directory. The header has a different name from the old
generated one so that a build directory that still holds the stale
ShaderCacheVersion.hpp next to the generated .cpp cannot pick it up.

What is hashed is unchanged: the same manifest (recompiler sources,
HostThreadLocal.hpp, submodule commits, compiler, build type,
architecture and flags), the same checks and the same rewrite-only-
when-different step, so the version still changes exactly when it did.
Running the upstream/main script and this one with the same arguments
over this tree gives the same version (0x7907101dc4d8c62e) and the same
26 switches, and a second ninja run has no work to do. The value
differs from the one main 682ef0c generates (0xdce3a0ce03bf030a) only
because this commit edits hashed files, as any recompiler change does.

Tested with ninja -d explain -j 4 shader_recompiler_agc_driver,
CCACHE_DISABLE=1, after appending a line to
IntermediateRepresentation/src/IrType.cpp, three runs on main and then
three runs on this commit back to back, with the machine at 100% CPU
from other builds. On main ShaderCacheVersion.hpp and
ShaderDiskCache.cpp.obj are dirty and the rebuild takes 22.0/23.9/22.2 s.
With this change only ShaderCacheVersion.cpp.obj and IrType.cpp.obj are
compiled, ShaderDiskCache.cpp is absent from the explain output, and the
rebuild takes 12.2/14.7/15.0 s. The shader and recompiler ctest set
(26 tests) passes.

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

Co-Authored-By: Codex <noreply@openai.com>
(cherry picked from commit 2e461aa)
…ation once per module

FPInterpolateF16 and FPInterpolateF32 (v_fma_mixlo_f16, v_fma_mixhi_f16,
v_interp_p1ll_f16, v_interp_p1lv_f16, v_interp_p2_f16) were lowered by
expanding the f64-based Interpolate emulation inline at every use, about
1200 SPIR-V words each, twice per instruction in wave64 shaders. Interpolate
now builds one non-inlined helper function per result width and float mode,
created on first use, and each use calls it. The function body is the
same instruction sequence the inline expansion produced, so results are
unchanged; only the module size changes.

agc_fma_mix_once checks that two more uses grow a module by less than the
first use with its shared function.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 8847086)
A compute shader with an LOD query was emitted with DerivativeGroupQuadsKHR,
which needs both workgroup dimensions even. A guest workgroup of N x 1 lanes
failed SPIR-V validation (VUID-StandaloneSpirv-DerivativeGroupQuadsKHR-10151),
which agc_driver_waterfall_images hits on every device.

GFX10 forms a compute quad from four consecutive lanes, which is
DerivativeGroupLinearKHR. The wave64 path no longer reshapes its workgroup
to 2 x N, which only made the 2D quads match consecutive lanes.

(cherry picked from commit 1ef97e5)
An s_swappc_b64 whose target pair comes from an s_buffer_load of a buffer
whose descriptor is loaded from user data now calls the targets that buffer
holds: at dispatch the driver reads the buffer, links one copy of each
distinct callee after the caller and rewrites the call into a compare chain
that s_call_b64s the matching copy. A target that matches no copy, and any
other computed call, records an UnlinkedCall fault that the driver reports,
instead of failing the shader at compile time.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 9c8fb78)
An s_swappc_b64 whose target is not resolved compiles to a faulting call
only at the fallback the table-call linker emits; the linker lists those
calls in the request (GuestContext::linkedCallFallbacks), and every other
computed call is refused at compile time again, as on main. The new
agc_driver_compute_table_calls test runs a linked two-record table on
Vulkan in wave32 and wave64, with SCC 0 and 1 reaching the callee, and a
record past the table reporting the UnlinkedCall fault.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 3c1f439)
Read-only packs of encoded cache entries are mapped once at startup from
the shader cache prebuilt directory (plus ANYPS5_PREBUILT_SHADER_CACHE,
opt out with ANYPS5_NO_PREBUILT_SHADERS). Disk loads try packs and loose
prebuilt folders first and fall through to the writable cache and the
compiler on a miss. Keys, source version, format and payload checksums
are validated exactly as for writable entries, and interval logs report
prebuilt hits, misses, rejections and load timings.

Depends on the uncached compile entry point only through the offline
tool that produces these packs; the loader itself is independent.

(cherry picked from commit 24c934a)
ds_ordered_count adds the first active lane's value to a GDS counter and
returns the previous value, like ds_append adds the lane count. Waves are
not serialized in launch order: each still gets its own range. Ordered
swap and multi-dword counts stay refused. DISPATCH_DIRECT and
DISPATCH_INDIRECT accept ORDERED_APPEND_ENBL (bit 3) of the initiator.
Compute shaders of a shipping title use both.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 46a1cc0)
On ds_ordered_count M0 holds the ordered wave ID, not a GDS address as
for ds_append: radeonsi and ACO pass the wave ID as the intrinsic's
pointer and keep the counter address in offset0. Reading M0 as the base
and size skipped the add whenever M0[15:0] was 0, so every wave got the
same range. The test now runs the ordered pass with M0 = 0 and M0 = 7.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 3a7e82a)
A 2D image_sample_l through a 1D T# now takes the 1D runtime mode, as
image_sample_lz already does, instead of failing the runtime image
interface. Measured on RDNA2 (gfx1036) with tools/hw-oracle against the
same sample with DIM 1D: u inside, on and past the edges, v of 0, 0.5, 1,
-0.25 and 3, LOD -1 to 6 on a 5-level R32_FLOAT texture, point, linear and
linear-mip filtering, wrap, clamp and border addressing, and HEIGHT or
DEPTH 3. All 4725 rows matched: the 1D T# decides the addressing and v is
ignored.

The execution test samples a 5-level 1D T# with distinct mip contents at
LODs -1 to 6, fractional ones included, with u inside, on and past the
edges, under point filtering with wrap and clamp and linear filtering with
linear mips and wrap, clamp and border addressing. Every result must match
the same image_sample_l with DIM 1D bit for bit; point-filtered results
must also be the expected texel of the expected level, and linear-mip
results the blend of the two levels the LOD selects.

(cherry picked from commit e52e140)
@RINNECODER
RINNECODER force-pushed the sync/upstream-11-shader-recompiler branch from 9114ea1 to a8da517 Compare October 15, 2026 07:33
@RINNECODER
RINNECODER merged commit 2c3ff50 into main Oct 15, 2026
1 check passed
@RINNECODER
RINNECODER deleted the sync/upstream-11-shader-recompiler branch October 15, 2026 07:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.