Brings #5872 (shader preparation on first use), main's async driver log and its geometry subgroup checks. The prepared-shader modes are the union of both lists. With this branch, the pipeline ABI of a lazily registered shader it cannot prepare leaves the stage deferred instead of throwing, so LazyRegistration now requires the stage to stay deferred with no prepared entry after that call; its dispatch and shutdown failure checks are unchanged. StderrCapture flushes the async log when it starts and before it reads, since a deferral's log line can otherwise still be queued. The undecodable-state check now matches the decode's VGT_SHADER_STAGES_EN reason rather than one message, which main's subgroup output check now gives first.
agc_driver_recorder_tests --draw-descriptors-only (drawDescriptorWriteTests and
drawSnapshotTableSetTests) had no CTest entry, so CI never ran it.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A PS5 (firmware 13.60) reports 8192 entries per side. It takes one cpu entry for each 2 MiB granule holding a committed mapping of any protection, and one gpu entry for each 1 GiB region holding a GPU-accessible mapping plus one for each granule of such a mapping that is not a whole granule of direct memory at a 2 MiB-aligned physical address. Shared granules and regions count once. sceKernelGetPageTableStats reported 2048 entries and charged each range per granule, CPU-accessible ones only to the cpu side.
On Windows the atexit handlers of a DLL run after the process has ended
its other threads, so the logger thread can be gone with lines still
queued and the unbounded Flush waits forever (guest_shader_link timed
out on 4 of the last 7 completed main builds since #6371). Run the bounded
FlushAtEnd there instead.
Co-Authored-By: Claude <[email protected]>
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.
The stage-A pre-sync of a dispatch listed only the surfaces that stage B reads on the CPU. The DCC
keys of an image that a recorded kernel writes were not in the list, so stage B waited for that
kernel in WaitForKeyWriters with the GPU mutex held and every other worker queued behind the wait.
At the Minecraft Dungeons II title the pre-sync fired once in 296,000 dispatch checks while
WaitForKeyWriters synchronized 400 times per 10 s.
PresyncSurfaces now also returns the key range of every image binding (PresyncSurface::dccKeys).
presync waits for a key range only while recorded work writes it, the key-store memo does not
already give its value (DccKeyWritersPending) and, under the mutex it takes for a moment anyway, the
pending stores do not give the keys either (DccKeyWriterNeedsSync, the test WaitForKeyWriters makes
before it synchronizes). Which keys the dispatch reads, and when, is unchanged: the locked lookup runs
as before and finds nothing pending.
APS5_NO_DCC_PRESYNC=1 leaves the key ranges out. The [presync] line counts key ranges checked,
pre-syncs that only the keys required and the outcomes of WaitForKeyWriters. The test
agc_driver_dcc_key_presync covers a kernel that writes the keys, a recorded fill of the keys and
nothing pending, and skips with the reasons check_skips.py expects when the device has no timeline
semaphores or no host import.
The test set neither mode, so ctest ran only the two-lane form. It now
recompiles each program two-lane and then spanned through
SpirvTarget::spannedWaves, checks that the spanned module asks for full
subgroups, and skips the spanned pass on a device without full 32-lane
compute subgroups.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
APS5_SPANNED_WAVE is now read once by the driver, which sets
SpirvTarget::spannedWaves only on a device with 32-lane compute subgroup
control and computeFullSubgroups. The recompiler no longer reads the
environment. The field is part of the cache key and of the request
serialization (version 32), so a cached or replayed module keeps the mode
it was built in.
A spanned module numbers its lanes SubgroupId * 32 +
SubgroupLocalInvocationId, which needs two full 32-lane subgroups. The
artifact records this as fullSubgroups (disk cache and pipeline identity
included), and the driver creates those pipelines with
REQUIRE_FULL_SUBGROUPS. Compute pipeline captures accept the flag with a
required subgroup size.
The two-lane fallback now catches only SpannedWaveUnsupported, thrown for
a shuffle wider than 32 bits; other emit errors surface as before.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A program that stores to a 2D multisampled texture writes the samples of
its host multisampled color target through a storage view. Targets are
created without storage usage; the first storage binding that resolves
to a target moves it to an image with storage usage, copying its samples
once, and keeps the previous image until the target is released. Storage
usage needs the device's shaderStorageImageMultisample feature and its
format at the target's sample count. A surface no draw rendered to is
created from its uniform color memory, as for sampling; other color
memory still throws.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
tagVariantRuns recorded each capture region's shared words under the
region's index, then split the region into runs where the user-data
base its words were read through changes. Everything that reads the
entries counts runs: validateVariant builds its regions one per run
(appendEntryRegions), so its runs.size() == regions.size() check always
held and VouchSharedRegions' ranges were taken as run indices by the
pending-write sync, the overlap checks and validateCaptured.
With a split ahead of a region in a supplied table block, the vouch
covered a run of the earlier region instead of the table's: that run
was neither synced nor compared, so a draw-cache hit could reuse the
variant after its guest words changed, on the strength of the table's
write stamp alone, while the table's own run was compared in full.
The shared words are now recorded per run, as the dispatch path does,
from each run's own words. An unsplit variant records what it did
before, and SameCapturedWords, which compares word positions, sees the
same merged entries.
tagVariantRuns moves to Driver's public members, beside
ClassifyIndirectDraw, so the relocation test can check that a split
variant's shared words name the run that holds the table's words.
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 <[email protected]>
Backslash names and MS-DOS attributes from an MS-DOS host, a .. escape written with backslashes, and a Unix-host name with a backslash.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Output entries are written with a Unix host, but the source entry's external attributes were copied as is. ZIPs made on Windows carry only MS-DOS attributes, so app0 files were recorded with mode 0000 and Info-ZIP unzip extracts them unreadable. Entries without a Unix mode now get 0644.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Windows PowerShell's Compress-Archive stores entry names with \ as the separator and an MS-DOS host. The converter rejected every such ZIP as an unsafe path. Entries from an MS-DOS host now have \ turned into / before the path is validated, so .. and the other unsafe names are still rejected. Unix-host names keep rejecting \.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The lock loop that emulates 64-bit LDS atomics runs only on the lanes
the guest's exec mask keeps, so a spanned wave's barrier-based ballot
there was not reached by both host subgroups. When one subgroup had no
active lane the other one paired its barriers with unrelated ones and
left the loop with lanes still pending, or the GPU hung (Ghost of
Yotei, program 0x80003af600). The elect and the lock are already per
host subgroup, so each subgroup now loops until its own lanes are done.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A spanned wave64 program exchanges ballots and shuffles through
workgroup-scope barriers. When a BDA fault stopped one invocation early,
the other 63 would wait at the next barrier forever. Spanned programs
now keep every invocation running and read zeros after a fault, as
programs with wave LDS barriers already do.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
sceSslConnect performs the client handshake on the host socket that the
guest number maps to in the libkernel or libSceNet socket table, and
sceSslRead and sceSslWrite carry application data. Session state comes
from the context's memory pool, and the server is verified against the
CAs loaded with sceSslLoadCert; a loaded client certificate is sent when
the server asks for one.
libkernel exports KernelLookupSocketNative_nid_no_patch, which checks
its own socket table before the one libSceNet registers. Pools take a
lock so connections can allocate outside the library lock.
TLS 1.3 is compiled out. A missing CA, a verify callback, would-block
sockets and every failure whose console code is unknown throw, as
recorded in the libSceSsl debt entry.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01RoU3ZF76A6uR8sCA7NMLch
#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 <[email protected]>
DispatchCmaskClear made earlier host writes available with a source stage of
ALL_COMMANDS and made its results visible to host reads with a destination
stage of ALL_COMMANDS. ALL_COMMANDS does not include the host stage, so the
host access bits were unsupported by their stage masks
(VUID-vkCmdPipelineBarrier-srcAccessMask-02815, dstAccessMask-02816) and the
host side of the dependency was not formed. Both barriers now add the host
stage, as the CMASK fill after them already does.
AI-assisted: yes
An import made at map time settles inside the guest's map call, so the mapping thread waits while the kernel maps the pages. A device that imports shared memory through host pointers settles nothing, so the test expects a settle only for a dma-buf import.
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 <[email protected]>
A draw without color or depth targets takes its framebuffer extent from
PA_SC_SCREEN_SCISSOR_BR. When that rectangle is empty the hardware still runs
the vertex stage but produces no pixels; it no longer throws. The framebuffer
is one pixel in the empty dimension and the screen scissor clips it to nothing.
AI-assisted: yes