Commit Graph
555 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
Dean ce7d547175 Merge pull request #8856 from klosixgaming-arch/feat/agc-point-list-geometry-output
feat(agc): draw point-list output of NGG geometry programs as mesh points
2026-10-22 01:46:18 +13:00
Yunus Shaikh 6d09797d6b Merge main into fix/agc-sample-location-grid-exact 2026-10-21 05:39:42 +00:00
klosixgaming-arch ee81c5112d feat(agc): draw point-list output of NGG geometry programs as mesh points
A geometry program with VGT_GS_OUT_PRIM_TYPE 0 (point list) was refused
as an unsupported output assembly, halting Cocoon (PPSA08766) on boot
with "VGT_GS_OUT_PRIM_TYPE other than a triangle strip, or a line strip
from a geometry program, is unsupported".

Each primitive export of an NGG point-list geometry program outputs one
point whose vertex index is stored directly in PrimitivePointIndicesEXT,
so the mesh module now declares OutputPoints with PrimitivePointIndicesEXT
for it when outputPrimitiveSize is 1. The point primitive export extracts
the 9-bit vertex index from the packed primitive export word and stores
it to the output array. A subgroup gets up to maxVertices points, with
provoking vertex 0 and point raster primitive topology.

Tested with Cocoon (PPSA08766) which now progresses past pipeline
creation and initial frame draws into gameplay.

AI-assisted: yes. Written with AI assistance and reviewed by me.
2026-10-20 22:26:30 -05: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
Adrià 0c54584946 Merge pull request #6611 from meh7an/perf/shader-validate-vertex-inputs
perf(shader): validate vertex stage inputs without building them
2026-10-20 22:28:45 +02:00
Dean baae66415c Merge pull request #5799 from SleglJan/fix/cube-output-modifiers
fix(shader): apply cube output modifiers whenever IEEE mode is off
2026-10-21 05:38:37 +13:00
Adrià b41a5ff685 Merge pull request #7516 from milescoviello/perf/f16-minmax-ordered-zero
perf(shader): leave out the both-zero select of f16 min and max
2026-10-20 17:26:28 +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
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
Mehran 5bb72c6b12 perf(shader): validate vertex stage inputs without building them 2026-10-20 15:18:49 +03:00
Adrià 25ab3510ca Merge pull request #7623 from thuanquang/fix/subvector-loop-exec-zero
fix(shader): test an empty exec mask in s_subvector_loop_begin with one compare
2026-10-20 01:41:41 +02:00
Adrià 1292e251c4 Merge pull request #7591 from mrfelek/fix/recompiler-offset-sgpr-reuse
fix(recompiler): fold draw offsets that the shader only reloads after the fetch add
2026-10-20 01:13:50 +02:00
Dean Galvin adf8e05f46 Merge main into pr-7042
# Conflicts:
#	core/shader/recompiler/Translation/include/Translation/TranslationContext.hpp
#	core/shader/recompiler/Translation/src/Float64Instructions.cpp
#	docs/dev/debt/shader.md
2026-10-20 09:25:06 +13:00
Dean 6d89a7bd8a Merge pull request #7036 from thuanquang/fix/f64-rounding-denormal-flush
fix(shader): flush f64 floor, ceil, fract and frexp denormal inputs
2026-10-20 09:22:37 +13:00
Adrià 602d8e66b1 Merge pull request #7429 from ps54all/feat/shader-ds-ordered-count-swap
feat(shader): model ds_ordered_count swap
2026-10-19 22:17:42 +02:00
Adrià 2232629a96 Merge pull request #7074 from CrimsonMac/fix/f16-fma-default-nan
fix(shader): give f16 fma invalid operations the default NaN
2026-10-19 19:56:30 +02:00
ps54allandClaude Opus 5.5 b0558ce95f feat(shader): model ds_ordered_count swap
A ds_ordered_count with offset1 bit 4 set swaps the first active lane's value into the GDS counter instead of adding it. Emit it as one device-scope atomic exchange through the same path as the ordered add, and return the counter's previous value to every active lane.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-19 16:41:03 +02:00
mrfelekandClaude Opus 5.5 2234121856 fix(recompiler): fold draw offsets that the shader only reloads after the fetch add
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01BywPXoZACVi8ALV4JKvuPZ
2026-10-19 16:15:55 +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à a5c5d1194a Merge pull request #6919 from yabanana/fix/indirect-offset-analysis
fix(recompiler): recognize plain no-carry draw offset adds
2026-10-19 15:39:55 +02:00
Crimson bd03daa4f2 fix(shader): give the default NaN for an f16 fma invalid product with a NaN src2 2026-10-19 14:57:35 +02:00
Crimson de82860c94 fix(shader): leave a NaN src2 of an f16 fma invalid product to the driver 2026-10-19 14:57:32 +02:00
Crimson e98cf7f9a0 fix(shader): give f16 fma invalid operations the default NaN
v_fma_f16, v_fmac_f16, v_fmamk_f16, v_fmaak_f16 and v_fma_mix_f32 with
f16 sources left the NaN of an invalid operation to the driver, so
inf * 0 gave 0x7fff and 0x7fffffff on NVIDIA where the hardware gives
the default NaN 0xfe00 and 0xffc00000. An inf * 0 product, or a NaN
from sources that are not NaN, now gives the default NaN; NaN sources
are still left to the driver.
2026-10-19 14:57:26 +02:00
Adrià 2b049317b8 Merge pull request #6850 from Ondra97/codex/fix-f64-compare-denormals
fix(shader): honor f64 comparison input denormal mode
2026-10-19 14:05:45 +02:00
thuanquangandClaude Opus 5.5 01ed9192ed fix(shader): flush v_add_f64 and v_mul_f64 denormals by the f64 field
v_add_f64 and v_mul_f64 ignored the FLOAT_MODE f16/f64 denormal field.
On RDNA2 (gfx1031) bit 6 clear flushes both inputs to a zero of their
sign, and bit 7 clear flushes a sum below 2^-1022 and a product whose
exact value rounded to 53 significant bits with an unbounded exponent
is below 2^-1022. The product test scales one source by 2^64 and
compares the host product with 2^-958.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-19 18:49:58 +07:00
thuanquangandClaude Opus 5.5 abea1bc710 fix(shader): flush f64 floor, ceil, fract and frexp denormal inputs
v_floor_f64, v_ceil_f64, v_fract_f64, v_frexp_mant_f64 and
v_frexp_exp_i32_f64 ignored the FLOAT_MODE f16/f64 denormal field. On
RDNA2 (gfx1031) bit 6 clear flushes a denormal input to a zero of its
sign, so v_ceil_f64 of 2^-1074 is 0 instead of 1, and bit 7 clear
flushes the denormal result v_fract_f64 gives for a positive denormal.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-19 18:34:17 +07: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à 118266aec2 Merge pull request #6760 from Ondra97/codex/fix-f64-minmax-denormals
fix(shader): honor f64 min and max input denormal mode
2026-10-19 12:27:39 +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 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
Dean 859017b4ce Merge pull request #7698 from tibzejoker/perf/f16-single-convert
perf(shader): convert one f16 value instead of an (x, 0.0) pair
2026-10-19 17:52:01 +13: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 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
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
thibautandClaude Opus 5.5 96bacb7eb8 perf(shader): convert one f16 value instead of an (x, 0.0) pair
ConvertF16F32 built an (x, 0.0) f32 pair and packed it, and unary f16 results
(v_rcp_f16, v_sqrt_f16, ...) were packed with a 0.0 high half: the constant half
went through the whole f32-to-f16 conversion each time, which without native
f16 is a bit-level rounding sequence. Both now convert the one value; the high
half of the bits is zero as before, so the results are the same.

Test: agc_f16_single_convert recompiles four v_rcp_f16 with and without native
f16 and requires no (x, 0.0) f32 pair; on main each case emits four.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01XBXM4pgkMHYEtqN1EQni2P
2026-10-19 03:07:05 +02:00
Yunus Shaikh 866ad41ea1 Merge main into fix/agc-sample-location-grid-exact
Keeps MultisampleTargetOrderTarget next to #6175's MultisampleTargetView, which now also returns the target's image.
2026-10-18 15:50:54 -07:00
Adrià 18bd700806 Merge pull request #6291 from santhoshkumar-dev/codex/fix-pixel-exec-helper-lanes
fix(shader): preserve pixel helper lanes in EXEC copies
2026-10-19 00:37:47 +02:00
thuanquangandClaude Opus 5.5 f65b4bbe91 fix(shader): test an empty exec mask in s_subvector_loop_begin with one compare
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-19 00:35:16 +07:00
milescovielloandClaude Opus 5.5 f099292f8c perf(shader): leave out the both-zero select of f16 min and max
minMaxF16Bits compares the halves as ordered integers (the low 16 bits
sign-extended, with the magnitude bits of a negative half inverted),
then replaced the result when both halves were zero: max took a & b and
min took a | b. The ordered integers already put -0 (-1) below +0 (0),
so the compare picks +0 for max and -0 for min, which is what the
both-zero select produced. Every caller passes halves with their upper
16 bits clear (readF16Bits masks them, the packed path extracts them),
and for those all 2^32 pairs of each give the same bits with and
without the select. Each f16 min, max, min3, max3 and med3 now emits
five instructions fewer per pair.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-18 10:31:17 +00:00
Dean Galvin 5db206aba0 fix(agc): read the depth remap scale and offset from push constants at run time
The remap mode stays a specialization constant and cache key input. Scale and
offset are two push words at byte 104, patched per draw, so draws that differ
only in depth range share one pipeline. The recipe, journal and serializer
carry the mode only.
2026-10-18 19:01:14 +13:00
Yunus Shaikh 8f6f7d7500 Merge main into fix/agc-sample-location-grid-exact 2026-10-17 19:10:21 -07:00
Mouad-Scriptz-0andClaude Fable 5.1 53212b18ac feat(agc): remap a viewport depth range the device cannot express into the vertex shader
Without VK_EXT_depth_range_unrestricted a viewport depth range outside
[0, 1] threw. Minecraft (PPSA17221) draws its world with scale 1 and
offset 0 in negative-one-to-one clip space, so its depth is the raw z/w
clamped by PA_SC_VPORT_ZMIN/ZMAX. On such a device the vertex shader now
scales clip z so z/w is the console's depth, the pipeline clamps depth at
the console's bounds, and two clip distances restore the near and far
planes that depth clamping removes. Mode, scale and offset travel as
pipeline specialization constants from the draw's vertex stage info, in
both the per-draw and the registration-module path; mesh and tessellation
draws with such a range still throw.

The console's depth clamp bounds are clipped to [0, 1]: exact for a
normalized depth target or none, and reported once for a tested or
written float depth target, where a depth below 0 is stored as 0
(Minecraft clamps its float depth target to [-1, 1]). The shader
validator accepts the remap's two extra clip distances next to the one
a program may already export.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
2026-10-18 14:27:48 +13:00
Ondra97 c4e9c431b5 chore: merge main into f64 minmax denormal fix 2026-10-18 02:28:30 +02:00
Yunus Shaikh ddf072e6f3 Merge main into fix/recompiler-once-per-pixel-sample-inputs
Main's EmitSetAttribute debt entry now says the generated rect-list and
barycentric tessellation stages forward the vertex shader's clip array.
It sits next to this branch's PERSP_SAMPLE and pixel position entries,
which main left as they were; keep main's entry and this branch's two.
2026-10-17 17:03:27 -07:00
thuanquangandClaude Opus 5.5 a314f2b85f fix(shader): flush f64 floor, ceil, fract and frexp denormal inputs
v_floor_f64, v_ceil_f64, v_fract_f64, v_frexp_mant_f64 and
v_frexp_exp_i32_f64 ignored the FLOAT_MODE f16/f64 denormal field. On
RDNA2 (gfx1031) bit 6 clear flushes a denormal input to a zero of its
sign, so v_ceil_f64 of 2^-1074 is 0 instead of 1, and bit 7 clear
flushes the denormal result v_fract_f64 gives for a positive denormal.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-18 01:54:10 +07:00