NVIDIA's Windows driver reads a host import of guest memory far slower than a buffer it allocated.
Since draw vertex and index ranges are bound in place from host imports (#2253, measured on Linux), Astro
Bot's Crash Site on Windows 11 with an RTX 5070 Ti spends 164 ms of every frame in draws on the GPU, and
45 ms with the ranges copied as before; with the same build, 4.71 fps in place against 7.52 copied. An
RTX 3060 shows the same (draws 32.3 against 24.3 ms per frame), while AMD's Windows driver reads them in
place about as fast as a copy (RX 9070 XT: 69.8 against 73.1 ms), so copying there only costs CPU.
The device decides once (DrawInputsInPlaceUsable, Context::drawInputsInPlace): ranges are copied with
VK_DRIVER_ID_NVIDIA_PROPRIETARY on Windows and bound in place everywhere else. APS5_DRAW_INPUTS_IN_PLACE=1
binds them in place and APS5_NO_DRAW_INPUTS_IN_PLACE=1 copies them on any device, the second winning.
agc_draw_inputs_in_place_driver checks the decision per driver and host; agc_draw_inputs_copied checks
that an aligned imported range is copied and its read not noted when the context copies, whatever the
inherited environment.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GN8FJFTedayRXLHythXkZ4
The MinGW libstdc++ reports a dangling symbolic link as missing and clears
the error, so std::filesystem::remove neither deletes it nor fails, and
remove_all loops forever over a tree that contains one. Remove reparse
points with DeleteFileW and RemoveDirectoryW and the fixture through the
shell; record the gap in the libs technical debt.
A CPU read of DISPATCH_INDIRECT arguments waited only through the flush
hook, which waits for the ranges recorded work noted as pending writes.
An address-based store (FLAT/GLOBAL, or through a descriptor the
recompiler cannot resolve to a static buffer) is not recorded as a
pending write: its batch leases the registered allocations, and only the
guest pin waiter finished that batch. So the thread-dimension,
misaligned and disabled paths, the fill-kernel path and the device's CPU
fallback read the arguments from before an address-based producer ran.
GTA V (PPSA04264) dies loading Story on such a read: a 64-thread clear
kernel read {160, 288, 0xffffffff} as thread dimensions
(3x288x4294967295 groups), bytes its 1-thread setup kernel had not yet
overwritten with {n, 1, 1}, and threw "workgroup count
3x288x4294967295 exceeds device limits".
Every CPU read of dispatch arguments at execution now first finishes the
recorder up to the newest batch recorded with a lease
(Graphics::FinishLeaseWork). The group read-ahead still reads without
waiting; a dispatch it resolved is adopted only when the execution-time
read gives the same counts, and one that differs is dropped and counted
in the [groupcap] line. The device limit error names the argument
address and cpuReason, and the driver adds the queue, path and
read-ahead outcome. The [indirect] read time includes the lease wait,
and the [recorder] sync-site table records the offset of
FinishLeaseWork's caller. The CPU reads that still miss address-based
writes (indirect draw arguments and count, the copy kernel's count
record, the awaits-title checks) are listed in the technical debt.
IndirectArgumentsPendingProducer covers the execution-time CPU argument
reads on compute queues and the pending-label CPU fallback in the Vulkan
device. Its sixth case records a real argument label behind a host Vulkan
event in an earlier batch and an address-based producer in the later open
batch. The event releases only after that producer batch is submitted;
a bounded watchdog releases for cleanup but fails the case. It requires
a deferred producer lease, an unsubmitted producer at the argument
decision, cpuReason 2 and the fresh arguments and counter result. Small
valid stale counts keep a broken-wait control finite on every driver.
Exact CPU-reason and watchdog diagnostics identify the failing path. This
replaces a spinning workload whose earlier label could retire before
the fallback decision on lavapipe, allowing a false green with cpuReason 0.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Codex <noreply@openai.com>
The C runtime allows 512 stdio streams by default, so after about 509
guest fopen/fdopen streams every further stream failed with EMFILE,
including the std::ifstream APR opens for each read, while getrlimit
reports 8192 open files. Raise the limit to 8192 when libkernel loads,
as the Linux build raises RLIMIT_NOFILE.
A picture deeper than 8 bits threw ("output deeper than 8 bits is not
implemented"), which stops Mortalfin (PPSA99141) as soon as it plays an HEVC
Main10 video (#6640).
A 10-bit picture is now written as 16-bit little-endian words with the sample
in the low 10 bits: Y rows, then interleaved UV rows at framePitchInBytes
times the height. framePitch is in samples and framePitchInBytes in bytes
(twice the width, aligned to 256). QueryDecoderMemoryInfo sizes a frame of an
HEVC or VP9 profile 2 configuration with two bytes per sample.
The layout and sizes follow EVO-PLAYER-PS5, which decodes and presents 1080p
HEVC Main10 on hardware through this path: its 10-bit check
(pitch_bytes >= pitch * 2), its UV offset, its low-bit sampling factor, and
the 1920x1088 Main10 frame buffer its hardware log reports (6128 KB after
rounding to 16 KiB).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>