Vulkan lets a device return either neighbour when it converts a float to a
normalized texel, and devices differ: for a product of 123.50003, NVIDIA and
Intel both store 123, and on GTA V's FSR1 RCAS compute pass the two vendors
stored different bytes for the same inputs.
Writes to unorm and snorm storage images whose components share one width
now clamp the value (NaN to 0), round value * scale to nearest even in the
shader and store level * c, where c is the smallest float not below
1 / scale. The exact product of that float with the scale lies in
[level, level + 0.01) for 8-, 10- and 16-bit unorm and snorm, so a device
that rounds to nearest and one that truncates both store the level. The
format comes from the image descriptor through specialization constants
(StoreQuantizeBase, four per written storage image), so other formats keep
the plain write.
Test: agc_driver_image_store_unorm_rounding stores values next to the
midpoints between levels, edge values and NaN/infinities to 8_UNORM,
16_16_UNORM, 8_8_8_8_UNORM, 8_8_8_8_SNORM and 16_16_16_16_UNORM images; it
fails on main on an RTX 4090 and on an Intel UHD 770 and passes on both with
this change.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01XBXM4pgkMHYEtqN1EQni2P
Replace the leading-slash absolute-target check with a root-name/root-directory
check so Windows targets like C:/ or \\server\share are rejected too, and
add guest tests covering rejected (.. , ../x, a/../b, a/../../x, /abs, plus
C:/ and UNC paths on Windows) and accepted (sub/dir, a..b, ...) targets.
PipeRead (guest_kqueue) and the blocking read in guest_socket_events took
their start time after creating the thread that writes after 50 ms, so a
main thread preempted between the two measured less than the writer's
sleep and failed the 40 ms check although the wait did block until the
write.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A recorded draw's pass access listed its shader-resource reads, indirect
arguments, storage images and resident color targets, but not the index
and vertex ranges it binds in place from host imports
(DrawInputs::inPlaceReads) nor its multisampled color targets (null in
RecordedDraw::targets). A later draw writing those ranges through a
shader buffer, or a pass sharing the multisampled target under another
pass key, found no hazard: the break between the passes recorded no
barrier, or the later draw continued the pass, so its writes could land
before the earlier draw fetched its inputs, and the two passes' attachment
writes and store operations on the multisampled image were unordered.
The in-place input ranges join the pass reads, and MultisampleTargetView
reports the target's image, which joins the pass attachments as written.
symlink_nid_postfix blocked absolute targets but accepted relative
targets containing '..' unchecked. The target is stored verbatim and the
host OS follows it when the link is later opened through the guest path
resolver, so symlink("../../../../..", "e") followed by
sceKernelOpen("e/etc/passwd", ...) reads host files outside the guest
root. Reject any '..' component, mirroring the absolute-target handling
above it.
In PS4 executables and modules the bytes between unwind functions are
16-byte slots of function tails and padding, and a tail can begin inside
an instruction, such as a lone REX byte before a 15-byte NOP. The
syscall and call-site scans decode the executable segment linearly, so
such a slot failed the relink with "Cannot decode instruction".
For images with a PT_SCE_DYNLIBDATA segment the scans now receive the
unwind function ranges. Outside every range an undecodable byte is
skipped and decoding resumes at the next byte, and a decoding that would
cross into a range ends at its start, so gap bytes cannot change how a
function is decoded. Inside a range a decode failure still fails the
relink, and images without unwind ranges are scanned as before.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
With WinLibs, std::this_thread::sleep_for under 1 ms returns at once, so
close raced the reader in every round and a run where all 60 rounds lost
the race aborted. The test now waits with PreciseSleepUs.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Resolves MultisampleTarget against #6635: the sampled view takes the requested view type and keeps the sampled-only usage when the target has a storage view for the guest's sample order.
RADV gives each image its own pipe-bank XOR when it creates it. When Ruffle
recreates a 4x render target on the same memory, the next draw names the
same surface, DCC and CMASK with another XOR, and the resident target refused
it as a changed layout ("multisampled DCC target layout or metadata
changed"). A use that differs from a resident DCC target only in that XOR now
keeps the target's image, views and cached textures, takes the new layout,
and reimports its contents from the current DCC and CMASK metadata the way a
first use does, clearing the image to that color after the work already
recorded against it. Any other layout change is still refused.
Reusing the image keeps memory flat: Ruffle's cache_as_bitmap__avm2_button
recreates its 864x864 4x target 28 times in 32 s.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
On Windows, sceKernelRaiseException suspends the target and redirects it to
the guest handler wherever it stopped, except inside NtContinue or
winpthreads. A target stopped inside host code (a C runtime call, a host
library) can hold a host lock there; a handler that then waits, as a
collector's thread-stop handler does, keeps it held, and every host thread
that needs the lock stops with it. SONIC SUPERSTARS stopped at frame 65 this
way: its "UDS" thread was redirected inside the stderr write of a trophy
message and parked in sceKernelWaitEventFlag holding the stream lock, and the
driver's logging threads blocked on it.
A target running code of a module other than the executable or a guest
module is now resumed and suspended again until it is back in guest code,
for up to the existing retry limit; a target blocked in an ntdll wait is
still redirected there, as before.
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
The write-back padding test gains an unpadded surface, a padded one and
one that spans two slabs, writes each of them back twice and checks the
stored texels and the untouched bytes after each write-back. The storage
refresh, write-back padding and single-pass tests run as
agc_storage_write_back.
writeBackWindows retiled every window into a device scratch buffer and
then copied the kept bytes from the scratch into the unit-shadow slabs,
so each stored byte was written twice.
A window now retiles straight into its slabs, one dispatch per slab
piece, when its kept range is its whole tiled range, every piece goes to
a slab that needs no seed, the pieces are tile-block and 4-byte aligned,
and it is not a tail, thick or saved slice. The bytes no element covers
are copied into the slab from their current source before the retile,
or left alone when the slab already holds them. Every other window keeps
the scratch path, and the scratch is not allocated when no window needs it.