Importing guest memory collected the write watch over the whole import,
which write-protected every page of it, so pages nothing had collected yet
took a write fault on their first CPU write. The import now collects only
the parts a collect already protects (GuestWriteWatchCollectArmed). The
rest stays unprotected until something collects it, which reports it as
written; a GPU write recorded into such memory (MarkWritten) first collects
the never-collected parts of its 64 KiB blocks
(GuestWriteWatchCollectFresh), so that report is older than the GPU's
results and does not read as a CPU write over them.
Those pages are stamped as written and their CPU pages are noted, but the
block's CPU stamp is left alone, so a GPU label record or a pending storage
image elsewhere in the block does not see a CPU write. StoredOver and
UnchangedSinceCollected read the noted pages whenever a block has them, so
a store to such a page is still seen by a check over that page. The extra
generation step happens only when something was collected; a block whose
write protection fails is unwatched and the write returns no generation.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
flock_nid_postfix threw on every failure, so a LOCK_NB request on a lock
held through another descriptor ended the process. FreeBSD flock(2)
returns -1 with EWOULDBLOCK there. Return guest errno 35 when LOCK_NB is
set and the host reports the lock as held: ERROR_LOCK_VIOLATION on
Windows, EWOULDBLOCK on Linux. Other failures still throw.
A formatted buffer load or store whose format comes from a prepared
descriptor emitted the switch over every buffer format inline, at each
access. The switch is now emitted once per resource, component count and
direction as a SPIR-V function taking the index, offsets, record count and
storage buffer offset, and each access calls it. Specialization still folds
the switch to the descriptor's format. Accesses through GPU-selected
descriptors keep the inline switch.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
FreeBSD's __sflags reads the access character, then b, +, x, e and v, and
stops at the first other character without failing, so "rt" opens for
reading. On Windows fopen inserted b after the first character and passed
the rest on, so "rt" became "rbt", the CRT rejected it with EINVAL, and
fopen threw. vkQuake opens history.txt with "rt" at startup. freopen
accepted only a fixed list of modes.
Both now parse the mode like __sflags. An unknown access character, or x
on a read-only stream, returns NULL with EINVAL; x on an existing file
returns NULL with EEXIST; e and v are accepted and ignored.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
An anonymous private mapping with MAP_ALIGNED_SUPER (FreeBSD MAP_ALIGNED(1))
is placed on a 2 MiB superpage boundary. Yamagi Quake II requests it for its
hunk allocations of 2 MiB and more.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
SDL queries the SCHED_OTHER range before it sets a thread priority. It gets
the same 256 to 767 range as SCHED_FIFO and SCHED_RR, which
pthread_setschedparam applies regardless of policy. The console's answer is
unverified and recorded in TechnicalDebt.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A global_store_dwordx2/x3/x4 was split into one StoreAddressU32 per
dword, each with its own write-pointer lookup and its own 4-byte store.
Across a wave those are strided partial writes, which are very slow to
host memory: RADV's clear_htile_mask kernel (one dwordx4 load and store
per thread over 640 KiB) took ~9 ms. Multi-dword stores are now one
StoreAddressU32xN; the emitter probes the whole span once and, when it
is mapped writable and 4-byte aligned, stores it as one vector (16- or
8-byte aligned) or as consecutive dwords, noting each written page.
Anything else takes the per-dword path as before, so faults and
range-spanning stores behave as they did. APS5_BDA_DWORD_STORES=1
restores per-dword stores.
AI-assisted (Claude Code).
Co-Authored-By: Claude Opus 5.5 <[email protected]>
0xffff1000 is a type-3 NOP whose count field is 0x3fff, which the command processor reads as a single dword. The driver read it as a 16385-dword packet and rejected every sceAgcDcbResetQueue envelope. Pm4::FillerPacket now also matches exactly this header, so every packet walker steps over it as one dword.
Refs #1581