storedLaneFunction took &words[offset + 1] for every instruction,
including the final one-word OpFunctionEnd, where offset + 1 equals
words.size(). GCC 15 and later define _GLIBCXX_ASSERTIONS in unoptimized
builds, so agc_spirv_optimizer, agc_spirv_optimizer_full and
agc_spirv_optimizer_none abort in every Debug build with
"Assertion '__n < this->size()' failed". Form the operand pointer from
words.data(); operands are still read only for instructions that have
them.
sceRudpPollCancel waited until no wait was registered, so a wait that
started during the drain kept it blocked, forever for an infinite one.
Waits registered when the cancel starts now move to a draining count,
and the cancel returns once those have left. A scope guard releases each
wait's registration on every exit, retaking the lock if the wait had
dropped it, so an exception in the condition wait no longer leaves a
registration that a later cancel can never drain. Reported by
@MarcZX10, @thepoppfish, @adriadam10 and @oneandonlydean; the guard
follows @thepoppfish's repair.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
v_fma_f32, v_fmac_f32, v_fmamk_f32 and v_fmaak_f32 threw "f32 denormal
mode 2 is not implemented" whenever FLOAT_MODE flushed f32 denormal
inputs but kept denormal results.
On RDNA2 (gfx1036) at round to nearest even, mode 2 flushes the inputs
and rounds the fused result once with gradual underflow, which the host's
Fma gives under DenormPreserve 32. The translation now matches all 5,596
measured triples for the four forms at IEEE 0 and 1. Mode 1 keeps
throwing: there the hardware flushes a result that is tiny after rounding
with an unbounded exponent even when the addend is nonzero.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
All four threw "f32 denormal mode N is not implemented" whenever
FLOAT_MODE kept only one side of the f32 denormals.
On RDNA2 (gfx1036), in every f32 round mode and at IEEE 0 and 1, mode 2
gives the results of mode 0 and mode 1 those of mode 3 with a denormal
result flushed, which only v_fract_f32 of a positive denormal produces.
The translation now matches all 118 measured inputs in modes 1 and 2.
Mode 1 of the three that run host float operations on a kept denormal
needs DenormPreserve 32, as v_min_f32 does.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
writeBackLayers printed "StorageTexture writeback submit" and "StorageTexture
writeback done" unconditionally around the blocking submit of every storage
image writeback. In five GTA V (PPSA04264) runs they were 54 to 978 lines per
run, 5 to 55 % of the log. They now use APS5_LOG_CHARS_OUT_DEBUG, like the
other per-operation lines of the AGC driver, and are compiled out unless
APS5_DEBUG_LOG is defined.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Seven of the titles here import scePadSetTriggerEffect and no test reaches
it. Pin the requests it leaves in the port's output state: a weapon and a
feedback command as their DualSense effect bytes and fallback strengths,
the trigger mask leaving the other trigger as it was, an off command, and
a special handle leaving the output alone.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Crimson Desert calls scePthreadRwlockTryrdlock, and its only test is on a
destroyed lock. On a lock made by scePthreadRwlockInit: two readers take
it, a try for the write lock is busy while either holds it, the write lock
is taken once both left, a reader is then refused, and after the writer
unlocks a reader takes it again.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Both log their arguments and the caller and return. Note what the
titles' bundled libc.prx passes them and that three of its
sceKernelDebugRaiseException calls are followed by ud2 in every build
checked, so the guest reaches that ud2 here.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
sceNpUtilJsonEscape has to stay inside a partly filled 16 byte buffer and refuse
one without a terminator, sceNpUtilJsonUnescape has to report the length of a
query with a null destination and size 0, and sceNpUtilJsonGetOneChar has to
reject a high surrogate that is not followed by a second unicode escape.
The final room check ran even when dst was null, so a size query such as
(nullptr, 0, src, n, &length) returned NP_UTIL_ERROR_BUFFER_TOO_SMALL and never
wrote the required length, although the per-character checks in the same
function already skip the comparison for a null destination. The check now
applies only when there is a destination.
After a high surrogate, sceNpUtilJsonGetOneChar parsed four hex digits at offset
8 without checking that offsets 6 and 7 hold a backslash and a 'u'. The string
"\ud83dXXde00" decoded to U+1F600 and consumed 12 bytes, swallowing the two
unrelated characters. sceNpUtilJsonUnescape already makes that check. A high
surrogate not followed by \u now takes the same failure path as an invalid low
surrogate.
sceNpUtilJsonEscape appends to the destination with strcat, but the room check
started its running length at 0 and ignored the text the buffer already held,
so escaping into a partly filled buffer wrote past its end:
sceNpUtilJsonEscape(buf, 16, "\n\n\n", 3) on a buffer holding ten characters
placed 16 characters and the terminator in 16 bytes.
The running length now starts at the length of the existing text, and a
destination that is already full returns NP_UTIL_ERROR_BUFFER_TOO_SMALL.
On Windows, GuestMemory::Unwatch excludes every page of each 64 KiB
block it touches, so unwatching one page of the descriptor unit left the
whole unit unwatched and the "descriptor page lost write watching" check
failed. Unwatch the unit and return only its descriptor page with
Rewatch there, which is page-granular, so the unit is partly watched on
every platform. Linux keeps the single-page Unwatch.
Diagnosed by maskym on Windows 11 26300 with an RTX 2070 SUPER.
Co-Authored-By: Claude Opus 5.5 <[email protected]>