ARCHITECTURE.md and the libSceAgcDriver debt entry now say that a
settled Windows import under 1 MiB returns to the write watch only when
no storage image overlaps it, and why.
Since #6678, a Windows host import under 1 MiB returns to the write watch
once its deferred settle read has completed, and GuestMemory::Rewatch
stamps every block of it as a CPU store. The return waited only while
storage results were pending over the import. A storage image can take
its generation before the stamp and have results pending only after it:
an image's first upload takes its generation and then imports its block,
a recorded draw marks its targets pending once it is recorded, and the
settle is polled at the import lookups between the two. The image's
next refresh then takes the stamp for a CPU store over its results,
drops them and uploads the guest bytes again, so the GPU's output is
lost. On an RTX 3070 this also splits the first two draws of
agc_driver_address_passes into two passes.
A settled import that a live storage image overlaps now stays compared,
as every import under 1 MiB was before #6678. Imports with no image over
them still return to the write watch. Keeping the import compared, rather
than waiting for the image to go, checks each settled import against the
live images once instead of at every poll. The [buffers] line counts the
imports kept compared.
agc_import_settle_storage_image makes an image whose first upload imports
its block, waits for the settle read, clears the image on the GPU, then
refreshes and stores it. On the old code the refresh drops the clear.
sceKernelReleaseDirectMemory and sceKernelCheckedReleaseDirectMemory returned the range to the
allocator before unmapping its views. The unmap waits for GPU leases on the views, and during
that wait another allocation could take the freed pages and map them while the old view was
still mapped and host-imported, so GPU writes through it landed in the new owner's memory.
Both calls now unmap the views first; the checked call still reports ENOENT for an unallocated
range before it touches any view.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
PlanBuilder::PatchReads emitted GetSrtResource and ReadConst at the end
of the block, then removed each with RemoveInstruction, which scans the
block from the front to find a value that is always at its end. Create
both values directly and insert them before the patched read, as
ResourceTracker's EmitBefore does. The SPIR-V is unchanged.
verifySrtReadPatching now checks that the flat read sits right before
the original read and the planning reference ends the block.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The remap mode stays a specialization constant and cache key input. Scale and
offset are two push words at byte 104, patched per draw, so draws that differ
only in depth range share one pipeline. The recipe, journal and serializer
carry the mode only.
The expected count in the failure message of the staged clear sampled
read test is Threads * 4u + SampleTexelBytes, a std::size_t, but was
formatted with %u. On LP64 hosts that is the only -Wformat warning in
the tree, and the message would print the wrong value.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The player hands out the newest frame that is due and skips the ones
before it (Source.cpp), as a real-time player does, and the test movies
are one second long. Under load, when the test thread runs late, the
WebM case could receive fewer than its five required video frames, and
the playback case, which waited for eight frames and eight audio chunks
before pausing, could reach the end of the movie first and find the
player inactive while paused.
The playback case now pauses after two frames and two audio chunks,
still enough for its timestamp order check, and the WebM case requires
one decoded video frame; its audio, which is not skipped at normal
speed, still has to deliver two chunks.
Co-Authored-By: Claude Opus 5.5 <[email protected]>