Commit Graph
258 Commits
Author SHA1 Message Date
Dean cbc4cc7d80 Merge pull request #11798 from milescoviello/perf/ir-value-pool
perf(shader): allocate a program's IR values in chunks
2026-11-03 01:26:46 +13:00
Dean 79eb4afea7 Merge pull request #10547 from mrfelek/claude/project-thread-umbqjy
fix(agc): prefer host interpolation on RADV to avoid the quad seam
2026-11-03 01:25:37 +13:00
Dean 1900d3963a Merge pull request #10941 from TechLevelZero/fix/div-fmas-f32-single-rounding
fix(shader): round v_div_fmas_f32 once and keep its denormal inputs
2026-11-02 23:25:23 +13:00
mrfelek b6ed7fa781 fix(agc): prefer host interpolation on RADV to avoid the quad seam
RADV gives the second triangle of a full-screen quad PerVertexKHR values
in an order that does not match gl_BaryCoordKHR, so passes whose pixel
shader uses plain v_interp_p1/p2 show a diagonal seam (Silksong final
pass on a Radeon 780M). On RADV, pixel shaders are now first translated
with host interpolation; only shaders the host interpolation checker
rejects keep native VK_KHR_fragment_shader_barycentric.
APS5_NO_HOST_INTERPOLATION_FIRST=1 restores the old behaviour.

AI-assisted. Tested by me on my own machine.
2026-11-02 10:12:24 +01:00
JJenkx 8c761ee3af fix(shader): retain dispatch offsets during layer specialization 2026-11-01 06:07:39 -05:00
JJenkx 218ca18e42 fix(agc): render mesh layers within device limits 2026-11-01 06:07:38 -05:00
TechLevelZero a7ce3fadaa Merge branch 'main' into fix/div-fmas-f32-single-rounding 2026-11-01 10:01:21 +00:00
Adrià 3dc8acbca6 Merge pull request #13807 from frankea/fix/tes-single-lane-without-subgroups
fix(shader): run tessellation evaluation stages one lane per invocation on devices without subgroups there
2026-11-01 02:35:26 +01:00
Celegans12 068f2b3ecf fix(shader): reuse bound specialization fields for null buffer slots
Null buffer descriptors still split modules on unused specialization
fields after buffer presence moved to run time. Learn the first valid
bound fields per slot and use them for absent descriptors, retaining
actual runtime presence and independent bound formats.
Snapshot the learned fields once for result memo keys and materialization
so identical null captures cannot retain a module made before learning.
Cover direct, captured and prepared calls, null stores, and changed formats.
Keep the process-local table and an off switch for main's module selection.

AI-assisted: yes
2026-10-31 23:22:39 +01:00
frankea 53e4e8e796 fix(shader): run tessellation evaluation stages one lane per invocation on devices without subgroups there
MoltenVK and lavapipe leave the tessellation evaluation stage out of
subgroupSupportedStages, so the driver's shader validation refuses every
domain program that declares GroupNonUniform ("subgroup capability 61 is
unsupported for shader stage 4"). Gran Turismo 7 stops there on macOS at
the Used Car dealership.

The device target now records whether the tessellation evaluation stage
has subgroups. When it does not, tessellation evaluation programs outside
the mesh path get a host subgroup width of 1 and the one-lane rules that
vertex programs already use without vertex subgroups: the lane id is 0,
a ballot is the invocation's own bit, a shuffle returns the invocation's
value and an elect is true. Reads of other lanes still throw. Devices
with tessellation evaluation subgroups emit the same SPIR-V as before.
The request serialization moves to version 51.
2026-10-31 03:01:43 -04:00
milescovielloandClaude Opus 5.5 cb2159e48f fix(shader): drop a source's kept program when its plan fails to materialize
getSource keeps the program it built a plan from, for the source's first
variant compile. When Materialize then threw, no compile ran, so the
program stayed with the SourceEntry for the life of the process. With the
value pool such a program holds the slots of its peak value count. Over
the replay corpus, the 90 requests whose descriptor sources do not
evaluate kept about 1 GB this way. recompileOnce now releases the program
when materialization throws; a later request for the source prepares it
again.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-30 21:50:26 +00:00
Filip Michalski 9755d4e0a0 perf(shader): reuse the prepared specialization value lookup 2026-10-30 17:23:54 +01:00
milescoviello 0fe2329ee8 Merge main 422f96b3a9 into perf/ir-use-arena 2026-10-30 04:34:36 +00:00
Dean 3d2d264392 Merge pull request #12916 from Tehshortbus/feat/multi-target-merge
feat(agc): merge a draw into more than one unclamped normalized color target
2026-10-30 16:49:46 +13: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
milescovielloandClaude Opus 5.5 c01d0bb24f fix(shader): move a cached program's use lists to the heap and drop its arena
A program kept in a SourceEntry held its use-list arena until the entry
was destroyed, so the buffers of values ReclaimUnusedValues dropped, and
the buffers every use list outgrew, stayed allocated for as long as the
program was cached. Before a program is cached, ReleaseUseArena now
copies each value's use list into a heap vector and frees the arena.
Values created after that draw from a new arena.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-29 21:17:43 +01:00
TehshortbusandClaude Opus 5.5 c037722384 feat(agc): merge a draw into more than one unclamped normalized color target
A draw that blends into several targets with BLEND_CLAMP clear now carries
one merge entry per target. Each entry gets its own storage image and
pixel-shader blend, and every pending entry is stored inside the draw's one
pixel interlock region. Partial writes of packed targets still merge alone.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-29 07:00:28 -07: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
TechLevelZero ef345e24bd Merge branch 'main' into fix/div-fmas-f32-single-rounding 2026-10-29 09:45:52 +00:00
Dean 4c7d275bef Merge pull request #11684 from oneandonlydean/feat/agc-unclamped-normalized-blend-v2
feat(agc): blend into an unclamped normalized color target in the pixel shader
2026-10-29 20:48:48 +13:00
Dean Galvin 00c06d63e8 Merge branch 'main' into feat/agc-unclamped-normalized-blend-v2
# Conflicts:
#	core/shader/recompiler/ControlFlow/src/RequestSerializer.cpp
2026-10-28 20:13:06 +13: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à 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
Dean Galvin 4d954209d2 Merge branch 'main' into feat/agc-unclamped-normalized-blend-v2
# Conflicts:
#	core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
2026-10-28 08:44:09 +13: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
Dean Galvin 10466c30e6 feat(shader): carry a blended normalized color target merge in the pixel request
TargetMerge gains a TargetBlend (factors, operations, write mask, constants, signedness) that the request serializer, the cache key and the variant hash take only when it is enabled, so every request without it keeps its bytes, key and hash.
2026-10-27 11:04:05 +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
TechLevelZeroandClaude Opus 5.5 a22a46931e fix(shader): round v_div_fmas_f32 once and keep its denormal inputs
On RDNA2 v_div_fmas_f32 never flushes its inputs, rounds the scaled
fused result once, and flushes a denormal result to a zero of its sign
when the f32 denormal mode flushes outputs. With Float64 the sum is now
computed in f64 and rounded to odd, so the scaling into the denormal
range no longer rounds twice and the hardware f32 flush no longer
reaches the inputs; mode 1 now flushes the result.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-25 11:05:37 +00: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