RSQRTPS and RCPPS are approximations whose low bits differ between Intel
and AMD. Intel returns 0x3F7FF000 for 1/sqrt(1.0), and two Newton-Raphson
steps on it settle on 0.99999994 instead of 1.0. PPSA21564 renormalises
its spring quaternions that way: an identity quaternion keeps w at
0.99999994 with a zero axis, its axis-angle conversion then normalises the
zero axis into NaNs, and the NaN bone poses reach keyframed physics bodies.
A NaN body later moves to an invalid broadphase cell and the game crashes
a few seconds into its hub level.
--to-intel now replaces the VEX.128 register forms with an out-of-line stub
that computes 1/sqrt(x) with SQRTPS and DIVPS (1/x with DIVPS), keeping
the upper half of the destination cleared and the scratch register intact.
A site with no room for the jump, including one followed by a branch
target or a RIP-relative instruction, keeps the native instruction and is
reported as kept instead of failing the relink.
A store the driver makes with the CPU into watched guest memory (a
GuestMemory::Write, a changed-bytes write-back, a completion action's label
store, the copy HLE's CPU path) faults its pages dirty in the write watch and
stamps the range with MarkWritten. The faults stayed behind: collects are
memoized per packet, so the next walk over those pages came later and stamped
them again, as a CPU write made after every check in between.
PPSA21564 fast-clears its normal G-buffer every frame with a register DCC key
fill on the GPU. While that fill is still pending, the first draw into the
target materializes the clear with a CPU store of the clear texels and a
refresh of the resident image. A dozen draws later a walk found the store's
faults, the target read as changed, and the image was uploaded again from
guest memory, dropping the draws recorded in between. Lighting then sampled
cleared normals and the level's moon and rocks went unlit in about half the
frames.
The driver's stores now consume those faults themselves: a walk before the
store stamps earlier CPU writes as such, a walk after it takes the store's
own faults as a driver store, and the range is stamped as before.
On Windows the arena's range also holds host regions that were already in
use when it was reserved (heaps, thread stacks). They are not write-watched,
so a store into one is stamped as before, without a walk.
The 22 exports used by PPSA21567 take the call shapes recovered from its
call sites (#481): destroys take the system and the object, attribute
setters take a count, SourceCreate takes only an output handle,
UnregisterMaterial only the material.
The system lives in the title's CPU memory (16-byte header, no GPU memory)
and its handle is that address; rooms, portals, sources and materials are
counter handles. Attributes are validated and have no effect; no rays are
requested and sources report no audio paths. Non-empty ray results, path
calculation and audio paths throw, SourceRender stays unimplemented, and
invalid input throws because no error code is known. Objects left when
their system is destroyed become unusable; their later destroy or
unregister is a no-op.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
GCC gives C code built with -fexceptions, and cleanup-only functions
after link-time optimization, the C personality __gcc_personality_v0.
The unwinder accepted only its own C++ personality, so an exception
thrown through such a frame was never caught.
libc now provides the C personality, which never catches and installs
the frame's cleanup landing pad in the cleanup phase, and the unwinder
calls it for those frames.
PPSA21564's galaxy map renders a 1920x1080 surface as a color target whose
CB names DCC keys at one address and then writes it from a compute shader
whose T# names keys at another. Both key ranges read uncompressed every
frame, but the storage cache remade the surface's image whenever a
descriptor named metadata other than the image's, so the image was
flushed, destroyed, created and uploaded twice a frame (1231 constructions
in a 56 s scene), with the views and draw recipes built on it thrown away
each time.
A descriptor naming other keys now keeps the image when the move is
unobservable: the image's own keys and the named keys both read
uncompressed, and its content was neither uploaded nor filled under a
clear code. That is exactly the content an image made under the named
keys would hold once this one's pending results were stored. Any other
case (a fast clear of either key range, a register clear, an image
holding a clear) still remakes the image as before, so clears of the new
keys reach it and pending results are stored first.
Every proof that stands in for a lookup checks the same rule: the sampled
view hit, the fast revalidation of views and storage elements (storage
elements now record their descriptor's keys), the own-object refresh, and
the draw recipe's resident targets. Named-key scans keep per-image proofs,
so a repeated check costs no scan while the key bytes are unstamped.
agc_dcc_key_sharing drives KeysServeSurface, the rule ServesKeysAt uses,
through a model of the storage cache.
Driver::Submit checks the title's submission packet, which the title
passes on its own thread stack. Host thread stacks are neither registry
mappings nor write-watched, so no page-state cache covers them and on
Linux every check scans /proc/self/maps line by line: about 1.5 ms per
submission on the render thread of PPSA21564 (66% of that thread's
samples in perf at the title).
A range between the calling thread's current frame and its stack's top
holds the frames of every caller, so it is mapped readable and writable
for as long as the call lasts; verify() now accepts it without a query.
A thread on another stack (a fiber's, a signal stack) has its frame
outside the thread's bounds and still gets the page query, as does any
range that runs past the stack's top or starts below the frame.
GetCurrentThreadStackLimits needs _WIN32_WINNT 0x0602 on MinGW, as
libkernel already sets; GuestMemory.cpp is compiled by several targets,
so the definition is a property of the source file.
SourceVersion hashed every libSceAgcDriver source, so any driver-only
change sent the shader disk cache cold: 88 of the last 200 merges on main
did; with the inputs below, 51 of them would have. It now covers:
- core/shader/recompiler/** (sources, headers, CMake);
- prx/libc/include/HostThreadLocal.hpp, the one header the recompiler
includes from outside its directory (checked against the ninja deps);
- the checked-out commits of SPIRV-Headers and glslang, plus SPIRV-Tools
when ANYPS5_ENABLE_SPIRV_TOOLS is on (the submodule HEAD files are build
dependencies, so moving a submodule regenerates the version);
- the compiler, build type, architecture and C++ flags.
Everything else the driver passes to the recompiler arrives in the
RecompileRequest, which the per-entry key covers. Two build-time checks keep
that true, failing the version step with a message naming the file:
- a recompiler source that includes a project header outside the hashed set;
- a driver source that calls or using-declares a ShaderRecompiler name not
on the reviewed list, pulls in the whole namespace, or sets an environment
variable (which could flip a recompiler APS5_* switch behind the key).
APS5_* switches are collected from every hashed source. The version script
sets cmake_minimum_required: without it CMake 3.x runs it with CMP0054 OLD
and reads the quoted section names in its if() tests as variables.