Commit Graph
437 Commits
Author SHA1 Message Date
Adrià 16452da934 Merge pull request #13681 from brumskysb/measure/f64-compare-denormal-modes
docs(shader): record the measured f64 compare denormal modes
2026-10-31 19:54:22 +01:00
Adrià ab1c3b8b63 Merge pull request #13341 from frankea/feat/f64-integer-emulation
feat(shader): compute f64 add, mul and f32 conversions with integers on devices without Float64
2026-10-31 01:26:50 +01:00
brumskysb 83e745132c docs(shader): record the measured f64 compare denormal modes
The four-mode matrix of the FLOAT_MODE f16/f64 denormal field was pinned from the
RDNA2 ISA and from LLVM but never measured on hardware. Measured on RDNA2 (gfx1036,
AMD Windows driver 31.0.22044.1) with the hardware oracle over the 22-value f64 edge
set of VopcCompareF64 as all 484 operand pairs, with the 16 v_cmp_*_f64 predicates,
at IEEE off and on and each f16/f64 denormal mode 0 to 3: modes 0 and 2 flush, modes
1 and 3 keep, the IEEE bit changes neither, and class compares select from the
pre-flush bits. The sign of the flushed zero is not observable by a compare. The
PS5's gfx1013 stays unmeasured.
2026-10-30 16:38:34 -07:00
AdriàandClaude Sonnet 5.5 30e8559f63 docs(shader): record the integer path for f64 add, mul and f32 conversions
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
2026-10-30 19:15:51 +01:00
Roojool a6d1bcbd12 docs(shader): separate comparison limits from shared lowering 2026-10-30 19:29:38 +05:30
5a32581256 fix(shader): round emulated array sampling half to even
Carry the RoundEven and unordered NOT_EQUAL fixes from #907, with
ThisIsAkill's invitation, onto the current constant-zero comparison path.
Keep TRUNC_COORD accepted for that path and retain the newer format rules.

Exercise array rounding through converted unorm sampling, where selecting
the wrong layer changes the result. Preserve zero comparisons for half-float
NaNs, signed zero, GREATER, NOT_EQUAL and TRUNC_COORD. Record the inherited
RDNA2 measurement basis and the limits of these host tests.

Co-Authored-By: Akhil Moola <[email protected]>
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-30 19:27:47 +05:30
Dean 51c31ea17e Merge pull request #13258 from ntamas94/fix/gcn-sin-linear-range
fix(shader): keep GCN v_sin_f32 linear up to 1.5 x 2^-12 of a turn as the PS4 does
2026-10-31 00:52:52 +13:00
Adrià f8124b820b Merge pull request #13122 from johnohhh1/fix/spirv-literal-float-initialization
fix(build): initialize bundled SPIRV literal-float encoding
2026-10-30 12:46:11 +01:00
Adrià 25ff0a6d88 Merge pull request #12561 from milescoviello/fix/msaa-sample-adjusted
fix(shader): read a 2D MSAA T# through image_sample_a as its sample 0
2026-10-30 10:56:12 +01:00
ntamas94andClaude Opus 5.5 807442da20 fix(shader): keep GCN v_sin_f32 linear up to 1.5 x 2^-12 of a turn as the PS4 does
A PS4 Pro (GCN, firmware 10.71) returns the input times 0x40c90fd5 for
every v_sin_f32 input below 0x39c00000 (1.5 x 2^-12 of a turn) and for
none at or above it, over 12,288 consecutive inputs of each sign across
that boundary and 65,536 random inputs from 2^-24 to 1 turn. The linear
band from 909281c994 ends at 2^-12, as measured on RDNA2, so PS4 guest
shaders took the driver sine or the series in [2^-12, 1.5 x 2^-12),
where the PS4 is 5 ULP away from the true sine.

PS4 guest shaders now keep the integer band of v_sin_f32 up to
0x39c00000. The half- and quarter-turn bands keep 2^-12: there the PS4
is within 6 ULP of the f32 2pi term and is not linear. PS5 shaders are
unchanged.

GcnSinNearZero runs a GCN compute kernel over PS4-measured inputs; it
fails without the change (0x39bf48b8 gives 0x3b163be8, the PS4 returns
0x3b163bed).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-30 09:23:09 +01:00
johnohhh1 ed4c3974c1 fix(build): initialize bundled SPIRV literal-float encoding 2026-10-29 22:35:53 -04:00
Adrià d0cf19b2cb Merge pull request #12233 from beardsciences/fix/nvidia-mesh-window-buffer
fix(shader): keep mesh register windows out of local memory on NVIDIA
2026-10-30 02:31:36 +01:00
Adrià f46f453a56 Merge pull request #12724 from Gonic0/fix/shader-single-lane-elected-max
fix(shader): give one-lane waves an elected atomic max per lane
2026-10-30 00:18:15 +01:00
Adrià 5e6c22e772 Merge pull request #12208 from XairRrR/fix/shader-srt-read-below-loaded-pointer
fix(shader): poison an SRT read below a pointer loaded from memory
2026-10-29 21:52:04 +01:00
Christian 6f79055a00 fix(shader): keep mesh register windows out of local memory on NVIDIA
On NVIDIA's proprietary driver, function arrays that live in local memory
and are read under a data-dependent branch return wrong values in
subgroups 1-3 of a mesh workgroup; subgroup 0 is correct. A wave64
geometry program whose relative addressing keeps its VGPRs in the vector
window therefore loses register writes in every wave but the first. In
the clipping geometry program of Sony's PS5 PSP emulator (PPSA07550) the
empty waves never cleared their candidate primitive slots and wrote
degenerate triangles over wave 0's, so the 3D menu drew spikes.

On that driver a mesh program's window now lives in a device-local
storage buffer of 256 workgroup slots of 65536 dwords, claimed through a
per-slot lock and released after the final barrier. The pool is created
before the first draw that uses it records anything, and its header is
zeroed in a batch of its own that is submitted and waited for; the pool
is published only after that wait, and a failure releases it. Direct
register accesses keep one function variable per register; a direct
store also writes the buffer when a buffer read can see it, relative
reads load the buffer, relative writes store only to it, and a direct
read that may follow a relative write loads the buffer and refreshes the
variable. A buffer entry is zeroed only when a buffer read can see it
before a write. APS5_NO_MESH_WINDOW_BUFFER=1 keeps the arrays.
2026-10-29 08:56:39 -04:00
Adrià 1ac12cc534 Merge pull request #10803 from slopgobblercobbler/fix/spirv-instruction-word-bounds
fix(shader): validate SPIR-V instruction word count boundaries and phi patching
2026-10-29 13:48:55 +01:00
Dean ba5b5330b3 Merge pull request #12706 from Gonic0/fix/agc-barycentric-patches-restart
fix(agc): draw compacted restart lists and restart-free strips through the barycentric patches
2026-10-29 23:56:52 +13:00
Adrià 9f04702aee Merge pull request #10831 from cgrd/fix/buffer-vsharp-type-stores
fix(shader): drop vector stores through TYPE 2/3 and FORMAT 0 buffer V#s as measured
2026-10-29 11:21:59 +01:00
Nicolas GonzalezandClaude Opus 5.5 5ff5075544 fix(shader): give one-lane waves an elected atomic max per lane
On a one-lane wave (vertex and local programs without vertex subgroups,
merged hull programs), a wave64 f32 max half-wave scan threw at its
v_permlanex16_b32. When the scan's lane 31 and 63 reads only elect,
through v_cmpx_eq_f32 against each lane's own key, the lanes that
buffer_atomic_umax or smax that maximum at a wave-uniform address with an
unused result, each invocation now takes its own key: every active lane
writes it, and memory ends with the wave's maximum because the keys are
proven non-negative and not NaN. The permutation, whose value then
reaches no other result, keeps its own value.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-29 02:04:56 -03:00
milescovielloandClaude Opus 5.5 90efd76e2a docs(shader): give image_sample_a of a 2D MSAA T# its own debt entry
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-29 04:27:49 +00:00
Nicolas GonzalezandClaude Opus 5.5 95e7deeaab fix(agc): draw compacted restart lists and restart-free strips through the barycentric patches
The barycentric tessellation path refused any draw with the primitive
restart bit set. A non-indexed strip ignores the bit, and on a device
without VK_EXT_primitive_topology_list_restart a list never restarts on
the host, since its indices are compacted on the CPU first, so both now
take the patches. Indexed strips with primitive restart still throw,
now also in Graphics::Draw, which knows the draw is indexed.
Patch-list pipelines never enable primitive restart, which Vulkan does not
allow for them without primitiveTopologyPatchListRestart.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-29 00:56:03 -03:00
Dean b433c40f2f Merge pull request #12251 from Michael-KD/fix/div-scale-fixup-f32-denormal-modes
fix(shader): translate v_div_scale_f32 and v_div_fixup_f32 in f32 denormal modes 1 and 2
2026-10-29 16:25:43 +13:00
milescovielloandClaude Opus 5.5 1273808212 fix(shader): read a 2D MSAA T# through image_sample_a as its sample 0
The _a sample forms only change how dword 3 of the S# is read, so an image_sample_a of a 2D MSAA T# now takes the same sample-0 path as image_sample: the tracker leaves the adjust flag out of its plain-sample check. Ghost of Tsushima's pixel shader 0x20054f4e00 samples its two-sample checkerboard depth this way and stopped with "image descriptor is incompatible with the static runtime image interface".

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-28 18:45:46 +00:00
XairRrR 91bbd2fca5 fix(shader): poison an SRT read below a pointer loaded from memory
A read at a negative offset from a pointer the walker loaded from guest
memory (a null pointer behind a guarded branch, offset -4) wrapped below
zero in AddSignedAddress, and the walk threw "cannot evaluate" instead of
recording the read as inaccessible. Uncharted: The Lost Legacy threw it
while loading its first level. The read is now recorded as an SRT poison
at its address wrapped to 48 bits, like any other unreadable address, so
the binding faults only if the shader takes that path.

verifyGuardedNullPointers gains the case for both branch outcomes; it
throws the title's error without the change.

AI-assisted: yes
2026-10-28 18:47:47 +01:00
Adrià 123f7f3b60 fix(shader): keep multi-dword TYPE 2/3 stores throwing and move the failed-capture fixture to TYPE 1 2026-10-28 14:42:32 +01:00
cgrdandClaude Opus 5.5 4620e29426 fix(shader): drop vector stores through TYPE 2/3 and FORMAT 0 buffer V#s as measured
A buffer V# whose TYPE is not 0 threw "buffer descriptor uses an
unsupported type" for every access. Measured on a PS5 (CFI-1115B,
firmware 12.20): through a V# with TYPE 2 or 3 and FORMAT 0 or a valid
format, buffer_store_dword and buffer_store_format_x write nothing and
don't fault, so a buffer a shader only stores to through one is bound as
a null V#. Loads and atomics through those V#s leave the destination VGPR
unchanged, which a null V# can't reproduce, so they still throw. Through
a TYPE 0, FORMAT 0 V#, vector loads return 0 and stores are dropped, and
those buffers are bound as a null V# too. TYPE 1 faults the GPU for every
access measured and keeps throwing.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-28 14:42:23 +01:00
Dean 0c4d871f18 Merge pull request #12253 from Michael-KD/fix/fma-f32-denormal-modes
fix(shader): translate the fused f32 fma forms in f32 denormal mode 2
2026-10-29 00:32:38 +13:00
Dean 7d223dd6da Merge pull request #12252 from Michael-KD/fix/f32-rounding-frexp-denormal-modes
fix(shader): translate f32 fract, floor, ceil and frexp_mant in f32 denormal modes 1 and 2
2026-10-29 00:32:22 +13:00
Dean 3a40945e62 Merge pull request #12298 from oneandonlydean/revert-11199-helper-lane-masks
revert(shader): restore pixel helper lanes in guest lane masks (#11199)
2026-10-28 22:57:31 +13:00
Dean 3917fa85ce Merge pull request #12188 from Gonic0/fix/shader-lds-lock-fences-moltenvk
fix(shader): fence the LDS lock's critical section on MoltenVK
2026-10-28 22:51:00 +13:00
Dean b332780eec revert(shader): restore pixel helper lanes in guest lane masks (#11199)
This reverts merge 7fc0ae6008. On NVIDIA, where helper lanes take part in ballots, clearing helper bits from every pixel ballot breaks derivatives along triangle edges (bright lines and specks on a cloud surface in PPSA21564). See the report on #11199.
2026-10-28 22:11:10 +13:00
Adrià 0fe94e2883 fix(shader): drop unreachable phi counter check, move debt line off section end 2026-10-28 09:17:36 +01:00
slopgobblercobbler fccfd18dcd fix(shader): validate SPIR-V instruction word count boundaries and phi patching 2026-10-28 09:17:32 +01:00
Adrià 7fc0ae6008 Merge pull request #11199 from QRMOE/fix/shader-pixel-helper-lane-masks
fix(shader): keep pixel helper lanes out of guest lane masks
2026-10-28 08:54:16 +01:00
Michael Krumland-DunningandClaude Opus 5.5 254d7b416f fix(shader): translate the fused f32 fma forms in f32 denormal mode 2
v_fma_f32, v_fmac_f32, v_fmamk_f32 and v_fmaak_f32 threw "f32 denormal
mode 2 is not implemented" whenever FLOAT_MODE flushed f32 denormal
inputs but kept denormal results.

On RDNA2 (gfx1036) at round to nearest even, mode 2 flushes the inputs
and rounds the fused result once with gradual underflow, which the host's
Fma gives under DenormPreserve 32. The translation now matches all 5,596
measured triples for the four forms at IEEE 0 and 1. Mode 1 keeps
throwing: there the hardware flushes a result that is tiny after rounding
with an unbounded exponent even when the addend is nonzero.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-27 22:05:57 -07:00
Michael Krumland-DunningandClaude Opus 5.5 126b7b98a0 fix(shader): translate f32 fract, floor, ceil and frexp_mant in f32 denormal modes 1 and 2
All four threw "f32 denormal mode N is not implemented" whenever
FLOAT_MODE kept only one side of the f32 denormals.

On RDNA2 (gfx1036), in every f32 round mode and at IEEE 0 and 1, mode 2
gives the results of mode 0 and mode 1 those of mode 3 with a denormal
result flushed, which only v_fract_f32 of a positive denormal produces.
The translation now matches all 118 measured inputs in modes 1 and 2.
Mode 1 of the three that run host float operations on a kept denormal
needs DenormPreserve 32, as v_min_f32 does.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-27 22:05:57 -07:00
Michael Krumland-DunningandClaude Opus 5.5 2295183c6c fix(shader): translate v_div_scale_f32 and v_div_fixup_f32 in f32 denormal modes 1 and 2
Both threw "f32 denormal mode N is not implemented" whenever FLOAT_MODE
kept only one side of the f32 denormals, so any LLVM-compiled f32
division in such a shader failed to translate.

On RDNA2 (gfx1036) at round to nearest even, v_div_fixup_f32 follows bit
0 of the field, and v_div_scale_f32 flushes its inputs in mode 2 as in
mode 0 and in mode 1 keeps them and flushes a denormal result, with the
VCC of mode 3. The translation now matches all 2,304 measured rows in
modes 1 and 2 at IEEE 0 and 1. Directed rounding still throws, as an
underflowing v_div_fixup_f32 result rounds to the smallest denormal there.

Division and F32DenormalFlush no longer require modes 1 and 2 to be
refused; Division checks v_div_scale_f32 in them against its measured
vectors instead.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-27 22:05:56 -07:00
Nicolas GonzalezandClaude Opus 5.5 2f25ab919f fix(shader): fence the LDS lock's critical section on MoltenVK
SPIRV-Cross emits the lock's acquire compare-exchange and release
exchange as relaxed Metal atomics, so the plain LDS loads and stores of
a locked 64-bit update were not ordered against the lock and contended
ds_add_u64 lost updates on an Apple M5 Pro. On MoltenVK the driver now sets
SpirvTarget::ldsLockFences, and the lock brackets its critical section
with workgroup-scope acquire and release OpMemoryBarriers, which become
threadgroup atomic_thread_fence with no execution barrier.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-27 23:37:56 -03:00
Adrià e0cd1259a9 Merge pull request #11254 from Michael-KD/fix/scalar-buffer-runtime-word3
fix(shader): ignore a runtime V#'s type for scalar buffer loads as RDNA2 does
2026-10-27 16:28:28 +01:00
Adrià 6f7cb75291 Merge pull request #9193 from imellag/feat/shader-barycentric-builtins-moltenvk
feat(recompiler): read I/J from barycentric built-ins on MoltenVK
2026-10-27 16:21:05 +01:00
Adrià 768e92f8b6 Merge pull request #9743 from frankea/fix/hull-reads-control-point-outputs
fix(shader): read other control points' off-chip outputs in hull programs
2026-10-27 12:00:31 +01:00
Adrià edabe9efa1 Merge pull request #11255 from Michael-KD/docs/vcc-descriptor-tuples-measured
docs(shader): record the VCC descriptor tuples measured on RDNA2
2026-10-27 08:28:15 +01:00
Adrià 42317c7f32 Merge pull request #11256 from Michael-KD/docs/array-comparison-through-2d-measured
docs(shader): record 2D-array comparison samples measured on RDNA2
2026-10-27 08:27:36 +01:00
Emanuele 03f7c1134f fix(shader): keep the position read of barycentric built-ins on MoltenVK
The I/J reads take the BaryCoordSmooth input, but gl_FragCoord was declared
only for the offset kinds, so its w was read as the constant 0 and the
fragment function never read [[position]]; Apple GPUs then return the
weights unnormalized. Declare it with the built-in, and select on
gl_FragCoord.w > 0, which a compiler cannot fold as it can
min(b, b + |w|).
2026-10-27 07:25:48 +01:00
Emanueleandyripper a95ced504c feat(recompiler): read I/J from barycentric built-ins on MoltenVK
MoltenVK exposes VK_KHR_fragment_shader_barycentric but its MSL step
rejects PerVertexKHR, so the extension is disabled there and a pixel
shader whose I/J VGPRs outlive their v_interp_p1/p2 pairs takes the
generated barycentric stages, which accept only triangle lists without
primitive restart on a device without geometry shaders.

A new target flag, fragmentBarycentricBuiltins, enables the extension
for its built-ins only. The host interpolation check then keeps the
leftover I/J reads (all perspective or all linear, at the fragment's
default position) and reads them from BaryCoordKHR or
BaryCoordNoPerspKHR, while the interpolated attributes stay hardware
varyings. Raw vertex parameters and I/J at an offset or a sample
position still take the generated stages. Apple GPUs return
unnormalized perspective weights unless the fragment function reads
[[position]], so each perspective read keeps a neutral use of
gl_FragCoord.w, loaded as a float. Devices with the full extension are
unaffected; the request serialization moves to version 45.

Co-authored-by: yripper <[email protected]>
2026-10-27 07:25:48 +01:00
Dean a453b29ebe Merge pull request #11434 from LeandroLP23/test/shader-cache-smb-posix-rename
test(shader): skip open-entry cache replacements where SMB has no POSIX rename
2026-10-27 18:38:46 +13:00
frankea 909a2f1f3b fix(shader): read other control points' off-chip outputs in hull programs 2026-10-27 03:47:24 +01:00
Dean d471a12b82 Merge pull request #11112 from Bram910/fix/shader-skip-unreachable-words
fix(shader): skip undecodable words that only follow s_branch or s_endpgm
2026-10-27 15:00:43 +13:00
Dean 37c6b4bc25 Merge pull request #8077 from 0xcrstn/ufc6/descriptor-web-fold
fix(shader): split descriptor webs whose paths fold or hold invalid arms
2026-10-27 14:56:47 +13:00
Dean d1de04f943 Merge pull request #7484 from AlxcBTW/pr/robust-loads
perf(recompiler): leave the descriptor-range comparison out of direct buffer loads when the device zeroes past the range
2026-10-27 14:56:32 +13:00