Recording draws allocates and frees many small objects; on Windows about
a fifth of the queue worker's time went to RtlAllocateHeap and
RtlFreeHeap. The driver's operator new and delete keep up to 64 freed
blocks per 16-byte size class (up to 1 KiB) per thread.
Blocks are plain UCRT malloc blocks, so a block allocated here and freed
by libstdc++ (or the other way round) is still a matching malloc and
free. A freed block is filed under the size class its _msize can hold,
or under the size of a sized delete that is a whole number of granules.
A thread's cache is returned to the heap by a fiber-local-storage
callback when the thread ends; deletes that run later in its teardown go
straight to free. The operators are excluded from the driver's automatic
exports, so libSceAgc and libSceVideoOut keep binding to libstdc++'s.
The cache is reached through a native TLS slot because MinGW's emulated
thread_local costs more than it saves; the same applies to
PageStates::initialize, which now checks an atomic flag before
std::call_once. agc_driver_host_allocator covers every size up to 2 KiB,
sized deletes, buffers that libstdc++ reallocates, blocks freed on
another thread and threads that end with cached blocks; it also checks
that private bytes stay flat over 16 further waves of ending threads, where a
cache that is never given back grows them by about 23 MiB per wave.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A linear color target took a synchronous draw (copy in, draw, copy out, CPU
wait) on every draw. When its memory already has a host import, it now gets a
resident image like tiled targets, and keepRecordedDraw stores its results back
to guest memory right after the draw with a recorded GPU store (FlushPending),
so CPU readers see them as before, without the wait. No import is created for
it (a lookup only): memory without one keeps the synchronous path.
APS5_NO_RESIDENT_LINEAR=1 restores the old path.
GTA V Story (RTX 4090, upstream main eb901bcf4 + #6488): 14.64 -> 16.47 FPS.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01X5rdnz9ZTN3ndFVUfizSvj
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]>
Add a CPU replay mode that reaches the runtime descriptor checks and specialization used by prepared shader invocations. Test active and inactive guarded descriptors and continuation after a failed request.
Co-Authored-By: Codex <[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
On Windows the C runtime appends by seeking to the end and then writing,
so concurrent appends through different descriptors overwrite each other
and lose data. Write and writev on an O_APPEND descriptor now go through
WriteFile at the end-of-file offset, which Windows appends atomically,
and writev gathers its buffers into one append as FreeBSD writes the
whole vector at the end.
On such a device a pass with a multisampled color target is refused, because the color samples have no storage view to be reordered through, while a depth-only pass was still reordered. A depth target drawn by both then held its samples in the guest's order after the depth-only pass and was tested in the stand-in's order by the color pass, so on odd rows each sample met the depth of the other half-pixel's position. With #6451 alone both passes kept the stand-in's order. Such a device now refuses the exact order for every pass, so each of its depth targets keeps one order. On a device with multisampled storage images, a color format without a storage view at its sample count still refuses only its own passes, which the debt entry now says.
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.
One process-wide counter throttled the reports of every instruction
together, so a second faulting instruction stayed silent after the
first eight reports of the first. The count is kept per program counter
and the periodic line names it.
The synchronous write-back threw the unaligned access out of
WriteBackBuffers before it marked the written storage images dirty, so
their stores were lost although the shader only skips that access. The
images are now handled first and the report follows, as in the deferred
path.
The fault record keeps the first fault of a dispatch, so an early
unaligned access could hide a later unmapped or permission fault, and
the write-back then published the stores of a dispatch that had a real
access fault. The shader now also sets a sticky flag in the record for
every fault of another kind. An unaligned record with that flag set
fails the command like any other fault, before anything is published.
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.
Remember inaccessible arena pages and Linux mapping gaps so repeated access checks do not rescan host mappings. Invalidate the cache when guest stack protections change.
After collector coverage, emit still rebuilt pixel input info from SPI and threw undefined attribute for the same UFC5 shader; return OFFSET 0x20 defaults from SPIR-V emission too.
Co-authored-by: Cursor <[email protected]>
PPSA03541 prepares a pixel shader that still reads attribute 0 while SPI_PS_IN_CONTROL.NUM_INTERP is 0; extend the CNTL table with OFFSET 0x20 defaults instead of throwing.
Co-authored-by: Cursor <[email protected]>
A plain build passes DispatchDataHitWords without the fix: AddSnapshot
compares the freed words with the live region, prints "guest snapshot
differs from registered memory" and lets the live region serve the GPU,
so the output is right. With APS5_SNAPSHOT_CHECK_FATAL=1 the throw lands
in the resolved-ahead rethrow, which re-runs the dispatch, and it still
passes.
AddSnapshot already counts those mismatches for its report. The count
now lives with the other snapshot compare counters, and
SnapshotMismatches() reads it. The test requires each data hit to add
none.
A dispatch-cache data hit copies the variant's words into a local
liveWords, patches the data words and builds its captured regions as
spans over that buffer.
When the dispatch is resolved ahead (every compute queue by default),
the parked entry copied both captured and liveWords: the copied regions
still pointed into the local buffer, which was freed on return. The
adopting dispatch then built its snapshots from those regions, and an
address-based program compared the freed words in AddSnapshot (an ASan
heap-use-after-free; the plain build reports "guest snapshot differs
from registered memory"). Moving both into the parked entry keeps the
buffer the regions point into.
The pipelined dispatch item had the same shape: its snapshots span the
local liveWords but the closure did not keep it. Capturing it by move
keeps the item self-contained.
DispatchDataHitWords submits an address-based dispatch whose constant
changes every round on a compute queue, so each data hit is resolved
ahead and adopted.
The cancelled replay's bound was taken from the totals before the torn-tail replay, which already
adds one present pipeline; when a worker reached the graphics recipe before the cancel, the test
failed (13 of 600 runs with 24 in parallel).
Co-Authored-By: Claude <[email protected]>
A condition variable that winpthreads initializes statically is set up on its first wait, under one global spinlock for all such variables. The async log's worker made that first wait itself, right after the driver started it, so a process that exited soon after starting the driver, such as guest_shader_link, could end with ExitProcess killing the worker inside that setup. The spinlock then stayed held, and the next destructor of a never-used condition variable, in ~Driver, spun forever. The log's constructor now waits on each of its condition variables once with no timeout before it starts the worker, so the worker's waits never take that spinlock. A new shutdown test mode exits right after the driver starts.
Prepared captures pass their source handle to the plan reload. When the handle
matches the request, its artifact serves the draw, so the rebuilt resource
program is not kept even if the push layout differs from the artifact's.
A handle that does not match the source is rejected before the entry changes.
Same change as f1b42dae4 on top of c00b0dfb9.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A prepared artifact also serves draws whose push constants start at another
offset. When such a capture reloads a released plan that is missing from the
disk cache, the rebuilt resource program must not stay on the source entry.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A PS5 (firmware 13.60) reports the front left speaker of its speaker info at +30 degrees and the front right one at -30, and -360 for the azimuth and elevation of every empty slot, in every HDMI device type and channel setting it offered. sceAudioOut2GetSpeakerInfo reported the front pair the other way round and empty slots as 0, the front centre direction. The type stays 0: the console's type followed the HDMI device type, and it reported 0 with the device set to TV.
wild 0.10.0 gives no canonical PLT entry to a DSO function whose address a
non-PIE executable takes (wild-linker/wild#2469, fixed after the release by
#2480), so the absolute personality pointer in .eh_frame names a local stub
and every exception reaching main is unhandled.
Co-Authored-By: Claude <[email protected]>
The driver's static is destroyed from its DLL's atexit table at process exit, after ExitProcess has ended the async log's worker. Its stop() then flushed the log through Flush(), which takes the log's lock and waits for every queued line, so it never returned when the worker died holding that lock or with lines queued. #6800's bounded flush runs after it, because the log registers it while the driver is being constructed. stop() now uses that bounded flush, which reads the counters without the lock and gives up after EndFlushLimit, marking the log abandoned. A new shutdown test mode holds the log's lock from another thread and checks that the driver's shutdown still returns.