Commit Graph
190 Commits
Author SHA1 Message Date
Adrià 3a930342d5 Merge pull request #9701 from frankea/fix/structurizer-scc-iterative
fix(shader): find strongly connected components without recursion
2026-10-25 23:03:07 +01:00
Adrià 18e85391b4 Merge pull request #9746 from imellag/fix/shader-empty-loop-continue
fix(shader): route a loop's back edge through an empty continue block when its latch holds instructions
2026-10-24 14:53:54 +02:00
Adrià 798c908fc4 Merge pull request #9068 from frankea/table-callee-range
fix(shader): link table callees that together exceed s_call_b64 range
2026-10-24 01:58:48 +02:00
frankea ef2b164b15 fix(shader): relay later table calls past earlier calls' callee copies 2026-10-23 22:13:23 +02:00
frankea a1ae72a2e8 fix(shader): a 64-bit SALU result overwrites both dwords of a call link pair 2026-10-23 22:13:23 +02:00
frankea 0a4027df9a fix(shader): link each table callee next to its own call so large callee sets stay in branch range 2026-10-23 22:13:23 +02:00
JAB-devandClaude Sonnet 5.5 8d54357e79 Merge branch 'main' of https://github.com/boykopovar/AnyPS5 into feat/agc-4-4-4-4-partial-writes
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
2026-10-23 21:18:00 +02:00
Adrià d7948b09f9 Merge pull request #8563 from JAB-dev/feat/agc-4-4-4-4-color-target
feat(agc): render 4_4_4_4 UNORM color targets through packed R16_UINT exports
2026-10-23 21:12:19 +02:00
Maz 913e458369 fix(shader): deserialize pixel function storage dwords at version 45
The SM-budget threshold writes the storage size after the LDS flag; read it back and keep the fixtures on the fused+pointList trailer.
2026-10-23 20:53:29 +04:00
Maz 40c7ff888c fix(shader): scale pixel LDS Function threshold by SM budget
Max measured a 4 GiB private-memory ceiling on a 4090; use
VK_NV_shader_sm_builtins so denser cards take the buffer path below 4096.
2026-10-23 20:53:24 +04:00
mazen dba7f5466c fix(shader): keep a pixel LDS overflow until the GPU is idle
The slot counter is reset only after earlier fragment writes, and the overflow flag stays until WaitIdle. The storage buffer is limited to NVIDIA's proprietary driver, which is where the large function array does not finish.
2026-10-23 20:53:21 +04:00
Adrià 0940da2424 Merge pull request #8070 from thuanquang/fix/table-call-wide-descriptor
fix(shader): link a table call whose V# is a slice of an s_load_dwordx8 or s_load_dwordx16
2026-10-23 18:40:11 +02:00
EmanueleandYcaro Gabriel 7410c37b6c perf(shader): emit exact f32 add, subtract and multiply as fma on MoltenVK
The recompiler marks every guest f32 add, subtract and multiply
NoContraction, because the guest rounds each one separately.
SPIRV-Cross turns each of them into a call to a helper that Metal
compiles without optimization, which dominates fragment time on
MoltenVK, and its multiply helper, fma(a, b, +0.0), turns a -0.0
product into +0.0.

On MoltenVK they are now GLSL Fma whose second step is exact, which
gives the separately rounded result: a * b is fma(a, b, -0.0), a + b
is fma(1.0, a, b) and a - b is fma(-1.0, b, a). The sin, cos and log2
series and the offset image coordinates and gather texel scale use the
same forms. The choice is a SpirvTarget flag set for
VK_DRIVER_ID_MOLTENVK, part of the shader cache key and of the request
serialization (version 44); other drivers are unchanged.

agc_driver_f32_separate_rounding checks a multiply feeding an add or a
subtract on rows where fusing them changes the result. It,
agc_driver_f32_arithmetic_nan and agc_driver_f32_denormal_flush also
run the fused forms on devices that do not use them, so lavapipe checks
them against the same rows.

Co-authored-by: Ycaro Gabriel <[email protected]>
2026-10-23 12:13:18 +02:00
JAB-devandClaude Sonnet 5.5 8b7dd6beb7 Merge branch 'main' of https://github.com/boykopovar/AnyPS5 into feat/agc-4-4-4-4-color-target
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
2026-10-23 12:00:34 +02:00
Emanuele 75fdf64721 fix(shader): route a loop's back edge through an empty continue block when its latch holds instructions 2026-10-23 06:46:55 +02:00
frankea 050af89f1a Merge remote-tracking branch 'origin/main' into fix/structurizer-scc-iterative 2026-10-22 22:40:28 -04:00
JAB-devandClaude Sonnet 5.5 d201de3f32 Merge branch 'main' of https://github.com/boykopovar/AnyPS5 into feat/agc-4-4-4-4-partial-writes
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
2026-10-23 04:09:40 +02:00
Dean Galvin 6990044dfb Merge main into feat/geometry-points-sized 2026-10-23 12:43:00 +13:00
JAB-devandClaude Sonnet 5.5 9ab242a6da Merge branch 'main' of https://github.com/boykopovar/AnyPS5 into feat/agc-4-4-4-4-color-target
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
2026-10-22 19:47:24 +02:00
JAB-devandClaude Sonnet 5.5 4aaf26e3f3 Merge branch 'main' of https://github.com/boykopovar/AnyPS5 into feat/agc-4-4-4-4-partial-writes
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
2026-10-22 14:24:38 +02:00
Get-fix a13d01bcc9 fix(shader): keep the PS5 user-data pointer check unchanged outside PS4 shaders
unchangedUntil skipped a write by the reading instruction itself for every shader, so an RDNA s_load that overwrites its own address pair was taken as a user-data pointer load where main refused it. The skip now applies only to PS4 (GCN) shaders, where it is needed; PS5 shaders take main's path.
2026-10-22 12:19:13 +03:00
Get-fix 4b717912d7 feat(shader): decode PS4 (GCN) shaders by re-encoding them to RDNA
Each GCN instruction is re-encoded to its RDNA form and decoded by the
existing RDNA decoder, so the PS4 path shares the recompiler. Covers the
legacy VS stage (program at the VS slot, user SGPRs from s0, vertex and
instance index in v0-v3), fetch shaders linked as user-data calls, MIMG
(image_sample and friends), PS4 buffer descriptors (GCN DATA_FORMAT /
NUM_FORMAT, 44-bit base) and T# image descriptors (GCN tiling in word 7).
The GCN switch is keyed into the shader disk cache. PS5 behaviour is
unchanged: every PS4-only rule is gated on GcnGuestShaders().
2026-10-22 12:17:44 +03:00
frankea 3606824314 fix(shader): find strongly connected components without recursion
computeStronglyConnectedComponents visited blocks recursively, one stack frame per block on the deepest path. The reach-flag fallback turns Ghostrunner's compute shader 0x200c520000 into a graph of 32,490 blocks, and with APS5_FORCE_STRUCTURIZER_FALLBACK the visit overflowed agc_shader_replay's 2 MiB stack after 4 s.

The visit now keeps its frames in a vector. It enters successors in the same order and closes components in the same order, so the components, their entry blocks and the irreducibility verdict are unchanged.
2026-10-22 04:27:00 -04:00
JAB-devandClaude Sonnet 5.5 8ed185a51c Merge branch 'main' of https://github.com/boykopovar/AnyPS5 into feat/agc-4-4-4-4-partial-writes
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
2026-10-21 20:13:17 +02:00
thuanquangandClaude 01e7d158b6 fix(shader): link a table call whose V# is a slice of an s_load_dwordx8 or s_load_dwordx16
Co-Authored-By: Claude <[email protected]>
2026-10-22 00:13:39 +07:00
milescovielloandClaude Opus 5.5 11bc7b1686 fix(shader): move the vertex point fields to request version 43
main took request versions 33 to 42 for other fields, the last of them
the pixel sample order, so requests of those versions from main have no
point-list tail. The point fields now come with version 43, after them,
and the tests expect 43 and reject 44.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-21 09:13:32 -04:00
milescovielloandClaude Opus 5.5 e7ea490325 feat(agc): draw point lists on the vertex path with their point size
A point list routed through the vertex path was refused, and so was
PA_CL_VS_OUT_CNTL.USE_VTX_POINT_SIZE on it. OliSe Player (PPSA01153)
stops on the latter with two of its MilkDrop presets.

The vertex path now draws point lists as Vulkan points. The vertex stage
writes PointSize: the misc export's X clamped to PA_SU_POINT_MINMAX when
USE_VTX_POINT_SIZE is set, and the PA_SU_POINT_SIZE height otherwise.
The point state travels in the recompile request (version 31) and the
cache and draw keys. Non-square register sizes, inverted clamps, point
sprite texture coordinates and, without largePoints, sizes other than
one pixel throw.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-21 09:13:09 -04:00
Yunus Shaikh 6d09797d6b Merge main into fix/agc-sample-location-grid-exact 2026-10-21 05:39:42 +00:00
Dean 494182e051 Merge pull request #8201 from savvaniss/fix/shader-call-link-wave-size
fix(shader): check call link registers for both wave sizes when the size is unknown
2026-10-21 15:02:27 +13:00
Dean Galvin a07ad30578 feat(shader): request DenormPreserve 32 where the device preserves f32 denormals
The recompiler asked for DenormPreserve only for 16-bit and 64-bit floats,
so a device that flushes 32-bit denormals by default (RADV, MoltenVK) flushed
them whatever the guest's float mode said. target.float32DenormPreserve is set
from shaderDenormPreserveFloat32 when denormBehaviorIndependence allows a 32-bit
mode, is part of the cache key and of the request serialization (version 41),
and makes the module declare DenormPreserve 32 unless the 32-bit flush is
already taken in hardware. APS5_NO_HW_F32_PRESERVE=1 turns it off.
2026-10-21 10:45:24 +13:00
JAB-devandClaude Sonnet 5.5 6ccb8c052e fix(agc): refuse memory-writing 4_4_4_4 merges only where tests can reject pixels
The refusal of a merging shader that writes guest memory under late
tests fired in two cases where the early tests change nothing.

The first was a draw with no depth, stencil or depth-bounds test. Early
tests reject no pixel there, so every write the console makes still
happens. The target merge now carries whether the draw has such a
test, and the refusal applies only then. This adds one byte to the
version 40 merge fields of the recompile request.

The second was any GDS binding, including a shader that only reads GDS.
The refusal now looks for GDS writes, atomics, appends and consumes.

Tests: the depth and stencil decode checks the new flag, and the
static shader key depends on it. A counter-adding shader under late
tests compiles without a test and throws with one. A late-test merge
that reads GDS compiles, and one that adds to GDS throws.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
2026-10-20 19:09:49 +02:00
JAB-devandClaude Sonnet 5.5 27c0004991 fix(agc): merge kill shaders under late tests when the draw writes no depth or stencil
A packed 4_4_4_4 partial write merges inside the pixel shader after early
depth and stencil tests. Moving the tests ahead of a pixel kill only changes
the result when the draw writes depth or stencil, so the target merge now
carries whether the draw does (depth write, or stencil with a write mask and
a non-keep operation), and the late-test kill refusal applies only then.
The flag is part of the static shader key, the serialized request (now
version 40) and the pixel input info.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
2026-10-20 19:09:48 +02:00
JAB-devandClaude Sonnet 5.5 48a7efcbec feat(agc): merge partial writes into 4_4_4_4 UNORM color targets
A CB_TARGET_MASK that writes fewer than four components of a 4_4_4_4
target leaves the other nibbles of each packed word as they were, which
an R16_UINT attachment cannot do. Such draws now close the attachment's
color write mask, and the pixel shader merges the written nibbles into
the target through a storage image: inside a pixel interlock it reads
the word, keeps the bits the mask leaves alone and stores it back.

The merge (export index, word mask, sample count) is part of the static
shader key, request version 40 and shader disk cache format 42; the
storage image is appended to the shader's images with a single runtime
mode, and its T# is encoded from the target's surface at draw time, so
the draw resolves it to the target's resident image, which Draw
requires. Merging shaders declare early fragment tests; shaders that
kill under late tests, export depth, stencil or coverage, use
alpha-to-coverage or a quad sample mask are refused, as are
multisampled, mipmapped, volume and array targets and more than one
merged target per draw.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
2026-10-20 19:09:48 +02:00
JAB-devandClaude Sonnet 5.5 aa210e4e5a feat(agc): render 4_4_4_4 UNORM color targets through packed R16_UINT exports
CB_COLOR_INFO format 19 with UNORM and COMP_SWAP 2 lists A, B, G, R from the
least significant bits. No Vulkan device is required to render into the 4-bit
formats and NVIDIA exposes none of them as color attachments, so the target
is an R16_UINT image and the pixel shader packs the exports into the guest
layout, as the 10_11_11 target does. Writes of fewer than four components,
blending, DCC and truncating rounding are refused.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
2026-10-20 19:08:22 +02:00
Savvanis SpyrosandClaude Opus 5.5 267d211318 fix(shader): refuse a call link escape only at the wave size it escapes under
When the graph is built without the wave size and the return address
escapes under only one of wave32 and wave64, the graph records that size
and its error instead of throwing, and translation throws it only at
that size. A wave64 program that reads a compare mask written over a
call's link pair from a scalar instruction is now recompiled, while the
same program at wave32, where the high dword still holds the return
address, is refused.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-20 18:13:18 +03:00
Dean 5ccf1824df Merge pull request #6679 from SleglJan/pr/merged-hull
feat(agc): run registered merged hull programs (binary type 3)
2026-10-21 04:12:03 +13:00
Savvanis SpyrosandClaude Opus 5.5 cf12795014 fix(shader): check call link registers for both wave sizes when the size is unknown
The control-flow builder does not know the wave size (the front end is
shared across wave sizes), and with an unknown size it took a v_cndmask
mask to read two registers but a VOPC result to write only one. A wave64
compare that overwrote a call's link pair before a v_cndmask read it was
then rejected as a link register escaping the call/return model. The
check now runs once for wave32 and once for wave64 when the size is
unknown, so each read is matched with writes of the same width.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-20 18:07:21 +03:00
Jan ŠléglandClaude Opus 5.5 8b8219dcef feat(agc): run registered merged hull programs (binary type 3)
A registered type-3 hull program holds the local and the hull part of a
tessellation draw in one binary, addressed through SPI_SHADER_PGM_LO_LS
(SH 0x148) with no SPI_SHADER_PGM_LO_HS: the local part runs on the lanes
below s3[7:0] and writes LDS, an s_barrier follows, and the hull part runs
on the lanes below s3[15:8] and may store the registers the local part
filled. The draw decode asked 0x148 for a type-5 local half, and
PPSA11386 (007 First Light) stopped in its level load with "registered
program refers to an incompatible shader binary type".

The draw decode now gives a registered type-3 program both the local and
the hull role and marks the tessellation configuration mergedHull. The
local stage only passes gl_VertexIndex and gl_InstanceIndex in a 16-byte
record. The hull stage runs the whole program, one invocation per output
control point: v2 and v5 come from the record of control point
min(gl_InvocationID, inputs - 1), v3 is the relative vertex id, and the
LDS becomes a per-control-point output array that a control point writes
in its own record and reads in any record of its patch after the barrier.
Registers live across the barrier stay in the invocation.

The hull stage of a merged program runs at one lane per invocation on
every device (HostSubgroupSize 1). Its lanes are gl_InvocationID, not host
subgroup invocations, so the s_cbranch_execz around the local part tests
the invocation's own lane. With the device's subgroup it took a subgroup
ballot, and lavapipe, whose subgroup stages lack the tessellation control
stage, rejected the draw ("subgroup capability 61 is unsupported for
shader stage 2").

The lowering refuses more input than output control points, LDS writes
outside the own record, reads outside the patch's records, barriers that
some invocations do not reach or that sit in a loop, reads or writes of
another lane's register, outputs beyond the device limits, and fetch
subroutines. Type 3 is prepared with its stage group like type 5 and
takes its float mode from RSRC1_HS. The hull user-data address (SH
0x102/0x103) is optional for a merged program: s[0:1] take it, unchecked,
when the draw sets it and are zero otherwise.

Both stages refer to one binary, so a draw lists each code and header
region once (AppendProgramMemory); a request's memory regions must not
overlap. An indirect draw's record words go into every program whose user
data holds the register, so the hull stage of a merged program reads
them too.

mergedHull is part of the recompile cache key, the draw decode comparison
and the request serialization (version 39).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-20 15:55:50 +02:00
Adrià 809aab71d8 Merge pull request #7630 from JJenkx/fix/shader-scheduled-table-index
fix(shader): follow scheduled jump table index writes
2026-10-20 13:04:54 +02:00
Adrià 9b4b3cf463 Merge pull request #6941 from kq62/fix/mesh-barycentric-emulation
feat(shader): emulate barycentrics and per-vertex parameters on the mesh path
2026-10-20 00:17:49 +02:00
Adrià f745930f03 Merge pull request #7413 from thuanquang/fix/table-call-hoisted-descriptor
fix(shader): link a table call whose descriptor load sits before its loop
2026-10-19 21:50:42 +02:00
sussyandClaude Sonnet 5.5 dd41527ce2 feat(shader): emulate smooth barycentrics on the mesh path
A pixel shader that reads barycentrics on a device without
VK_KHR_fragment_shader_barycentric used to need a vertex shader so a
generated geometry stage could follow it, which a mesh pipeline cannot
have. The mesh program is now compiled a second time with the layout
its pixel shader needs: it writes its clip position as a varying and the
three corner positions of each primitive as per-primitive outputs, and
the pixel shader solves for the weights, for both smooth and linear
interpolation.

The layout is part of the mesh cache key, the stored artifact and the
captured request. Without VK_EXT_mesh_shader the draw still throws, now
saying so. Per-vertex parameters on the mesh path still throw.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
2026-10-19 17:26:37 +02:00
simonbronkandClaude Opus 5.5 7563b4a480 fix(agc): replace with a stencil operation value the pixel shader exports
With DB_SHADER_CONTROL.STENCIL_OP_VAL_EXPORT_ENABLE the pixel shader
supplies the value that REPLACE_OP and the add and subtract operations
use in place of DB_STENCILREFMASK.STENCILOPVAL. The bit was refused as a
whole, which stopped Onimusha: Way of the Sword (PPSA27836) at a
DB_SHADER_CONTROL 0x45 draw with DB_STENCIL_CONTROL 0x40040 (REPLACE_OP
on depth pass, both faces), write mask 0xff and compare ALWAYS.

The export is accepted with the 32_GR and 32_ABGR Z formats. When no
reachable operation through a non-zero write mask reads the value, it
cannot change the result and is ignored. Without a test value export, a
reachable REPLACE_OP becomes REPLACE with the exported value as
FragStencilRefEXT (or the bounded replay on devices without the
extension), provided both faces compare without the test value and use
no ONES or REPLACE_TEST; early tests throw. The add and subtract
operations, and REPLACE_OP with a test value export, still throw.

The value is read from bits 8-15 of the second MRTZ channel: the
title's pixel shader shifts it left by 8 right before exp mrtz
(v_lshlrev_b32 v0, 8, v0). That is the only evidence for the layout and
it is listed as technical debt. The pixel stage info carries the new
flag into the cache key, the draw keys and request serialization
version 31.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-19 12:53:13 +02:00
Yunus Shaikh 53cc193a3c Merge main into fix/agc-sample-location-grid-exact
#6503 took request serialization 36 for its float32 flush flag, so this branch's sample order moves to 37. The version relabels in ShaderMemory.cpp and RequestSerializerTests.cpp drop both trailing flags and the sample order.
2026-10-18 22:52:06 -07:00
ThatsLeo ac14d6317d perf(shader): flush f32 denormals in hardware when a startup probe matches the emulation
Devices with DenormFlushToZero for f32 run the mixed denormal-flush programs with and
without the hardware mode at startup; when every result matches, add, sub, mul, fma,
floor and ceil in the default rounding mode drop their software flush.
2026-10-19 07:00:13 +02:00
Yunus Shaikh 18463ff5c2 Merge main into fix/agc-sample-location-grid-exact
#4650 took request serialization version 35 for its depth remap flag, so this branch's sample order moves to 36. The serialization tests drop #4650's trailing byte from every older version they build, as main's do, along with the iteration fields and the sample order.
2026-10-18 20:56:57 -07:00
Dean Galvin 4d4ae6e5eb Merge main into pr-4650
# Conflicts:
#	core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
#	core/shader/recompiler/ControlFlow/src/RequestSerializer.cpp
#	core/shader/recompiler/tests/RequestSerializerTests.cpp
2026-10-19 14:32:36 +13:00
Yunus Shaikh 745f199d5a Merge main into fix/agc-sample-location-grid-exact
Combines this branch's sample order with #6470's once-per-pixel and once-per-sample inputs. The pixel request keeps both sides' fields: #6470's iteration, position location and sample locations are serialized at version 34, and the sample order after them at version 35. The serialization tests move the sample-order bytes after the iteration fields and drop both from older versions. The pixel info collector adds sample order to the SampleLocationsVary inputs, and the draw keys compare and hash both. EmitSampleOffset's iterated index already goes through GuestSampleIndex, since the SampleId builtin does. The shader cache stays at FormatVersion 40, and the sample-location debt entry takes #6470's sentence on the position inputs.
2026-10-18 18:30:37 -07:00
Adrià 00666eeb36 Merge pull request #6470 from EagleBearerYS/fix/recompiler-once-per-pixel-sample-inputs
fix(recompiler): run a pixel shader the guest does not iterate once per pixel
2026-10-19 03:21:34 +02:00
Adrià 55a3ac6440 Merge pull request #6405 from fdfawef324/claude/shader-structurizer-branching-returns
fix(shader): give a selection a merge when one arm returns through nested branches
2026-10-19 02:07:54 +02:00