vkGetPipelineCacheData is not stable in size on a driver that keeps
pipelines: RADV grows a loaded cache by 8 bytes on the first create and
shrinks it by 8 on a later hit, so an exact size match reports a hit as a
miss and agc_pipeline_cache_file fails on hardware. lavapipe keeps
nothing, so every size stays equal, the probe reads that as a device that
does not store pipelines and the test skips, which is why CI never saw
this.
Size each pipeline in an empty cache first and treat a change below half
that as a hit, and skip on a device where a pipeline adds nothing.
Co-Authored-By: Claude Opus 5 <[email protected]>
The initial import of a native multisampled depth target only proceeds
when every HTILE word proves the same clear value, so no compressed Z
planes are read from guest memory. ITERATE_256 only changes how the DB
and the texture unit walk compressed MSAA Z planes (Mesa
ac_descriptors.c: "TC-compatible MSAA HTILE requires ITERATE_256").
The HTILE footprint (Addrlib) and the HTILE clear words (Mesa
radv_get_htile_fast_clear_value) do not depend on it. The import no
longer requires it; the texture's ITERATE_256 must still match the
target's.
Unblocks PPSA27836 (Onimusha: Way of the Sword), which samples a
four-sample D32 target with pipe-aligned HTILE and ITERATE_256 off.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The constant folder now knows which bits a value can hold (masks, merges,
shifts, field extracts, 16- and 8-bit widenings, selects) and which bits a
user reads:
- a mask that clears no bit the value can hold is dropped, and so is a
merged part with no bit under the mask;
- And(And(x, a), m) becomes And(x, m) when m keeps no bit outside a, and a
mask rewrite is folded again;
- a field extract, shift, mask or 16-bit truncation reads through masks
that keep the bits it reads and through merged parts that hold none;
- a right shift of a left shift by the same amount becomes a mask;
- BitFieldUExtract(x, 0, n) is x when x has no bit at or above n;
- Or of two masked parts of one word becomes the word under the union of
the masks (the word itself when they cover it);
- a field extract of a left shift reads the unshifted word.
These patterns come from 16-bit halves of 32-bit registers (f16 and packed
math), which the translator splits and merges per instruction.
Test: agc_constant_bit_test gets six cases (repeated, narrower and wider
masks, a mask under a merge, half extractions, halves that rejoin); all six
fail on main.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01XBXM4pgkMHYEtqN1EQni2P
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]>