Commit Graph
8890 Commits
Author SHA1 Message Date
AlxcBTW e74484e0fb perf(agc): spin before blocking on the GPU mutex and the draw committer hand-offs
At the Minecraft Dungeons II title the queue-0 worker, the draw committer and the compute worker
hand work to each other 49,000 times per 10 s through the GPU mutex, the committer's condition
variable and DrawPipeline::Drain, and each hand-off that has to wait costs a kernel wake-up. The
three workers are busy 21-34 % of the time: the GPU idles because the chain of hand-offs is slow,
not because a thread runs out of CPU.

GpuMutexType::lock retries try_lock for a window before it blocks, the committer polls its item
count for the window before it waits on its condition variable, and Drain polls for twice the
window before it waits for the committer. A hand-off that completes within the window costs no
wake-up. The window is 150 us on machines with at least 8 logical processors and 0 below that;
APS5_HANDOFF_SPIN_US sets it (0 turns it off). Ordering and the lock's semantics are unchanged.
The test agc_handoff_spin covers the window policy, the spin helpers and contended locks, and
docs/dev/ARCHITECTURE.md describes the spin.
2026-10-16 14:19:43 +02:00
Adrià eb901bcf4e Merge pull request #6784 from milescoviello/fix/journal-mesh-output-size
fix(agc): journal the mesh output primitive size
2026-10-16 14:03:21 +02:00
Adrià 127e5bf826 Merge pull request #5872 from Sam-mon7/perf/lazy-shader-prepare
perf(agc): allow shader preparation on first use
2026-10-16 14:01:24 +02:00
Adrià c8044c3a7a Merge pull request #5914 from fdfawef324/codex/vertex-lane-bounds
fix(shader): fold fixed 32-lane vertex bounds
2026-10-16 13:47:56 +02:00
Adrià bba8b293ba Merge pull request #5899 from ps54all/feat/shader-image-store-d16-sint
feat(shader): store D16 data to SINT storage images
2026-10-16 13:45:23 +02:00
milescovielloandClaude Opus 5.5 2d5f761cb5 fix(agc): discard pipeline journals written before the mesh field
The layout guards only build on Linux with libstdc++, so a Windows or
macOS build of main after #5884 wrote journals whose mesh records lack
outputPrimitiveSize under the new shader-cache source version. The
journal format is now 3, so such a file is discarded instead of being
read with the new codec. MarcZX100 pointed this out.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 11:45:11 +00:00
milescovielloandClaude Opus 5.5 b1e88d5995 fix(agc): journal the mesh output primitive size
#5884 added MeshConfiguration::outputPrimitiveSize, and #5875's pipeline
journal guards the layouts it encodes. The two merged separately, so on
Linux with libstdc++ PipelineJournal.cpp no longer compiles:
MeshConfiguration is 40 bytes, ShaderStages (which holds an optional
one) 112. The guards now name those sizes, and the recipe codec writes
and reads the new field, so a replayed line-strip geometry pipeline
keeps its two-vertex primitives.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 11:36:25 +00:00
Adrià 65d56a297c Merge pull request #5804 from MarcZX100/codex/pixel-interlock-terminate-2009
fix(agc): stop pixel invocations on BDA faults when supported
2026-10-16 13:35:18 +02:00
Adrià aff725bf6d Merge pull request #5886 from ymatrix1/fix/shader-unnormalized-sampler-without-mip-filter
fix(agc): read an unnormalized sampler without a mip filter at its base level
2026-10-16 13:25:42 +02:00
Adrià 645644c488 Merge pull request #5884 from AnthonyClemens/fix/agc-geometry-line-strip-output
feat(agc): draw line-strip output of NGG geometry programs as mesh lines
2026-10-16 13:25:36 +02:00
Adrià 0615cd2b82 Merge pull request #5875 from adriadam10/perf/agc-pipeline-journal
perf(agc): journal the pipelines of a run and build them ahead on the next one
2026-10-16 13:19:18 +02:00
Adrià Franch d8c2b71d12 docs(debt): D16 SINT image stores measured on RDNA2 2026-10-16 13:18:43 +02:00
ps54allandClaude Opus 5.5 a18d6e9a6b feat(shader): store D16 data to SINT storage images
image_store with D16 data to a storage image of a SINT format threw
"stores 16-bit data to an image of a SINT format", both when the
descriptor is decoded and in the SPIR-V image emitter, and the runtime
image modes left out the SINT conversions for such images. God of War
Ragnarok (PPSA08330) stops on it in compute shader 0x1052a17900 right
after its MFSR setup.

Each 16-bit half is now converted like the D16 format buffer stores
(EmitD16StoreComponent): sign-extended, then saturated to the
component width as for 32-bit data. The buffer form was measured on
RDNA2 in #331; the image form is not measured (TechnicalDebt).

agc_driver_image_store_sint now stores D16 data with DMASK 0xf and 0x5
to all eight SINT formats and after an image_atomic_add on 32_SINT,
instead of expecting the refusal.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 13:18:38 +02:00
Adrià 3f171d03e0 Merge pull request #1747 from MichonGoddijn231849/perf/pipelined-dispatch
perf(agc): dispatch-cache recipe hits as ordered commit items
2026-10-16 13:10:50 +02:00
Adrià Franch b85146dbf5 test(agc): keep the recompiled words alive in the terminate tests 2026-10-16 13:10:31 +02:00
Adrià Franch 00fdf5b4c4 test(agc): give the vertex terminate test the ClipDistance capability 2026-10-16 13:10:31 +02:00
MarcZX100 8a82811d9b fix(agc): preserve draw parameter profile validation
Restore the shaderDrawParameters feature guard while adding shaderTerminateInvocation support. Cover enabled and disabled DrawParameters profiles, and pass the termination feature to the correct shader validation argument.
2026-10-16 13:10:28 +02:00
MarcZX100 502a972f2d test(agc): update terminate checks for current APIs 2026-10-16 13:10:28 +02:00
abnergtz 54e95dfa76 feat(agc): enable VK_KHR_shader_terminate_invocation on the device
The device queries and enables shaderTerminateInvocation when available, advertises SPV_KHR_terminate_invocation to the recompiler and validation, and the shader device profile rejects a target that advertises the extension without the enabled feature.

Based on the approach in poonasor/AnyPS5@73969879.

Refs #2009

(cherry picked from commit 1866a3f70e7ac1c34c8cd87fc79a973bd9ba6947)
2026-10-16 13:10:28 +02:00
abnergtz 0fe8527a0a test(agc): cover terminate invocation specialization, stage boundaries and disabled feature 2026-10-16 13:10:28 +02:00
abnergtz 0e8ce286e1 fix(agc): validate OpTerminateInvocation itself, not only its extension
The validator only checked SPV_KHR_terminate_invocation when it saw the
OpExtension, so a module using OpTerminateInvocation without declaring
the extension, or in a non-fragment stage, was accepted. Require the
fragment stage, the enabled shaderTerminateInvocation feature and the
declared extension at the instruction itself.

Refs #2009
2026-10-16 13:10:28 +02:00
abnergtz 42cd3f2ec4 feat(agc): gate SPV_KHR_terminate_invocation on shaderTerminateInvocation
Shader validation accepts the extension only in fragment shaders and only when the device enabled shaderTerminateInvocation. The flag is part of the validation memo key.

Refs #2009
2026-10-16 13:10:28 +02:00
abnergtz 7041ba8d9a fix(recompiler): terminate pixel invocation on BDA fault when supported
Pixel invocations stopped by a BDA fault now end with OpTerminateInvocation when the target offers SPV_KHR_terminate_invocation, and keep OpKill otherwise. OpKill is not enough on AMD driver branch 21045, where a guest atomic after the kill still lands once per faulting pixel.

Based on the approach in poonasor/AnyPS5@73969879.

Refs #2009
2026-10-16 13:10:28 +02:00
Adrià Franch 89333e056f test(agc): wait for the pipeline to empty between descriptor rounds 2026-10-16 12:53:38 +02:00
Adrià Franch ebc2342d1e docs(architecture): describe dispatches queued as pipeline items 2026-10-16 12:53:38 +02:00
MichonandClaude Opus 5.5 ccfee8e260 perf(agc): dispatch-cache recipe hits as ordered commit items (APS5_PIPELINE_DISPATCH)
With pipelined draws, a DISPATCH_DIRECT on queue 0 whose dispatch-cache entry hits with a
recipe runs as an ordered commit item instead of draining the pipeline first. Misses, reads
that overlap writes still pending in the pipeline, verified data hits and writes that cannot
be ranged still drain. A dispatch that is resolved ahead (or adopted from a group resolved
ahead) and copy kernels keep the drained path; with the switch on, queue 0 does not resolve
dispatch groups ahead, since that drains the pipeline at every group. Off by default.
agc_driver_pipelined_dispatch counts drains per opcode (each dispatch drains with the switch
off); agc_driver_pipelined_dispatch_item checks that repeated dispatches do not drain, and that
a dispatch whose descriptor table a pending fill retargets drains and reads the new buffer.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-16 12:53:34 +02:00
Adrià Franch fa30a9d5d2 fix(agc): do not create the pipeline journal at driver shutdown
Flushing at shutdown built the singleton and its writer thread on a run that never recorded anything; on Windows that throws std::system_error while the process is exiting.
2026-10-16 12:52:28 +02:00
Adrià FranchandClaude 1ad590fc05 test(agc): give the new program of compute_pipeline_outside_gpu_mutex its own module
Pipelines are now shared by every program that recompiles to the same
module, and a leading s_nop recompiles to the same one, so the second
dispatch reused the first pipeline. The new program also stores to the
second word.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-16 12:52:28 +02:00
Adrià FranchandClaude 52d8d6ce28 fix(agc): journal the pipeline state fields main added
The replayed stencil reference, the reversed blend, the quad sample masks
and the tessellation instance patches and draw parameters change the
pipeline a draw creates, so the recipe carries them; the file format is
bumped and the layout guards follow the new sizes.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-16 12:52:28 +02:00
Adrià FranchandClaude 57ff6a63b2 fix(agc): record nothing in the pipeline journal without its file lock
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-16 12:52:28 +02:00
Adrià FranchandClaude 67f5350e25 fix(agc): keep the pipeline key buffer in a host thread-local slot
MinGW's emulated TLS runs thread_local destructors from the module's TLS
callback, which corrupts the heap when a replay thread or queue worker that
ran CachedPipeline exits (0xC0000374, prx_thread_local_destructors).

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-16 12:52:28 +02:00
Adrià FranchandClaude addcdc7c41 fix(agc): journal the sample location grid and per-sample shading of a pipeline
#5861 added both to the pipeline state and its store key; the recipe dropped them, so a
replayed pipeline keyed another configuration.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-16 12:52:28 +02:00
Adrià FranchandClaude Fable 5.1 4aafda8e3b perf(agc): journal the pipelines of a run and build them ahead on the next one
A graphics pipeline the store builds or a compute pipeline a dispatch builds is
appended to pipelines.journal next to the shader cache entries, as the
materialized result of each stage (the specialized SPIR-V, bindings and push
constants) plus the recipe the pipeline was built from: the stages'
identities, vertex input layout, descriptor set layout keys and the state
fields the Pipeline constructor reads. When a VulkanDevice is created with a
window (a headless device waits for its first draw or dispatch, since the
window's device usually replaces it first) the journal is loaded and its
pipelines are built on a pool of threads while the title loads, so the first
draw or dispatch of a configuration seen on an earlier run finds its pipeline
resident instead of compiling it on the queue worker.

The pipeline stores key on RecompileResult::Identity, a hash of the module
words, specialization constants, subgroup width and bindings that is the same
on every run (SharedSpirv::ContentHash, computed once per shared module),
rather than on the process-lifetime variant ids; a generated stage is keyed
like any other. CachedPipeline builds outside the store's mutex and the
library parts and link are built outside the library store's mutex, so replay
threads and queue workers build in parallel; a concurrent build of the same
key keeps the first inserted. A replayed pipeline enters the store at its
least recently used end and a full store takes none, and its optimized relink
waits for the first draw that binds it, so the title's own pipelines come
first in both. The compute pipeline creation moves into
VulkanDevice::createComputePipeline, shared by dispatches and the replay. The
store key also covers the color component mapping, the depth target's sample
count and a depth bias clamp, which the constructor reads.

The file names the device it was written for (the properties the driver's
pipeline cache file is named by) and starts over for another; a torn tail is
cut at a record boundary; two runs sharing the directory take turns on a lock
file and keep each other's records; a read failure never starts the file
over. A device cancels its replay before it is replaced or destroyed, and a
replaced device destroys its pipelines then rather than at the driver's stop.

APS5_NO_PIPELINE_JOURNAL=1 disables it; APS5_PIPELINE_JOURNAL_THREADS,
APS5_PIPELINE_JOURNAL_ENTRIES (the first recorded), APS5_PIPELINE_STORE_ENTRIES
and APS5_PIPELINE_JOURNAL_MAX_MIB bound it; APS5_PROFILE_DRAW prints a
[pipeline-journal] summary. APS5_VERIFY_SET_LAYOUTS=1 now also checks a
dispatch's set layout against the one described from its shader. The lavapipe
test suite, which shares one cache directory, runs with the journal off except
for the journal's own tests.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P6hw3kRAuQdfcU9YCZgaoK
2026-10-16 12:52:28 +02:00
Adrià 7dcfff559f Merge pull request #6573 from hashaam1217/test/agc-frame-dump-pipe-capacity
test(agc): write more pixels than a pipe holds in the closed-pipe case
2026-10-16 12:48:14 +02:00
Adrià 51acb79ac4 Merge pull request #5828 from billythemenace2/fix/agc-non-image-tsharp-as-null
fix(agc): treat a TYPE 1 T# in a read-only static image slot as null
2026-10-16 12:34:28 +02:00
Adrià 3f539f5510 Merge pull request #4649 from Mouad-Scriptz-0/perf/agc-inplace-vertex-barrier
perf(libSceAgcDriver): order in-place vertex inputs behind pending GPU writes with a barrier
2026-10-16 12:34:22 +02:00
Adrià a4782fe11d Merge pull request #4855 from fdfawef324/feat/agc-submission-ring
feat(agc): keep the last submissions per queue and dump them on a stall or crash
2026-10-16 12:32:48 +02:00
Adrià 72c5eed1ff Merge pull request #6761 from adriadam10/ci/linux-adaptive-parallelism
ci(linux): size build and test parallelism to what the shared host has free
2026-10-16 12:16:08 +02:00
Adrià FranchandClaude f7e767add9 ci(linux): size build and test parallelism to what the shared host has free
The self-hosted runners share one 32-thread host and were fixed at one job each, so
a build with many ccache misses compiled them one after another (686 misses took 37 min).
Pick jobs from the free CPUs and available memory (1 to 8, ctest at most 4) and pass a
load limit to ninja so a busy host backs off.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-16 12:14:07 +02:00
Adrià f8d4ce340b Merge pull request #4943 from TheAggie/perf/agc-draw-relocation-main
perf(agc): find cached draws across moved user-data pointers
2026-10-16 12:13:51 +02:00
Adrià 332b0b1b79 Merge pull request #6371 from AlxcBTW/perf/worker-logging
perf(agc): format and write steady-state log lines off the queue worker
2026-10-16 11:44:23 +02:00
Adrià Franch 4339eee2c3 fix(libSceAgcDriver): flag the vertex barrier only for bound inputs, cover attachment writes 2026-10-16 11:30:20 +02:00
Mouad-Scriptz-0andClaude Fable 5.1 13a82bdccf perf(libSceAgcDriver): order in-place vertex inputs behind pending GPU writes with a barrier
An in-place draw input flushed pending GPU writes over its range on the
CPU before the bind, a submit-and-wait of the open batch when a dispatch
in it wrote the buffer. The CPU never reads a vertex buffer's bytes, so a
vertex input under a pending write is bound in place behind a barrier from
shader and transfer writes to vertex attribute reads, recorded before the
draw's rendering begins; index inputs keep the flush, since the highest
index is read on the CPU. Minecraft generates a vertex buffer with a
compute dispatch every frame and drew from it one CPU wait later.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-16 11:30:20 +02:00
Adrià Franch 4859af0213 test(agc): register the C runtime heap trap test only on Windows
The mode returns 77 on Linux with a message that tools/check_skips.py does not accept as a device limitation, so the full Build failed the skip check.
2026-10-16 11:18:26 +02:00
fdfawef324andClaude Opus 5.5 13b171cab5 feat(agc): keep the last submissions per queue and dump them on a stall or crash
A GPU hang or a crash in a title leaves no record of what the queues
were last given: APS5_TRACE_GPU prints every submission (too much to
leave on), and the WAIT_REG_MEM timeout message shows only the packet
before the wait on the waiting queue.

Each queue now keeps a ring of its last 16 submissions
(APS5_PM4_RING=<n>, 0 to 4096, 0 disables): the TraceMs time in tenths
of a millisecond, serial, size, guest address and a copy of the first
512 dwords after indirect buffers are inlined, recorded under the
driver lock next to the serial, REWIND tails included. The ring of a
queue and the failure report registration are set up at the top of
Submit, before any output is reserved, so recording under the lock
does not allocate. Disabled, Submit only tests a static flag; enabled,
it costs one bounded copy per submission.

DumpSubmissionRings decodes the kept dwords with Pm4::PacketWords and
the new Pm4::KnownName, which returns the decoder's names as views of
static strings (empty for an unknown opcode, printed as UNKNOWN_0x%02x);
Pm4::Name now builds its std::string from it. Every line is formatted
with integer and string conversions only into a 512-byte stack buffer
and written with one WriteFile / write(2) on the stderr handle, so the
dump does not allocate from the C runtime heap, lines from other
threads do not interleave and the CRT stream lock is not taken (the
rule of #3871). The header gives the number of queues and the ring
size, and each queue line the submissions recorded and kept.

libc gets a small registry of failure reports
(LibcRegisterFailureReport_nid_no_patch, Unregister, Run); Run runs
the registered reports the first time it is called and returns at once
after that. The Windows crash report runs it after the thread dump of
an unhandled exception, after SIGABRT (which also covers the
APS5_HANG_DUMP_SECS timed dump, since it aborts) and after an invalid
CRT parameter, so an abort after a reported exception does not print
the rings twice. The driver registers its dump at the first submission
and unregisters at static destruction; the dump there waits a bounded
time for each ring lock. What the crash-path dump cannot do (a ring
held by the crashed thread, rings corrupted by the crash, Linux) is
recorded in technical debt.

APS5_STALL_WATCHDOG_SECS=<n> (0 to 86400, 0 disables) makes a waiter
that has not progressed for n seconds dump the rings once per wait: a
WAIT_REG_MEM (progress as for APS5_GPU_WAIT_TIMEOUT_MS: another packet
runs or completes), a REWIND waiting for the title, and a compute
submission held behind queue 0. The last one prints under the driver
lock, so submissions and the other queues wait for it (USAGE.md says
so). Both variables are read at the top of Submit, so an invalid value
of either throws at the first submission and never later inside a GPU
worker. The order wait behind queue 0 releases its order hold on scope
exit, so a throwing dump cannot leave it counted.

No packet semantics change; packet sizes and names are those of the
existing decoder (PM4 type-3 header layout as in Mesa
src/amd/common/sid.h). The queue bound of Submit and of the rings is
one constant, SubmissionQueueEnd.

Tests: agc_driver_pm4_tests gets ten modes, each its own ctest:
agc_driver_pm4_ring (APS5_PM4_RING=4, six submissions on queue 0 and
two on 0x20: the dump holds #3..#6 and #1..#2 in order, nothing
older), agc_driver_pm4_ring_empty (one line), _ring_disabled (one
line), _ring_invalid and agc_driver_pm4_stall_watchdog_invalid
(APS5_STALL_WATCHDOG_SECS=1x: the submission throws and is not
executed), _ring_report (LibcRunFailureReports_nid_no_patch dumps the
rings), _ring_report_heap (Windows: with ucrtbase.dll's HeapAlloc and
HeapReAlloc imports counting calls from the reporting thread, the
failure report of a submission holding INDEX_BUFFER_SIZE names it and
allocates nothing, while Pm4::Name of the same header is seen
allocating), and with APS5_STALL_WATCHDOG_SECS=1 a WAIT_REG_MEM
(agc_driver_pm4_stall_watchdog), a REWIND (_stall_watchdog_rewind) and
a compute submission held behind a queue 0 rendering wait
(_stall_watchdog_order), each held for about 2.5 s, dump once and
complete when released. The PM4 catalog test checks KnownName against
every opcode and custom name. windows_backtrace_failure_report checks
that abort() runs the registered reports once and not an unregistered
one; windows_backtrace_failure_report_once that abort() does not run
them again after an earlier run. With the dump decoding through
Pm4::Name, agc_driver_pm4_ring_report_heap fails with "the failure
report allocated from the C runtime heap"; with Run resetting its
flag, windows_backtrace_failure_report_once prints the report twice.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 11:18:26 +02:00
Adrià 5d9dcc42d2 Merge pull request #6372 from AlxcBTW/perf/pipeline-cache-once
perf(agc): load the pipeline cache file only on the windowed device and save without re-reading an unchanged file
2026-10-15 23:58:29 +02:00
Adrià 7b20318e89 Merge pull request #5882 from billythemenace2/fix/agc-msaa-target-without-msaa-enable
fix(agc): rasterize a multisampled target without MSAA_ENABLE at the pixel center
2026-10-15 23:58:24 +02:00
Adrià 31cbb55d75 Merge pull request #5880 from ErenYeager1836/test/cpu-temperature-probe-coverage
test(libkernel): cover valid probe in cpu temperature guest test
2026-10-15 23:15:48 +02:00
Adrià be4a6f0a82 Merge pull request #5878 from ErenYeager1836/test/operation-mode-and-trinity
test(libkernel): cover sceKernelIsTrinityMode and dual-null in operation mode guest test
2026-10-15 23:15:43 +02:00
Adrià f35c13fc95 Merge pull request #5833 from Ondra97/codex/fix-windows-vector-io-lock
fix(libkernel): serialize Windows vectored file transfers
2026-10-15 23:15:38 +02:00