Resolve the overlap with main's WindowLaneGuard and image-resource changes
by keeping both sides: DescriptorFault sits next to WindowLaneGuard in the
opcode list, metadata and side-effect switch, and its emitter next to
EmitWindowLaneGuard; optionalDescriptor is serialized after
remappedDepth1D; undefinedImageWords follows the new image helpers; the
descriptor web debt entry follows main's new entries.
The ImageResource field-count assertion is derived from the merged
structure (44 fields: main's 43 plus optionalDescriptor). sizeof
(ImageResource) stays 96 and sizeof(MemoryInfo) stays 80, so those
assertions are unchanged. The undefined-format test keeps its captured
regions in a variable, as MemoryRegionView no longer binds a temporary.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A target in host code got the delivery as an APC as well as through the
return breakpoint and the sampling. An APC runs in any alertable wait,
so host code that waits alertably while holding a lock would have run
the guest handler inside that wait with the lock held. The APC is now
queued only while the target is in a libkernel wait (Pthread waitCount),
the point where the handler already ran before; a target elsewhere in
host code takes the delivery when it returns into guest code.
guest_raise_leaves_host_code adds a target in an alertable
WaitForSingleObjectEx: each raise must return in under 500 ms and the
handler must run in the executable after the wait was released. The
earlier behaviour (an APC for every host-code target) fails it.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
RaiseOn suspended the target and, while it sat in host code, resampled
it until a 50 ms limit and then redirected it into the handler there.
A handler that waits, as Unity's GC thread-stop handler does, then held
whatever host lock the thread had: in Graveyard Keeper 2 a job worker
stopped inside shader specialization kept the shader registration lock,
another worker blocked on that lock never ran its own stop, and the
load froze with 39 of 40 threads acknowledged (about 1 in 15 loads).
A target in host code is never redirected now. The raise queues the
delivery as an APC (taken when the thread waits alertably), arms a
debug register 0 execute breakpoint at the frame's return address into
guest code (found with the image's own .pdata and RtlVirtualUnwind,
stopping at frames that push a machine frame, guarded against faults),
and hands the target to a host deliverer thread that keeps sampling it.
The first of the three to reach the thread delivers, through one taken
flag per delivery. A target in guest code is still redirected at once;
a target inside NtContinue still makes the raise throw after 1 s.
guest_raise_leaves_host_code checks that a handler never runs in host
code, for a target blocked in WaitForSingleObject and one busy in
MultiByteToWideChar, and that each raise of the blocked one returns in
under 500 ms.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
BunnyFl ran firmware 13.42's libSceFont natively against this PR's
checks. With both set, the surface's style frame wins over the argument,
so it is now taken first. A frame that sets no scale, zeroed or only
initialised, is accepted and keeps the glyph's generation scale instead
of returning SCE_FONT_ERROR_INVALID_PARAMETER. A valid
sceFontGlyphRenderImageVertical call, and sceFontGlyphRenderImage on a
vertical font, throw again: the module draws the char call's pixels
there but reports a different advance and stride (40/40 against 90/90
at 40 px), and one case doesn't name the rule.
The test drops the vertical comparison and the non-renderer pointer
check, whose result in the module depends on memory past the pointer,
and checks the frame order and the unscaled frames.
be write-watched at the initial import ("native FMASK contents require
watched guest memory") and at each reuse ("native FMASK sampling requires
watched guest memory"). In Linux comparison mode a host import over the
FMASK unwatches it, so the target is refused one check after the color,
DCC and CMASK ranges that the previous commit accepts.
Treat an FMASK range that a compared host import covers
(ComparedHostImportCovers) as the color and metadata ranges are treated:
keep a copy and its NewestStamp at the initial import, skip it in the
import's UnchangedSinceAll, and at reuse require the stamp and the bytes
to be unchanged, comparing them at most once per collect epoch. An
explicitly unwatched FMASK range is still refused.
Four-sample targets take no FMASK range, so this changes nothing for them.
Refs https://github.com/boykopovar/AnyPS5/issues/9724
Rush 2 Recompiled (PPSA69423) and Wave Race 64 Recompiled (PPSA69424)
stop with "AGC graphics: initial multisampled DCC contents require
watched guest memory"
(https://github.com/boykopovar/AnyPS5/issues/9724). On Linux with
lavapipe, the write-watch probe finds that device accesses to a host
import trip the write watch, so every imported range is compared rather
than watched. A multisampled DCC target whose color, DCC or CMASK range
lies in such an import was then refused at its first draw: importing the
target takes a write generation for each range, and a compared range has
none.
A range that is not watched but lies in a live host import the probe
compares is now copied when the target is imported, and its metadata
again when a whole fill is taken as its fast clear. Each later use
compares the range with that copy, at most once per collect epoch, and
counts any driver or GPU store over its 64 KiB blocks since the copy as
a write, so a guest store of new bytes or any store by the driver
refuses the resident target as a watched range does. A range left
unwatched outside such an import is refused as before.
This covers the Linux comparison mode, not the Windows deferred settle
(BF-150): compared imports on Windows still refuse.
An APS5_AB run interleaves phases A and B, and every periodic report
covers the time since the previous report of its kind, so its numbers
need sorting before A and B can be compared. tools/ab_split.py reads
the [ab] lines and counts a [present], [gputime], [draw] pipelined or
[syncwait] report for a phase only when its whole span lies inside the
phase after its settled line. It prints presents per 10 s and frame
time per phase, GPU busy and idle time per frame, GPU time per present
(also per --program key and --class), committer, drain and hook-wait
times, the A and B means, and each B phase against the mean of its
neighbouring A phases, which cancels a linear drift.
AI-assisted: yes
Two runs of the same scene drift apart by more than many effects worth
measuring. APS5_AB=<seconds>:<switch>[+...] alternates phase A (switches
as the environment sets them) and phase B (the listed switches toggled)
at flip packets, under the GPU mutex after the draw pipeline drained,
and prints "[ab] phase A|B <k> begins/settled at present <n> (t <s> s)".
APS5_AB_START (a flip count, or <n>s) delays the first phase and
APS5_AB_SETTLE (default 2 s) marks when a phase's reports are clean.
Switches live in a registry (RuntimeSwitches) of relaxed atomics that
start as the environment sets them; APS5_NO_BARRIER_BATCH is the first,
since every elision it gates is decided per barrier. Any other name
fails the first flip. Without APS5_AB nothing changes.
AI-assisted: yes
With an NP title id in place, a PS4 Pro (firmware 10.71) answers 0x80551607
from sceNpTrophyRegisterContext through an aborted handle, ahead of the
missing trophy package (0x80551626 through a live handle). The earlier
measurement stopped at the NP title id lookup on both handles.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
On a PS4 Pro (firmware 10.71) sceNpTrophyGetTrophyUnlockState and
sceNpTrophyGetGameIcon answer 0x80551607 through an aborted handle, ahead of
the not-registered check, and aborting the handle again answers 0.
sceNpTrophyAbortHandle now records the abort, the calls that use the handle
answer NP_TROPHY_ERROR_ABORT, and destroying the handle clears it.
sceNpTrophyRegisterContext keeps its answer, as measured without a trophy
package.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
sceCesRefersUcsProfileCp858 threw. It now returns a single-byte profile
accepted by sceCesSbcToUtf8, sceCesUtf8ToSbc and the MBCS context
conversions. Code page 858 is code page 850 with byte 0xD5 mapped to the
euro sign (U+20AC) instead of U+0131; that is the whole high half of
ICU's ibm-858_P100-1997.ucm. Bytes 0x00-0x7F stay unchanged, as in the
other single-byte profiles.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01FzhWRMauD3ouc8kSxT2NnT
The debt entry for 11_11_10 float color targets covers rendering but not the
resolve. A CB resolve of a multisampled 11_11_10 float source stays refused;
the new entry says that its averaging and rounding are not measured, that no
known source describes them, and that PPSA12361 reaches it (issue #11362).
AI-assisted: yes
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Console libSceLibcInternal exports Y9C9GeKyZ3A as a 136-byte STT_OBJECT;
titles that resolve the wide num_get vtable as data need a zeroed 17-slot
object matching the narrow num_get layout on console.
A create over a marked state now retires the encoder its instance id
names before any state write or allocation, so a replacement lost to a
host allocation failure or the libopus OPUS_ALLOC_FAIL branch cannot
strand an entry the state no longer names: Destroy and Terminate stay
consistent on every failure path. The debt notes record the
replacement rule as our choice with the console failed-replace
behaviour unmeasured and why the tests cannot force the failure
paths.