233 Commits
Author SHA1 Message Date
Adrià f5fefb982c Merge pull request #11305 from joedeangelis533-bot/review/tessellation-depth-upstream-20261025
feat(agc): remap unsupported tessellation viewport depth ranges
2026-10-27 22:27:35 +01:00
Adrià b9623a5c26 Merge pull request #11297 from mrfelek/perf/probe-f32-flush-nvidia
perf(agc): use the NVIDIA driver's f32 denormal flush when the startup probe matches
2026-10-27 22:09:23 +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 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
Dean 630211a866 Merge pull request #6612 from milescoviello/feat/tess-geometry
feat(agc): draw tessellation followed by an NGG geometry stage
2026-10-27 14:56:18 +13:00
Dean 82358b124e Merge pull request #10976 from slick-daddy/perf/redundant-sort-hotpath
chore(shader): skip redundant sort/unique on single-element otherReads
2026-10-27 14:27:18 +13:00
0xcrstnandClaude Opus 5.5 ec06ba2973 fix(agc): read back descriptor faults of shaders that also use image tables
A shader with an image table map read its fault buffer back only when a
table record was poisoned, an SRT read was poisoned, it had window lane
guards or the loop guard was on. A DescriptorFault only set the fault
buffer, so with a valid table and no copied write nothing ran the fault
check, and a lane that took a folded descriptor web path or selected an
undefined arm read arm 0 or zeros with no report.

The compiled artifact now counts its DescriptorFault instructions
(descriptorFaults, stored in the shader disk cache, format 48), and the
readback gate requests the fault check when it is nonzero. The result a
capture materializes copies the count, and also windowLaneGuards, which
that copy had dropped, so the gate's window lane guard condition never
saw it. sizeof(CompiledShaderArtifact) is 288 and sizeof(RecompileResult)
552 with the new field.

agc_driver_descriptor_web_faults adds a wave32 shader that reads an image
table and then the descriptor web, storing only to LDS so no copied write
forces completion: it binds an image table and no BDA address table, a
valid arm and an unselected undefined arm stay clean, the folded path and
a selected undefined arm fault at the read, and nothing faults with EXEC
empty. Without the gate change the folded case does not fault.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-26 14:46:11 +02:00
joedeangelis533-bot 724a4fcde8 feat(agc): remap unsupported tessellation viewport depth ranges 2026-10-26 06:13:51 -04:00
Dean Galvin e0bd61fae2 Merge branch 'main' into pr/robust-loads 2026-10-26 23:10:10 +13:00
mrfelek 3e7a0ae671 fix(shader): keep the f32 floor and ceil flush where the device flushes by default
NVIDIA's proprietary driver flushes f32 add, multiply and fma denormals by default but not the inputs of floor and ceil, so its startup probe failed only on those two. Drop their software flush only where the device declares DenormFlushToZero 32.
2026-10-26 08:57:06 +00:00
milescovielloandClaude Opus 5.5 8868e09624 fix(shader): bound the bytes the recompiler's result memos hold
Every shader source keeps up to 256 materialized results of
Recompile(request, capture) in its result memo, and as many patch
recipes in its masked memo, with no limit on their bytes. In Ghost of
Tsushima's opening the memos held about 500 MiB after 5 minutes and
kept growing, at a 13 % hit rate.

Each memo entry now counts the bytes its result's vectors keep (the
bindings' vectors included; the module is shared with the prepared
module cache), plus its patch recipe in the masked memo. A result held
by both tables counts once in each. Past a budget, 256 MiB unless
APS5_RESULT_MEMO_MB sets another (0 sets none), the least recently used
entries of both tables of all sources are dropped until three quarters
of the budget is left. The recency stamps come from one clock for all
sources and both tables so they compare across them. The profile line
also reports the trimmed and held entries and their MiB.

The trim takes its lock blocking and repeats, re-reading the bytes held,
until they are within the budget, so the insertion that pushed them
over has its trim run after any other; it stops when nothing is left to
drop.

SetResultMemoBudget and ResultMemoBytes let agc_shader_result_memo_budget
check that a memo over its budget keeps the most recently used results
and drops the oldest one, with the masked memo off. A one-shot hook
inside the trim (SetResultMemoTrimHook) lets
agc_shader_result_memo_budget_threads insert two results from other
threads after the trim has read the bytes held: the memo must still end
within its budget. agc_shader_result_memo_budget_masked, with the masked
memo on, checks that a first result counts its masked entry too and that
a trim empties the masked memo.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-26 05:04:18 +00:00
Slick Daddy 16507a99f8 perf(shader): skip redundant sort/unique on single-element otherReads 2026-10-25 14:41:31 +03:00
Adrià 66e6772ca2 Merge pull request #10473 from milescoviello/fix/release-unused-specialized-modules
fix(shader): release specialized modules that no result uses
2026-10-25 11:58:42 +01:00
Adrià 75227c7cdc Merge pull request #10423 from meh7an/perf/shader-masked-result-memo
perf(shader): reuse a memoized result by patching its copied words
2026-10-25 11:50:14 +01:00
milescovielloandClaude Opus 5.5 cd5fc9e838 feat(agc): draw tessellation followed by an NGG geometry stage
Crimson Desert (PPSA25286) draws with VGT_SHADER_STAGES_EN 0x60212d:
local, hull, domain and NGG geometry stages, the hull halves merged in one
registered type-3 program, the domain and geometry halves in one type-2
program. The domain half runs as the tessellation evaluation stage and
captures each vertex's ESGS item, and a mesh shader runs the geometry half
on the captured items.

Registered type-3 merged hulls come from #6679; this adds 16-bit LDS
reads and writes in tessellation stages, which Crimson Desert's merged
hull uses.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-25 08:32:37 +00:00
Dean Galvin eb3dd54501 Merge main into pr/robust-loads 2026-10-25 12:15:18 +13:00
Adrià e7e99adcc4 Merge pull request #6010 from zmeizy/claude/add-mul-f32-denormal-modes
fix(shader): translate f32 add and multiply in f32 denormal modes 1 a…
2026-10-24 18:20:07 +02:00
Adrià 893f1a067a Merge pull request #10496 from milescoviello/fix/share-identical-resource-plans
fix(shader): share resource plans loaded from the same disk cache payload
2026-10-24 11:54:07 +02:00
milescovielloandClaude Opus 5.5 0e1767b24b fix(shader): release specialized modules that no result uses
The specialized module caches (by variant and constants, by binding plan
and by registration key) and the SPIR-V interning table held every
module's words for the rest of the run, after the results that used them
were gone. They now keep a module's interface (bindings, push data,
specialization ID and content hash) and only a weak reference to its
words; a lookup after the words were released builds them again from the
same key, checks the content hash, and keeps the specialization ID that
names the module's pipelines. The interning table keeps weak references
and drops expired ones from the bucket it searches.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-24 10:22:05 +02:00
milescovielloandClaude Opus 5.5 38ac888dbb fix(shader): share resource plans loaded from the same disk cache payload
A shader source loading its resource plan from the disk cache decoded
its own copy, also when another source had already loaded the same
plan: the same code registered under another plan key (another host
subgroup size or interface) stores byte-identical plan entries. In Ghost
of Tsushima's cache, 14,043 plan entries hold 8,170 distinct payloads.
Loaded plans now go through a table of weak references keyed by two
hashes of the payload, its size and the shader address the plan carries,
so equal payloads for one shader decode once and share the plan, its
compact form and its compiled SRT tape while any source uses it.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-24 04:23:05 +00:00
valenciana-nc 42424dd55e fix(agc): include descriptor words in vertex validation errors 2026-10-23 20:44:39 -06:00
Dean f45a8d2bdc Merge pull request #9274 from zmeizy/claude/f32-hardware-flush-float-mode
fix(shader): take the hardware f32 flush only in shaders that flush f32 denormals
2026-10-24 14:20:09 +13:00
Mehran 54d7c780a5 perf(shader): reuse a memoized result by patching its copied words 2026-10-24 01:17:14 +03:00
Adrià e7f46f5c89 Merge pull request #8489 from wachi35676/fix/shader-amd-lds-fence-scope
fix(shader): widen LDS atomic fences to device scope on AMD's proprietary driver
2026-10-24 00:02:07 +02:00
Adrià dcd7e3a61e Merge pull request #8564 from JAB-dev/feat/agc-4-4-4-4-partial-writes
feat(agc): merge partial writes into 4_4_4_4 UNORM color targets
2026-10-23 23:23:11 +02:00
Adrià a0e858ff7b Merge pull request #8881 from thuanquang/fix/writelane-spill-window
fix(shader): keep a v_writelane lane known across computed-index window stores
2026-10-23 23:17:12 +02:00
Adrià 11e8ad2934 Merge pull request #8713 from SeifKaroui/fix/shader-unused-phi-cycles
fix(shader): remove unused phi cycles before resource planning
2026-10-23 22:46:22 +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
Muhammad Wasif Ali WasifandClaude Opus 5.5 98df163cc6 fix(shader): widen LDS atomic fences to device scope on AMD's proprietary driver
The recompiler orders an LDS atomic, and the compare-exchange loop that
writes a byte or a halfword of LDS (ds_write_b8/b16), with a
workgroup-scope OpMemoryBarrier after the update. AMD's proprietary
Windows driver 32.0.21042.62 (Radeon 0x13c0, RDNA 2) compiles that
memory barrier to s_barrier, as the code objects in its pipeline cache
show. Such updates usually sit in branches that only some waves of a
workgroup take, so those waves execute extra s_barriers, which pair
with the other waves' barriers, and the other waves read LDS before it
is written. An OpMemoryBarrier is not an execution barrier and SPIR-V
allows it in non-uniform control flow, so the SPIR-V is valid; a
device-scope OpMemoryBarrier compiles to GL0 and GL1 cache
invalidations without s_barrier there.

PS5LM Plus (PPSA99581, llama.cpp's Vulkan backend) drifted into
garbage on that driver with flash attention on. Its flash-attention
shader stores two halfwords to LDS in a branch that two of its four
waves take, inside the KV loop. The driver's code had 23 s_barrier for
the guest's 21; a replay of the dispatch differed from NVIDIA in 159
words, up to 1.7e38, and now has 21 and differs only in the last bit
of 9 words.

On that driver the fence is now device scope, which orders everything
the workgroup-scope fence did. Other drivers keep the workgroup scope.
The flag is part of the shader cache key, and agc_shader_replay takes
--device-scope-lds-memory-barriers to replay a request the way that
driver compiles it. The LDS update helper already fences, so the
second, identical fence after it in ds_min/max_f32 and the other
read-modify-write LDS operations is dropped.

agc_driver_lds_subword_store_branch stores a halfword to LDS in a
branch that waves 0-1 of four take, delays those waves and then
exchanges LDS slots across one s_barrier. Before, thread 64 read a
stale slot on the AMD driver; it passes on AMD and NVIDIA now.
agc_subgroup_barrier checks the driver quirk and that ds_write_b16,
ds_add_u32 and ds_max_f32 each emit one fence of the expected scope.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01BM2kfDbr6MydxsfTckZJDR
2026-10-23 20:34:25 +02:00
Adrià a19e7f6fdc Merge pull request #7888 from mazen320/fix/pixel-function-lds-buffer
fix(shader): keep an unbounded pixel LDS array in a storage buffer
2026-10-23 20:12:31 +02:00
Adrià d42c9617c8 Merge pull request #8340 from milescoviello/fix/share-identical-specialized-spirv
fix(shader): share the words of identical specialized modules
2026-10-23 20:08:22 +02: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
mazen 287b149950 fix(shader): keep an unbounded pixel LDS array in a storage buffer
A Function array of 8192 dwords faults NVIDIA driver 617.42. The guest array stays that size, and each invocation gets its own region in a buffer.
2026-10-23 20:52:46 +04:00
Adrià b066e5cb77 Merge pull request #8145 from TheSovietWaffle/fix/recompiler-stencil-replay-readonly-bda
fix(recompiler): replay stencil exports of pixel shaders that only read through BDA
2026-10-23 18:46:24 +02:00
Adrià 68810f6342 Merge pull request #7816 from Capmare/fix/shader-frontend-call-analysis-wave-size
fix(shader): give the frontend's call analysis the dispatch's wave size
2026-10-23 17:38:03 +02:00
Adrià 6b2d6af510 Merge pull request #8612 from imellag/perf/shader-fused-exact-arithmetic-moltenvk
perf(shader): emit exact f32 add, subtract and multiply as fma on MoltenVK
2026-10-23 14:30:16 +02:00
Adrià 362d702c1d Merge pull request #7817 from JJenkx/fix/shader-specialized-bda-abi
fix(shader): clear BDA ABI after removing address bindings
2026-10-23 13:28:24 +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 870bacd092 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 08:59:06 +02:00
MarcZX10 f6826208fb fix(shader): normalize offset perspective barycentrics 2026-10-23 06:32:27 +02:00
zmeizyandClaude Opus 5.5 6a2614077a fix(shader): translate f32 add and multiply in f32 denormal modes 1 and 2
v_add_f32, v_sub_f32, v_subrev_f32, v_mul_f32 and v_mul_legacy_f32
follow the FLOAT_MODE f32 denormal field with f32 round to nearest
even, as measured on RDNA2 (gfx1030): mode 1 keeps denormal inputs and
flushes a denormal result, and mode 2 flushes denormal inputs and keeps
a denormal result. Both need the device to keep the f32 denormals the
shader keeps, so they translate only when the module declares
DenormPreserve 32 and throw otherwise. The result flush now applies
when only the result flush bit is set; it was skipped unless the input
flush bit was set too. A constant factor no longer skips the tiny
product check while denormal inputs are kept, as a kept denormal times
such a constant can still be tiny. Directed rounding in these modes
still throws.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-22 22:45:56 +03: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 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
AlxcBTW 16259facef Merge branch 'main' into pr/robust-loads 2026-10-21 23:21:03 +02: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
zmeizyandClaude Opus 5.5 959efbb8d3 fix(shader): take the hardware f32 flush only in shaders that flush f32 denormals
When the startup probe chose the hardware f32 flush, every module declared
DenormFlushToZero 32, also shaders whose FLOAT_MODE keeps f32 denormals
(f32 denormal field 1, 2 or 3), so the device flushed what they keep and
DenormPreserve 32 was never declared. The hardware flush now applies to
shaders that flush f32 denormals (field 0, or no float mode); the others
declare DenormPreserve 32 where the device supports it.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-21 18:34:55 +03:00
1a74a6cdd9 fix(shader): keep a v_writelane lane known across computed-index window stores
fdfawef324 notes that current LLVM spills SGPRs into VGPRs it allocates like any other
register, so one window register can be an ordinary register early in a
program and hold spill lanes later. ReadLaneEliminator only followed a
spilled lane across M0-indexed window stores for slots never used as
ordinary registers, so RESIDENT EVIL 4 (PPSA07411) and LEGO Horizon
Adventures (PPSA14632) kept their reloaded descriptors as run-time
values and stopped. A known lane can only come from a v_writelane chain,
so keep it across a computed-index store instead; a constant-index store
of the slot still ends the spill. This is fdfawef324's suggestion on
#6277.

That such a store misses the spill cannot be proven for these programs,
so it is checked at run time where a replaced read depends on it: a
backward liveness over each slot and lane whose known value a replaced
read used puts a WindowLaneGuard before every computed-index store at
which that lane is live, and the guard records a WindowLaneSpill fault
when the store changes that lane of the slot. The driver reads the fault
buffer back for every program with such a guard and reports the dispatch
or draw as failed, so a broken assumption is no longer silent. This also
covers the pure spill slots main already folds.

Co-authored-by: fdfawef324 <[email protected]>
Co-Authored-By: Claude <[email protected]>
2026-10-21 20:17:08 +07:00
capmare 9863f8b641 fix(shader): give the frontend's call analysis the dispatch's wave size
AcquireFrontend built the frontend's SwappcInfo with a wave size of 0, while the
driver's LinkUserDataCallees passes the dispatch's wave size. A wave64 v_cmp_e64
that reuses a call's link pair after the return, followed by a v_cndmask_b32_e64
that reads it, was refused as escaping the call/return model. The frontend now
receives the dispatch's wave size, and a frontend built for one wave size is not
reused for another.
2026-10-21 14:13:06 +02:00