Commit Graph
503 Commits
Author SHA1 Message Date
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
Adrià 415fd7136b Merge pull request #8991 from Tamalero/fix/shader-image-table-split-tsharp-halves
fix(recompiler): match image-table T# halves offset before and after readfirstlane
2026-10-21 21:53:27 +02:00
Dean 3594eee9f3 Merge pull request #6604 from notaxeltv/fix/recompiler-default-past-num-interp
fix(recompiler): fill missing pixel interpolators as DEFAULT
2026-10-22 08:31:15 +13:00
Adrià 1698d1ea6a Merge pull request #8642 from MarcZX10/codex/color-compare-format-support-7934
fix(agc): match measured color comparison formats
2026-10-21 21:02:30 +02:00
TamaleroandClaude Opus 5.5 9998385047 fix(recompiler): match image-table T# halves offset before and after readfirstlane
A T# loaded as two s_load_dwordx4 halves from a pointer table, where the
second half's offset is formed per lane (v_lshl_add_u32 key, 5, 16) before
v_readfirstlane and the first half's after it (readfirstlane(key) << 5),
was refused: the second half's +16 sat inside ReadFirstLane(Select(exec,
..., old), exec), so TryMakeTableColumn saw a different base and a zero
addend. Compare such offsets in a first-lane normal form (lane value, mask,
shift, addend), peeling selects the mask implies as the SRT walker already
does.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-21 20:21:35 +02:00
Dean Galvin efb4ac4773 Merge origin/main into PR 6604 2026-10-21 21:12:11 +13:00
Yunus Shaikh 8c9c8eb5b5 Merge main into fix/agc-sample-location-grid-exact
main 7ce3b1df3e took disk-cache format 43 (#8295) for its own layout, so this
branch's format moves to 44. The request serializer stays at 42: main
still writes 41.
2026-10-20 23:48:14 -07:00
Yunus Shaikh 6d09797d6b Merge main into fix/agc-sample-location-grid-exact 2026-10-21 05:39:42 +00:00
Dean Galvinandmazen dc38f31983 Merge main into fix/skip-inaccessible-branched-scalar-load
Shader disk cache FormatVersion 43: main took 42 with #7966, and this
change also changes the cached plan.

Co-authored-by: mazen <[email protected]>
2026-10-21 14:23:05 +13:00
Dean 1faa800f08 Merge pull request #7966 from KarthikeyaAnna/fix/agc-1d-depth-compare-2d
fix(agc): back 1D depth comparison textures with 2D images
2026-10-21 14:21:13 +13:00
Dean bcdb033754 Merge pull request #7560 from parl0v/perf/window-store-liveness
perf(shader): drop window stores no relative read can see
2026-10-21 10:48:39 +13:00
Dean 26740077bd Merge pull request #8144 from TheSovietWaffle/fix/recompiler-domain-computed-control-point
feat(shader): read domain inputs at a control-point index computed from data
2026-10-21 09:31:11 +13:00
Adrià eb73c168bb Merge pull request #7431 from milescoviello/perf/srt-patch-insert-before
perf(shader): insert patched SRT reads before their use without appending first
2026-10-20 22:29:45 +02:00
MarcZX10 4f0e4ba8e7 fix(agc): return zero for measured color compares 2026-10-20 19:53:00 +00:00
Adrià f6ce8e34a2 Merge pull request #7666 from tibzejoker/fix/normalized-storage-write-rounding
fix(shader): round normalized storage image writes from the exact product
2026-10-20 18:24:01 +02:00
Adrià 636aa09cb1 Merge pull request #7520 from milescoviello/perf/ir-single-use-list
perf(shader): keep one use list per IR value
2026-10-20 17:26:34 +02: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
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
Maz 53ed35b362 fix(shader): skip unreachable flat SRT loads under a known branch
Capture evaluated every flattened scalar slot even when a clean scalar
branch skipped it, so an inaccessible direct user-data root refused the
draw. Record flat-slot uses on resource control-flow blocks and evaluate
only the reachable ones; keep refusing taken and unresolved paths.

Fixes #8272.
2026-10-20 13:11:24 +04:00
karthikeyaAnna c97e5e0338 fix(agc): back 1D depth comparison textures with 2D images
Back 1D and 1D-array depth comparison textures with 2D Vulkan images and views of height 1. Drivers such as AMD RADV reject 1D depth images (VK_ERROR_FORMAT_NOT_SUPPORTED). The shader recompiler maps 1D depth comparison samplers to 2D image descriptors, and pins the normalized vertical coordinate to 0.5 to sample the center of row 0 without hitting borders.
2026-10-20 14:21:58 +05:30
thuanquangandClaude Opus 5.5 a5e1f83417 fix(shader): keep the 24-bit factor reads of 16-bit multiplies
#7018 reads the low-half factors of v_mul_lo_u16 and v_pk_mul_lo_u16
as 24-bit fields because AMD's Windows driver stores the full 32-bit
product when it knows both factors fit in 16 bits. #7673's fold of
BitFieldUExtract(x, 0, n) into x removed those reads when the program
had masked the factors to 16 bits, so agc_driver_mul_lo_u16_high_half
failed again on that driver. The folder now keeps a field read that a
multiply uses.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-20 15:18:13 +07:00
Adrià 38d7e344b1 Merge pull request #7871 from Ondra97/codex/perf-cse-operand-keys
perf(shader): keep redundant expression operand keys inline
2026-10-20 05:04:22 +02:00
Dean Galvin f06c9f9222 Merge main into pr-6604
# Conflicts:
#	docs/dev/debt/shader.md
2026-10-20 14:05:05 +13:00
Adrià 509cad049d Merge pull request #7707 from milescoviello/fix/uint-direct-point-sampler
fix(shader): point-filter direct samplers paired with unsigned integer images
2026-10-20 02:57:22 +02:00
Adrià 1b0ff1e153 Merge pull request #7673 from tibzejoker/perf/fold-unused-bits
perf(shader): fold masks, shifts and field extracts through bits they do not use
2026-10-20 02:35:37 +02:00
battleblob1andClaude Opus 5.5 f95471ec6a feat(shader): read domain inputs at a control-point index computed from data
A domain program that picks one of its patch's control points from data
(Onimusha: Way of the Sword, PPSA27836, selects a corner with v_cmp and
v_cndmask before a buffer_load from the off-chip ring) was refused with
"the tessellation ring or LDS address is not affine in the control point
and relative patch". Computed indices were accepted only for hull LDS
reads.

- The address evaluator gives off-chip EvaluationInput reads the same
  dynamic term as hull LDS reads, and a value read from the patch's own
  ring or LDS no longer counts as depending on the relative patch index,
  since the lowered read takes the patch implicitly.
- When the program also uses its relative patch index as data, the
  index is replaced by the grouped patch instead of 0, which left a
  computed read's address pointing into another patch. Such reads now
  subtract their relative patch term, for hull and domain reads alike;
  reads in programs that do not use the index as data keep their address.
- The computed offset must be a whole number of control points, and the
  backend clamps the domain gl_in index to the last output control point
  as it already does for hull reads.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-20 03:05:55 +03:00
Adrià 138199da67 Merge pull request #7491 from milescoviello/perf/mse-skip-empty-families
perf(shader): skip masked-select families that have no candidate select
2026-10-20 00:08:44 +02:00
Adrià 7fe0790e59 Merge pull request #7388 from pushkarreddyy/feat/recompiler-waterfall-image-table
feat(recompiler): support waterfall select conditions and key bounds in pointer image tables
2026-10-19 22:04:09 +02:00
Adrià d10ef4d2c6 Merge pull request #7381 from thuanquang/fix/volume-array-sample
fix(shader): sample a 3D T# through DIM 2D_ARRAY as a volume
2026-10-19 21:38:12 +02:00
Adrià c0adf025b8 Merge pull request #6815 from JJenkx/fix/msaa-load-on-plane
fix(shader): read 2D textures through MSAA image loads
2026-10-19 21:07:00 +02:00
pushkarreddyy 91abb61be6 fix(recompiler): use ActiveMaskImplies in SrtTape and restore debt entry 2026-10-19 20:00:18 +05:30
thuanquangandClaude Opus 5.5 1ed8eb6d8b fix(shader): sample a 3D T# through DIM 2D_ARRAY as a volume
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-19 16:19:13 +02:00
Adrià 85029a00f5 Merge pull request #6762 from simonbronk/fix/stencil-op-value-export
fix(agc): replace with a stencil operation value the pixel shader exports
2026-10-19 15:45:10 +02:00
Adrià 3bb15be094 Merge pull request #6799 from milescoviello/fix/cube-face-image-store
fix(shader): store through DIM 2D image_store to a cube T#'s BASE_ARRAY face
2026-10-19 15:04:02 +02:00
Ondra97 921b8408d4 perf(shader): keep redundant expression operand keys inline 2026-10-19 13:24:47 +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
Adrià Franch 6a894d4c1c Merge upstream/main into codex/fmask-image-reads 2026-10-19 09:48:51 +02:00
Adrià feb74b65c2 Merge pull request #6551 from yash27git/patch/Tessellation-Lowering
feat(shader): read hull inputs at a control point chosen by a select or phi
2026-10-19 08:31:08 +02:00
pushkarreddyy bfd5b6e388 fix(recompiler): constrain ActiveMaskImplies template and make bounded test key dynamic 2026-10-19 11:15:37 +05:30
pushkarreddyy b7e0189265 feat(recompiler): support waterfall select conditions and key bounds in pointer image tables 2026-10-19 11:15:37 +05:30
Yunus Shaikh 245cec763f Merge main into fix/agc-sample-location-grid-exact
Resolves sameDecode in DrawRegisterKey.cpp, keeping this branch's sample-order comparison and #6530's merged-coverage comparison.
2026-10-18 21:53:18 -07:00
Adrià e0b8be9dc5 Merge pull request #6530 from milescoviello/feat/smoothing-mixed-samples
feat(agc): draw radeonsi line and polygon smoothing (SAMPLE_COVERAGE, merged mixed samples)
2026-10-19 06:06:26 +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 41764f27ac Merge main into pr-4650
# Conflicts:
#	core/shader/recompiler/ShaderDiskCache.cpp
2026-10-19 15:36:07 +13:00
Karan Vora 6d92220829 perf(agc): stage raw buffer elements a dispatch sweeps
Since 2688b7646 a read and written V# element is staged in device memory
up to 16 MiB when the direct dispatch's threads times the V# stride cover
at least half of it. A raw buffer has stride 0, so it never passed and
kept the 2 MiB written window: GL storage buffers compiled by Mesa stay
bound in place in the host import however hard a dispatch sweeps them.

The PS5 OpenGL Showcase's particle update (262,144 threads, each loading
and storing its own 32-byte record of an 8 MiB SSBO) took about 53 ms of
GPU per frame on an RTX 4060 bound in place; staged it takes about 0.1 ms
plus 2.2 ms of bulk copies.

The recompiler already records the furthest byte each buffer resource's
accesses reach past their base (maxByteExtent). The binding plan now
carries it per guest buffer element (DescriptorBinding::bufferExtent,
shader disk cache format 37), and a raw element uses it as its record
size in the sweep test. Strided elements are unchanged.
2026-10-19 03:43:19 +02:00
Adrià 23629c2847 Merge pull request #6454 from EagleBearerYS/perf/shader-image-table-reuse-v3-pr
perf(agc): share one image table per heap and write epoch through capture, compare, resolution and descriptors
2026-10-19 03:39:03 +02:00
Adrià 72b0ab3e8e Merge pull request #6312 from meh7an/perf/agc-cut-draw-allocations
perf(agc): cut per-draw heap allocations
2026-10-19 03:38:58 +02: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
milescovielloandClaude Opus 5.5 03b0db0520 feat(shader): load the SAMPLE_COVERAGE pixel input from gl_SampleMaskIn
SPI_PS_INPUT_ENA/ADDR bit 14 (SAMPLE_COVERAGE_ENA) gives the pixel shader one
VGPR, after ANCILLARY, holding the samples the primitive covers. The decoder
refused it and the recompiler never loaded the VGPR. It is now loaded from
gl_SampleMaskIn[0] (sharing the input the partial quad sample mask already
declares). On a multisampled draw the hardware word is the whole pixel's
coverage while gl_SampleMaskIn holds only the invocation's samples when the
pixel shader runs per sample, so that case, and sample-rate or ancillary inputs
beside it, are refused.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-19 01:25:21 +00:00