Since #5364, Draw/DrawRegisterKey.hpp includes Shaders/ShaderRegistry.hpp,
which reaches ShaderMemory.hpp and its "Recompiler.hpp". tests/Pm4.cpp
includes DrawRegisterKey.hpp, but agc_driver_pm4_tests only links
libSceAgcDriver, libc and libkernel, so the recompiler's include
directories are not on its path and Pm4.cpp no longer compiles. The test
targets that already reach ShaderMemory.hpp link shader_recompiler_agc_driver;
this one now does too.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
ConstantFolder::Fold visits each instruction once, in block order. A loop
header phi whose back-edge value is a later phi that folds to it in the
same pass, such as the header phi of an inner loop in which an S# is
copied out and back, is visited before that phi folds and stays a phi of
its one definition and itself. Later folds run only after read-lane or
masked-select elimination changed the program, and since #4150 the one
after masked-select elimination only runs in programs where a
PackedAncillary builtin still has live uses.
These phis reach resource tracking, which compares descriptor dwords as IR
values, so the phi of an S# and the S# itself become two samplers. Two
PPSA11386 (007 First Light) pixel shaders each had 21 direct samplers for
6 distinct S# values; at two heap slots each they exceed the 32 sampler
slots, and the shaders stopped at their first draw with "shader sampler
pairs exceed runtime heap capacity".
After its pass over the instructions, Fold now folds the phis of its
blocks again until a pass folds none. Each fold turns a phi into an
Identity, so the loop ends. Replayed on an older local branch with #4150's
restriction in place, the captured requests plan 6 samplers each, one per
distinct S#, and recompile. agc_shader_memory compiles an S# copied out
and back in three nested loops and sampled before and inside them, with
and without a masked write: one sampler and one sampled pair each, two of
each before.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
On Windows the write watch is dropped in whole 64 KiB blocks
(WriteWatchCoverage::Exclude), but the unwatch hook was given the page
range of the import. An image with results pending in the same block as
an imported page, outside that page, lost the watch without its guest
bytes saved, and storing its results threw.
The hook now gets the span of blocks Exclude drops (ExcludedSpan, the same
block math), so every image with results pending in those blocks saves its
bytes first.
__sync_fetch_and_{add,sub,and,or,xor}_16 and __sync_lock_test_and_set_16 are
cmpxchg16b loops returning the previous value, and __atomic_is_lock_free
answers by size and alignment, as in the libc.prx bundled with PPSA08427. Its
generic __atomic_load/store/exchange/compare_exchange are a ud2, so they throw.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Q8tinbP1MUpUaDsbNWnGnu
VideoOut flips on an RTX 3060 now show that a first frame dump that cannot be opened no longer stops presentation. Header, pixel and close failures remain measured only by the CPU fixture.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A multisampled depth target is created as, or already is, the native depth owner, and a target whose HTILE overlaps a resident depth guard aliases one. Neither may have its HTILE read or rewritten by the generic store-back: the expanded words would be a guest write over the owner's range. DepthSurfaceView decides this before the store-back, which still runs before GpuMutex() and the surfaces mutex are taken. NativeMultisampleDepth binds the owner and a single-sample alias of its HTILE and checks the words stay untouched.
Soft-float arithmetic and comparisons, float/double/x87 conversions to and from
32-, 64- and 128-bit integers, __extendsfdf2, __truncdfsf2, complex
multiplication and division and __powixf2, matching the libc.prx bundled with
PPSA08427: soft-float results ignore MXCSR and raise no flags, division flushes
subnormal quotients, NaN payloads are moved unshifted and float-to-integer
conversions do not saturate.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Q8tinbP1MUpUaDsbNWnGnu
A fill or clear the driver recognizes over an HTILE drops the range's last-read generation, so the
next bind reads the words and stores them back even when the write tracker did not see the fill's
stores. A depth view of slice 1 or later reads the HTILE at its own address
(DB_HTILE_DATA_BASE + slice * HtileMetadataBytes); the HTILE word layout is only modelled for slice 0,
so such a slice takes the clear and the store-back only when all its words are equal and keeps its
fill-time fast clears otherwise. DepthTarget::slice carries DB_DEPTH_VIEW SLICE_START.
agc_driver_depth_fast_clear_submit: an unrecognized kernel clears the HTILE on two frames in a row and
both clears are taken; slice 1 with words that are not all equal is refused and stored back untouched;
slice 1 with equal words takes the clear. agc_driver_graphics checks the decoded slice.
The bind-time HTILE read covered one word per 8x8 tile from DB_HTILE_DATA_BASE, but main models the
HTILE as the pipe-aligned SW_64KB_Z_X metadata (HtileMetadataBytes, the extent HtileFillCovers takes):
at 1920x1080, 1856 of the 32400 tile words lie past the first tiles*4 bytes, so they kept ZMask 0
after a store-back. The read and the store-back now cover the whole metadata and run before the
surfaces mutex is taken, since both wait for recorded work over the range. The tests' HTILE arrays
hold the whole metadata.
PPSA25344 (Unreal Engine 5) decodes its depth through HTILE in its Nanite depth export after the
depth prepass and takes ZMask 0 as a tile holding the clear value; the new
agc_driver_depth_fast_clear_submit case checks that a draw after a fast clear leaves every word
expanded.
The libc.prx bundled with PPSA08427 returns 32 from __clzdi2 and __ctzdi2 and
64 from __clzti2 and __ctzti2 for a zero argument; found by comparing every
builtin against it on random inputs.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Q8tinbP1MUpUaDsbNWnGnu
A sampler voice set up with an all-zero format has no channels. Adding no
waveform blocks to it, or setting a matrix with no levels, threw
std::invalid_argument, which ends the title.
Accept both on such a voice: the empty add only applies RESET and the
CONTINUE state, and the empty matrix clears that matrix, which rendering
already treats as unset. Blocks with data, APPEND, and an empty matrix on
a voice with a format are still refused.
Steins;Gate Re:Boot (PPSA36591) clears a voice this way when a button is
pressed at its title screen.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
GuestImageReader::ReadModuleNames lost its only caller in 41126bfa5.
EmitShiftImm and ElfReader::ReadSection have no callers.
ValidationPolicy's NID, SCE structure size, dynamic field and syscall
instruction checks are never called, ValidateSyscallAbsence is empty,
and RegisterLibraryImport only fills the library set that the unused
NID check reads.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A buffer copy whose source is exactly a live storage image becomes a device
copy between images (AliasCopy). Its results stayed pending in the destination
image and reached guest memory only at a later flush, so a guest that waits
for a label recorded after the copy and reads the destination on the CPU (a
readback) read the bytes from before the copy. Store the destination's results
in the same batch, behind the image copy.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Use checked host stdio for BMP output and stop requesting dumps after the first write failure. Keep pixel validation, allocation and non-I/O failures on the existing fatal path.
Co-Authored-By: Codex <[email protected]>
FoldVertexLaneBounds replaced every LaneId < 32 compare of a vertex
program on a fixed 32-lane host subgroup with true. The half-wave scan
matcher of the SPIR-V backend recognises a lane word by the select of its
low and high words on that compare. A scan keyed by the entry EXEC ballot
lost that shape, so its v_readlane_b32 of lane 63 was no longer read as a
half-wave reduction and the recompile failed (agc_shader_memory).
Fold the lane word select itself instead, and only when both words are
constants. Lane words built from ballots or other values keep their
lower-half test.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
#6292 moves the APS5_PROFILE_DRAW check in Driver::timed to the top and
rewrites the report's condition, the two lines this branch's driver-time
line sat between, so the two conflicted. The line now follows the
report. It reads the same flag and times, so it counts the same.
LibAtrac9 defines six channel configurations but indexed the table with all eight values of the 3-bit field, so indices 6 and 7 read past it and initialized a decoder from the bytes that follow. The config data check now fails for them, which sceAjmDecAt9ParseConfigData, AJM initialization, libSceAudiodec and NGS2 already report as invalid config data.
Co-Authored-By: Claude Opus 5.5 <[email protected]>