A one-sample target drawn by a multisampled rasterizer refused a pixel
shader that reads ANCILLARY with POS_X_FLOAT or POS_Y_FLOAT, because the
sample index made the host shade per sample and moved FragCoord from the
pixel centre. A shader the guest does not iterate now runs once per pixel
with sample number 0, and on this path the rasterizer keeps one sample, so
those draws are no longer refused. Resident Evil Village's (PPSA01556)
2x depth-only pass with SPI_PS_INPUT_ENA 0x2301 was one of them.
Main took request serialization versions 31 (output primitive size) and
32 (spanned waves), and #6683 uses 33, so the pixel iteration fields move
to version 34. A version 32 request keeps its spanned-waves flag and reads
no pixel iteration.
The deferred settle of small Windows imports could only be turned off
through the test hook. The variable turns it off for a run, so a title can
be compared with and without it on one build; unset, nothing changes.
Main's #5905 settles Linux dma-buf imports with settleImport, which is
now built on both platforms. The batched settle of Windows imports under
1 MiB, its counters and adoptSettleDevice's batch reset stay Windows-only,
and ClearHostImports drains the batches only there.
On top of #5882, a draw with PA_SC_AA_CONFIG.MSAA_NUM_SAMPLES 2 (4x),
MSAA_ENABLE clear, a one-sample color target and no depth target threw
"a color target's sample count differs from the rasterizer's", which
stops METAL GEAR SOLID: Peace Walker (PPSA18216) at its first
presentation (draw C on #5268). Without MSAA_ENABLE every sample is at
the pixel center, and a one-sample target keeps the coverage of sample
0, so the draw is now drawn as a one-sample draw.
PS_ITER_SAMPLE, ANCILLARY or SAMPLE_COVERAGE pixel inputs and a
sample-mask export throw on this path.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A concurrent scePsmlMfsrReleaseSharedResources could pass its "still used
by a context" check between the handle lookup and the context insertion.
The technical debt entry now says how KytyPS5's layout differs from the
calls in PPSA08330 and PPSA03016.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
scePsmlMfsrInit, the shared-resource calls and the 800M3_2 context calls
threw or answered "not initialized", so a title that sets PSSR up at
start-up stopped there even when it never uses PSSR on hardware without
it (PPSA08330 calls the setup unconditionally and only dispatches when
sceKernelIsTrinityMode is set, which AnyPS5 reports as 0).
The layouts come from the calls in PPSA08330 and PPSA03016: requirements
are {block bytes, alignment, block count}, handles are 8-byte values
written through the first argument, and a context parameter carries its
block list at 8/16 and the shared-resources handle at 0x38. Init sets
the initialized state, the requirements ask for four 2 MiB blocks (what
PPSA08330 allocates regardless of the returned count), and create and
release keep bookkeeping objects. Invalid arguments throw because their
error codes are unknown.
The 1100 calls, scePsmlMfsrCreateContext1300 and the 900/1000/1300
dispatch packets keep returning 0x8A810001 before Init and throw after
it; packet size, mip bias and capture still throw.
The guest test links libc and gets Windows unwinding so it can check the
refused calls.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Allow custom voice filter type 0 to clear the destination filter,
matching the sampler filter convention. Type 1 continues to configure
the biquad frequency, Q and level. Other unsupported filter types
still throw.
This follows the listener-transform support in
fix/libSceNgs2-listener-transform and is needed for Dead Cells
(PPSA15552), which reaches this path after the custom sampler rack.
Depends on: fix(libSceNgs2): support listener transforms in sceNgs2GeomCalcListener- #5810
Unblocks: PPSA15552
AI assistance: yes
flock, fstatfs, ftruncate, fsync, fdatasync, getdirentries, fchmod, futimes and mmap on an archived descriptor acted on its null device and succeeded or failed with an unrelated errno. They now throw NotImplemented, each covered by the kernel archive test; mmap is noexcept, so its refusal is checked through the terminate handler.
sceKernelOpen and open give an archived file a read-only null-device descriptor. Reads, positioned, vectored and AIO reads, seeks, fstat and FIONREAD are served from the archive; dup, dup2 and F_DUPFD share the position. sceKernelStat and sceKernelCheckReachability see archived paths.
Writing opens fail with EROFS, O_CREAT|O_EXCL with EEXIST and O_DIRECTORY on a file with ENOTDIR. Opening an archived directory or one merged with the disk throws until getdents can list it.
A ZArchive named app0.zar beside app0/ is a read-only layer under it. libc opens it at the first path resolution, looks paths missing from app0/ up case-insensitively, reads files across compressed blocks and keeps the archived descriptor table with shared positions.
Resolving an archive-only path through a call that does not read the archive throws instead of failing with ENOENT, as do opendir of a directory present in both places, fdopen of an archived descriptor and chdir into the archive. A path through .. in an archive-only directory resolves.
The automatic window needed 8 logical processors, which a 4-core CPU with SMT passes while the waited-for thread may run on a sibling thread, and ignored the process affinity. It now needs more than 8 processors in the affinity mask (CpuTopology), falling back to hardware_concurrency.
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.
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.