sceSysmoduleLoadModule and sceSysmoduleIsLoaded already accept ids the
project does not know and log them; unloading such an id threw, so a title
that loads and later unloads an unknown module aborted at the unload.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
SCE_USER_SERVICE_ERROR_INVALID_ARGUMENT is 0x80960005; 0x80960002 is
NOT_INITIALIZED (the neighbouring NO_EVENT 0x80960007 and BUFFER_TOO_SHORT
0x8096000A already match the real sequence). The privacy getter returned the
raw value and now uses the constant.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Since direct memory mapped at two addresses is shared read-only instead of
refused, the guest memory test expected an exception that no longer comes.
It now maps the second view, reads the first view's bytes through it, and
writes through the first view once the second is gone, which faults unless
its protection came back.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Only the lines this branch added lose their comments; the commits before
keep them, with the reasoning behind each change, for whoever digs into
that code later.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An address-based build maps every readable registered range. A heap
range past APS5_HOST_IMPORT_MIB (or refused by the driver) was copied by
every such build: about 3200 ranges, 670 MiB and 500 ms per build on the
story-mode load, which then stalled. Such ranges are now served by
persistent host-cached mirrors, as the main image is, and the load
reaches its next failure.
- a heap mirror keeps no shadow; it keeps a write-tracking generation
per 64 KiB block and a build copies only the blocks stamped since. The
generation is stored by the copy, so a build that throws before it
leaves no block marked current with stale bytes
- the build gathers its heap mirrors, sorts them and collects each run
of adjacent ranges once (a collect costs about 4 us whatever its size;
~3000 mirrors took 16 ms per build, now about 3 ms)
- writable ranges are mirrored too: each build keeps the bytes its merged
written ranges held at upload and write-back stores only what the GPU
changed from them, so a CPU store made meanwhile stays; recorded work
writing a range completes before a refresh reads it
- the mirrors are limited by APS5_HEAP_MIRROR_MIB (24 GiB by default); a
mirror past it, or one whose buffer the driver refuses, stops the
process. Heap mirrors are not given to descriptor sub-ranges, image
mirror serials or reusable direct regions
- past APS5_ADDRESS_COPY_MAX_MIB (64 MiB by default) of committed bytes
still copied, a build stops the process, naming the largest ranges and
why each is copied (unreadable pages, an image mirror the driver
refused, a range outside the write-watched arena, mirrors disabled)
- a direct memory page mapped at several addresses is read-only in every
view while its range stays writable: copies, descriptor regions and
mirrors take every readable page, write-back stores the writable ones
and fails on a GPU change inside a read-only page instead of dropping it
- a store through the BDA table into a mirrored or copied range faults
as before (only writable ranges imported in place are writable there);
the fault now names the table range and that rule
- the BDA resource tests run with a storage range limit that holds the
fault buffer and cover a mirror's fill, reuse, per-block refill, an
interrupted refresh, a descriptor store beside a concurrent CPU store,
and the copy limit
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Both suites stopped at their first stale expectation, so nothing after
it ran; the BDA device tests did not link.
- the BDA device tests define the one recorder entry Resources.cpp
reaches (no recorder) and fail loudly on the others
- Buffer::Invalidate refuses memory that is not host mapped again (lost
in 8a69fef); the device tests expect it for a device-local buffer
- APS5_PIN_WAIT_MS (60000 by default, unchanged) bounds the wait before
a mutation of a leased range is refused, and the refusal names it; the
graphics tests set 200 ms, as they expect about a dozen refusals
- the expectations follow the behaviour the code chose since: a buffer's
four-DWORD V# is refused as a T#, a sampler exceeds the mock's zero
sampler slots, a V# at unmapped memory binds its committed pages only,
a rect-list fragment input without a vertex export reads as zero,
detiled rows span the padded block width, mip ranges are checked in
address order, block-compressed and 128/129/132 formats use render
target tiling, an XOR swizzle is refused only over a base that is not
64 KiB aligned, DCC and partial mip chain views decode, a cube reads as
a 2D array, the sampler fixture's max LOD fits the 4.8 field, a BDA
program with barriers is accepted, a tessellation control stage is
refused, a corrupt request fails on its signature and a newer one on
its version
- the DCC comment in the texture decoder no longer claims metadata
compression is refused
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A title libc from sce_module calls it from __cxa_throw/__cxa_rethrow when
no handler is found, right before std::terminate, with the thrown object,
0x400 (meaning unknown), the demangled type name and what() (or null).
The console keeps it for the core dump; there are no guest core dumps
here, so it is printed to stderr. It was the only import such a libc
needed beyond the existing libs.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
--spv saves <request>.spv in the working directory for spirv-val; the usage
line lists --asm and --mem too.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
APS5_WATCH_MEMORY takes <hex address>:<hex bytes> ranges separated by commas;
a snapshot holds them back to back, in order, and is kept when any changed.
Each range matches its own heap base above bit 36, and watching starts once
all are mapped.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The decoder puts an instruction's DPP fields on its source, and only a
destination carrying them has writeRawU32 keep the lanes the masks leave out
(and, without bound_ctrl, the lanes with no source lane). destinationOperand
copied them over, but no write used it, so every row was written: a wave64
scan adding the other row's total into the odd rows only (row_mask:0xa) added
it into every row, the prefix sums a key pass indexes primitives by came out
wrong, and the tree built from the keys held cycles its walkers looped on.
As in the Kyty recompiler (writes through DestinationOperand):
TranslateInstruction gives the destination its source's DPP fields once, and
a mac accumulator reads the destination without them (accumulatorOperand).
agc_dpp_write_tests checks a masked DPP add writes through DppUpdateU32.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- The loop guard's report names the shader (its code address when its plan
was built, now the translator's shader hash), and LoopGuardTripped() tells
whether any dispatch reported one.
- APS5_WATCH_MEMORY=<hex address>:<hex bytes> (with APS5_SYNC_DISPATCH=1)
keeps the last 64 contents of a range with the dispatch that left each, and
writes them to watch_<n>_<program>.bin when the loop guard first trips; the
address matches any heap base above bit 36.
- agc_shader_replay --mem prints the guest buffer V#s and which the shader
writes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A V# with records but a base address of 0 threw at bind time ("null shader
buffer descriptor address"), although a shader that never reaches that slot
works on hardware; an access through it would fault there, so a working
title does not make one.
Such a V# is specialized empty like one without records (every access out of
bounds) and binds the placeholder buffer; the draw cache's alias check skips
it as the build does. The tests expecting the old rejections are dropped.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
findSelectionMerge took the nearest common post-dominator of a selection's
targets, computed across the loop's back edge. When one arm only continues
(reaching that block in a later iteration) and the other target is shared
with an enclosing selection, the shared merge was split off the header, the
post-dominator stayed where it was, and splitting repeated until the budget
threw.
Inside a loop, an arm that reaches the post-dominator only past the continue
or merge block now leaves the selection by continuing, and the merge is the
other arm's target; after one split that is the header's own synthetic merge.
agc_structurizer_tests builds the smallest such graph; it hit the budget
before.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A view whose offset in its GPU owner is not a multiple of
minStorageBufferOffsetAlignment could not be bound, and an address-based
build (its registered heaps imported whole) put descriptor-bound buffers at
arbitrary offsets inside them, so such dispatches failed.
GuestBufferMemory::Descriptor now binds from the aligned offset below the
view and reports the difference; ShaderResources stores it, per guest buffer
element, into the push constant block at the shader's memory byte offsets
(RecompileResult::memoryOffsetDword), which the shader already adds to every
access. Every push constant path (dispatches, recorded and synchronous draws,
draw recipes) takes the patches; the assembling overload of
Pipeline::PushConstants is gone. A shader whose shader data is a buffer fails
when it would need one.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A dispatch sized in threads (USE_THREAD_DIMENSIONS) launches a partial last
workgroup on RDNA2, but the host rounds it up to whole groups, so the extra
threads ran: past the end of a node list they read past it and wrote over
live records.
Such dispatches now compile a separate variant (ShaderComputeStageInfo::
partialThreads, keyed only on whether it is set) whose entry EXEC excludes
threads at or past the requested size. The size reaches the shader as three
shader data dwords after the memory offsets (StageInputKind::
DispatchThreadLimit), is mixed into the dispatch cache key and the result
memo hash, and serialized in recompile requests (version 3). Whole-group
dispatches keep their variant.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A V# without records (all zero, say, for a slot the taken path never
uses) makes every access out of bounds on hardware: loads read zero or the
format's default, stores and atomics are dropped. The recompiler now
specializes such a buffer as empty, so every access through it is out of
bounds, and the driver binds a small per-device placeholder buffer to the
element instead of rejecting the V#. A V# with records at address zero
still throws.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A V# the SRT walker cannot compute (loaded from a descriptor heap at a
GPU offset, or built by the program) has no binding to hold it. Raw
dword loads and stores of 1-4 dwords through one now decode the V# in the
shader, apply the RDNA2 bounds rules (OOB_SELECT, stride, swizzle,
ADD_TID, format 0) and go through the BDA page table, as Kyty does.
Stores need Write permission, which only ranges that are a writable
allocation's host import get, so a store into a mirror or a copy faults
rather than being lost. The shader notes each written page in an
open-addressed set behind the fault record; once the work completed the
host marks those pages GPU-written, and an overflowing set throws.
Formatted, typed, sub-dword and atomic access through such a V#, and
their use outside compute shaders, still fail.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A sampled T# of a 32-bit integer format over a depth layout (a Z swizzle
mode) reads the raw bits of a depth plane, and a host cannot view a depth
image with an integer format. Such an image is specialized as float and
bound as the depth surface's float view: a fetch returns the same bits,
which the shader keeps as they are, and swizzle constants read as the
integers 0 and 1. Filtering is forced to point, as for integer formats.
The same T# over guest memory rather than a depth surface throws.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
EVENT_WRITE PIXEL_PIPE_STAT_DUMP (event 0x39) dumps the DB sample
counters. The recorder, once a title asks for them, keeps an occlusion
query open over each batch (precise when the device supports it) and adds
the result to a running count when the batch is reaped. A dump drains
recorded work like a label and writes the count in the PS5 layout: 16 DBs
16 bytes apart, begin and end counters interleaved, the count in the
first and bit 63 marking each ready. Kyty and SharpEmu write a fixed
"visible" result instead.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A depth target lives only in a GPU image (its guest surface is never
written), so a texture over its depth or stencil plane now samples that
image through a view of the plane's aspect: R32_SFLOAT for D32, R16_UNORM
for D16, R8_UINT for stencil, one level and slice at the surface's extent.
Other shapes, and storage access to a depth surface, throw. Depth images
get the sampled usage, and the barriers after a render pass and before a
dispatch include depth attachment writes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A title maps physical pages at a new address while the GPU still reads them
through the old one. Every view of such a page gets the same contents and
loses write access while the page is shared; the last view left gets its
protection back. A CPU write to a shared page faults, and views that differ
when one is unmapped (a GPU write through an import) throw, instead of the
views silently diverging.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
sceAgcQueueEndOfPipeActionPatchData is called with the packet and the new
64-bit label value only; reading a context id and a data selector from the
unused argument registers wrote garbage into the RELEASE_MEM, so fences
signalled with wrong values.
-KRzWekV120 is sceAgcDcbSetIndexSize with the per-instance object id flag
(VGT_INDEX_TYPE bit 14), as Kyty and SharpEmu build it. The no-op left the
previous index type in place, so 32-bit index buffers were read as 16-bit.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- NP: signed-out callbacks and reachability; owned add-on entitlements
from anyps5-entitlements.ini next to the executable (or the file
ANYPS5_ENTITLEMENTS names)
- web browser, message, player invitation and player selection dialogs
finish without a UI; Remote Play, IME keyboard, SharePlay, live
streaming and video recording lifecycles for a console without them
- app content temporary data mount, format and free space (download data
quota from param.json); content export, search and delete lifecycles
- pad output-only calls, system service notice-screen flags, RazorCpu
markers, ulobjmgr
- throwing stubs for the remaining imports, so missing behavior fails
loudly
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- AJM codec 0 (MP3) decodes with FFmpeg, prebuilt through the
ffmpeg-core submodule as in Kyty; sceAjmBatchJobDecode and the Run job;
the PCM encoding follows the job flags; other codecs throw
- AudioOut2 ports of 16-bit integer samples, and the ambisonics speaker
array decode for the reported layout
- the voice library for a console with no headset, with a frame size for
voice ports
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Depth/stencil: draws that test depth or stencil against a bound surface
render with a GPU-only depth/stencil attachment (DepthSurface), cleared
to DB_DEPTH_CLEAR/DB_STENCIL_CLEAR when made. Z test/write/function and
per face the stencil function, operations and masks (BACKFACE_ENABLE);
replacements by another value where Vulkan's single reference can carry
them. Clear and copy draws, add/sub other than 1, array or mip views
and MSAA throw, and texture reads of a surface's memory are refused.
Scaleform menus mask with the stencil (REPLACE 0, ADD_CLAMP, EQUAL);
their masked content was skipped before.
- Mipmapped color targets render through the resident image of the whole
chain with a view of the mip, so mips in the packed tail are drawn too;
CB_COLOR_VIEW's mip level is read from bits 26-29 (GFX10).
- Color: SNORM targets, UNORM16/SNORM16 exports, one-component formats
honouring COMP_SWAP (A8), 32_R/32_GR/32_AR exports, linear rows padded
to 256 bytes, BLEND_BYPASS.
- INDIRECT_BUFFER jumps are followed when copying a submission; thin 3D
textures in display and rotated XOR swizzles; only the bytes the GPU
changed are written back; resource registration.
- VideoOut: a flip stalls the GPU queue while the flip queue is full and
holds the submitter back.
- APS5_DUMP_FRAMES_EVERY dumps every k-th presented frame.
- The graphics test target builds again (missing sources, a hand-aligned
64 KiB buffer, stale expectations updated) and gains DepthStencilTests.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- packet sizes for the existing builders and the tessellation ring
config
- direct register writes and end-of-pipe action data, type and cache
patches
- GS/HS shader halves fused by merging their registers, after Kyty
- jump target patches; reserved jumps are allowed
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
libkernel:
- direct memory keeps its contents per physical page across unmap and
remap; a page mapped at two live addresses at once throws
- sceKernelDirectMemoryQuery answers from tracked allocations
- SCE protections read back as set, GPU and AMPR bits included
- APR prefix path resolve, file size and stat by id, positional reads,
fsync/pread/pwrite; directories open as descriptors on Windows
- sceKernelCheckReachability, getpeername, shutdown
- Dinkumware C11 threads (_Mtx_*, _Cnd_*, _Thrd_*) in the title libc
layout; any pthread stack size, rounded at thread creation
libc:
- unaddressed guest mappings go to the system-managed area from
0x2_0000_0000, leaving the application area to fixed mappings
- the process starts in /app0
- guest sscanf on Windows; a null %s prints as (null) as on FreeBSD
- localeconv, _FNan, _FDtest, _FExp, __udivti3, wcsncpy_s, aligned
operator new, _Throw_Cpp_error
Tests: direct memory following physical pages, guest formatting.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Per maintainer feedback: PNG encode/decode belongs together in a
future core/Decoder/Png shared by the relinker (icon loading) and
PRX layer, not a one-off libScePngEnc-only encoder. Reverts
libScePngEnc/Export.cpp to the upstream stub and removes the vendored
stb_image_write.h dependency, leaving ConvertKeycode, VoiceChat and
the PlayGo chunk-id fix.
Strip inline explanatory comments (comments are restricted to
technical-debt markers, #endif, and namespace-close trailers) from
HitLog.hpp, libSceConvertKeycode, libSceVoiceChat, libScePngEnc, and
the new hunk in libScePlayGo; add the missing #endif trailer comment
to HitLog.hpp's include guard. Rename the local helpers/params that
didn't match the naming convention: log_soft -> logSoft and
Readable -> readable (private free functions, camelCase), and
snake_case arguments (user_id, request_id, memory_address,
memory_size, output_info) to camelCase. NID export functions and
pre-existing upstream code (libScePlayGo's existing snake_case
parameters, PngEnc's vendored stb_image_write.h) are left untouched.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Bring the pad-gamepad-haptics diff in line with docs/dev/CONVENTIONS.md:
strip explanatory/rationale comments (struct layouts, algorithm notes,
rewired-NID rationale) down to code only, and rename the anonymous-
namespace helpers in PadState.cpp (Normalize/Fuse/EncodeZones/MaxOf/
ScaleStrength) to camelCase to match upstream's free-function style.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Was a NotImplemented stub that returned an empty/undefined result.
For a package where every declared chunk is already local, the
installed-chunk set is identical to the full chunk set already
computed by ValidateChunks()/ValidChunks(), so this simply delegates
to the existing scePlayGoGetChunkId(). Driven by the title's own
playgo-chunkdefs.xml, not any hardcoded per-title chunk count.
Replaces the 4-stub placeholder with a working create/delete/encode
path backed by stb_image_write. The encode parameter block layout is
inferred by analogy with the decoder's and validated strictly
(dimensions, pitch, buffer sizes, readability of both the source and
destination buffers) before any pixel is touched; anything that does
not fit is rejected rather than guessed at. Handles RGBA and BGRA
source pixel formats.
Init/terminate/handler/event exports are real no-ops. Session and
channel request exports return SCE_VOICE_CHAT error SIGNED_OUT, since
voice chat sessions cannot be established without a network backend.
Matches the offline-stub pattern already used by other online-service
PRX modules in this project.
sceConvertKeycodeGetImeKeyboardType is implemented for real (reports
keyboard type 0 for a valid user id). sceConvertKeycodeGetVirtualKeycode
has an unconfirmed ABI, so it only logs its raw arguments and reports
failure rather than guessing a pointer layout.
Renames template parameters to the TKey-style the conventions doc
requires (TValue, TFunction), removes the extern "C" close comment
(not one of the two allowed structural exceptions), and replaces
the magic error/flag numbers left after the previous comment
cleanup with the existing SCE_KERNEL_ERROR_* constants and a named
RTLD_NOW constant so the code documents itself.
Comments in this codebase may only mark technical debt (human-added
only), the end of #endif, and the end of a namespace, per
docs/dev/CONVENTIONS.md. Remove the inline rationale comments added in
the AGC PM4 opcode and shader recompiler robustness commits; the code
itself, the commit history, and the PR description now carry that
context instead.
Notably, Command::WriteMemSemaphore takes the corrected 4-argument
form (address, waitForMailbox, signalType, operation): an earlier
revision of this helper used a different, incompatible argument
order. sceAgc*MemSemaphore callers derive waitForMailbox/signalType
from the low two bits of clientCode, and operation from action
(0 = signal, 1 = wait). This ABI note previously lived as an inline
comment; it is recorded here instead per the no-comments convention.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Comments in this codebase may only mark technical debt (per
docs/dev/CONVENTIONS.md), plus the #endif and namespace-close
structural exceptions. Removes the descriptive comments added on
this branch across PreciseWait.hpp, FormattingWide.cpp, the
direct-memory pool query/free-run plumbing, and the module loader
wiring, keeping the two allowed structural markers intact.
sceSystemServiceGetHdrToneMapLuminance was NotImplemented. Titles read
it at startup to set up their HDR tone mapping.
The presenter always outputs through a B8G8R8A8 sRGB-nonlinear swapchain,
so the display range the title has to map into is SDR: the maximum and
full-frame maximum luminance are the 100 cd/m2 SDR reference white and
the minimum is 0. A null output pointer returns
SYSTEM_SERVICE_ERROR_PARAMETER like the other getters here.
ShaderMemory captures guest memory per page, so a 32-byte table entry that straddles a page
boundary is held by two adjacent regions. The bindless test's coverage check required one region
to hold the whole entry, so it failed whenever the stack placed an entry at page offset 4080
(about one run in 75). The check now accepts adjacent regions that together cover the range.
An MRT export to a slot past the draw's color attachments (outside
CB_TARGET_MASK & CB_SHADER_MASK, e.g. MRT1 with only slot 0 enabled) is
dropped by the color backend. Vulkan discards a fragment output without
an attachment the same way, but validation rejected the draw ("fragment
shader must export float4 colors at locations below the attachment
count"). Such outputs are now left out of the written locations, and
only the exports that reach an attachment must be float4.
sceVideoOutOpen threw for any non-null param. PS5 titles pass a 16-byte
open param whose first word is its size, so they could not open a port.
A param whose size word is 16 and whose other three words are zero
requests nothing beyond a null param and is accepted. Any other size,
or any non-zero option word, still throws.
scePthreadMutexattrSetprotocol threw for SCE_PTHREAD_PRIO_INHERIT, so a
title creating its mutexes with priority inheritance stopped at the
first one.
Guest thread priorities are recorded (scePthreadSetprio/Getprio) but
never applied to host scheduling, so there is no priority for a waiter
to lend to the owner: an inheriting mutex locks, unlocks and reports
errors exactly like a PRIO_NONE one here, and the protocol is accepted.
The POSIX pthread_mutexattr_setprotocol wrapper already accepts it.
Priority protection (PRIO_PROTECT, with its ceilings) and unknown
protocols still throw.
sceAgcDriverAddEqEvent and sceAgcDriverDeleteEqEvent were NotImplemented,
so a title that waits on its equeue for the GPU to reach the end of a
command buffer could never be woken.
AddEqEvent now registers a graphics-core event (filter -14, ident = the
given id, EV_CLEAR, data counting the interrupts since the last wait) on
the kernel equeue and remembers the registration; DeleteEqEvent removes
both. An invalid equeue or deleting an event that is not registered
throws.
The driver delivers the interrupt when it executes a RELEASE_MEM whose
INT_SEL is non-zero. Such a packet is not deferred as a GPU label: the
recorded work before it is drained, its memory write (if any) is done,
and then the event registered with the id of the issuing queue is
triggered (0 for the graphics ring, the ACB queue id for compute), which
matches how titles derive their event ids from the ring they submit on.
Vertex buffer formats 50-55 (2_10_10_10 UNORM, SNORM, USCALED, SSCALED, UINT, SINT: X in the low
10 bits, the 2-bit W on top) map to Vulkan's A2B10G10R10 packings, and format 36 (10_11_11_FLOAT:
X in the low 11 bits) to B10G11R11_UFLOAT, the same mapping TextureFormat uses for textures.
11_11_10_FLOAT (43), whose 10-bit X has no Vulkan packing, stays rejected.
DISPATCH_INITIATOR bit 13 (TUNNEL_ENABLE) asks the SPI to launch the dispatch's waves ahead of
other work. It is a scheduling priority hint with no effect on the results, so direct and indirect
dispatches accept it like the other ignored modifier bits.
sce::Json::Value::getBoolean, getInteger, getUInteger and getReal return const references
(const bool&, const long&, const unsigned long&, const double&), so the guest reads the value
through the returned pointer. A value-returning implementation made callers dereference the value
itself. Cross-type conversions keep main's range rules and are stored on the node so the reference
stays valid.
Value::referValue(const String&) looks a member up without creating it: it returns null for a
missing key or a value that is not an object instead of inserting an entry or throwing.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ButHENCbXXt8h4EZuWUabJ
s_getpc_b64 produced the next instruction's offset from the start of the
shader, so code that addresses data stored behind itself built V#s at a
tiny address. Astro Bot's video-frame NV12->RGB pass draws its quad with
an NGG shader that fetches the four vertices from after its own code
(s_getpc_b64; s_add_u32 0x98; s_addc_u32) - the buffer resolved to 0xf0,
every vertex read as zero, the quad never rasterized and the PlayStation
Studios logo video stayed black.
The result is now GetShaderBase + offset. The resource walk already
evaluates GetShaderBase per request from the code address, so the V#
names the real data and the same code at another address still shares
its compiled variant.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ButHENCbXXt8h4EZuWUabJ
Feat/provide release
Added a release workflow for v* tags: build Windows and Linux, run tests, and publish only if both platforms are successful. The release contains PRX archives, relinker executables, and documentation from docs/user. The build cache is reused.
- `prx-windows-v0.1.0.zip`
- `prx-windows-v0.1.0.tar.gz`
- `prx-linux-v0.1.0.zip`
- `prx-linux-v0.1.0.tar.gz`
- `relinker-v0.1.0.exe`
- `relinker-v0.1.0`
- `COMPATIBILITY.md`
- `INPUT_MAPPING.md`
fix(shader): support byte permutation and fix compiler lifetime bugs
Adds `V_PERM_B32` byte selection and fixes two existing bugs exposed while testing it: IR equality could merge buffer reads with different metadata, and concurrent shader compilation could crash during Windows thread-local destruction.
- Include instruction flags when comparing IR values so selections between different buffer offsets survive constant folding.
- Decode RDNA2 opcode `0x344` and translate all byte selectors through existing integer IR and the SPIR-V backend, including sign replication, zero/ones fill, and overlapping destinations.
- Reuse the existing `HostThreadLocal` helper for six destructible compiler scratch objects. Add async worker/destructor checks to the existing lifetime test. Scratch storage remains reusable.
feat(libSceMouse): implement stateful mouse API exports
Replace the libSceMouse stubs with an implementation that follows AnyPS5’s existing NID-based library integration. Mouse input comes from the host SDL event loop; this change does not add memory hooks or direct access to console HID devices.
Manage the mouse handle, button state, timestamps, and a thread-safe, 64-event history in src/mouse_impl.cpp. Reads are non-blocking.
Forward relative motion, supported buttons, vertical scrolling, and horizontal scrolling from libSceVideoOut’s SDL event loop.
Release pressed buttons when the window loses focus without reporting a hardware disconnection.
PS5 grew Ngs2WaveformBlock's data_offset/data_size pair from 32-bit to
64-bit fields (40-byte record vs. the 32-byte PS4 layout). Standalone
correctness fix, unrelated to and non-conflicting with the pad work in
the preceding commits.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Reconcile our SDL gamepad motion/haptics work with upstream's
configurable keyboard/mouse binding feature (PadInput now built around
Pad::LoadInputMapping() and a std::vector<Pad::InputBinding>). Upstream's
openFirstAvailableController()/openController(deviceIndex) flow and
HandleEvent/Update/publish logic for keyboard, mouse, and wheel
bindings are kept as-is (including APS5_NO_PAD_INPUT handling); the
sensor-enabling and host-haptics steps are grafted on as additional
work done once a controller is open:
- openController(deviceIndex) now also calls enableSensors() and
marks a re-apply of the current guest output request pending.
- New sampleController()/applyOutput()/enableSensors() bring in real
gamepad sampling, motion sensor reads, DualSense touchpad finger
tracking, and pushing rumble/light bar/adaptive trigger state out via
SDL_GameControllerRumble/SetLED/SendEffect. sampleController()'s
button list and trigger/stick scaling are an exact copy of the
button/trigger/stick reading that used to be inlined in publish()
under the SDL_GameControllerGetAttached check (no deadzone added,
no extra button remapped) -- only the motion, touchpad, and
device-kind sampling on top of it are new.
- Update() now also samples the controller and applies pending output
every tick, in addition to upstream's SDL_GameControllerUpdate() call
and its keyboard/mouse/wheel timing logic.
- publish() seeds PadInputState from the sampled gamepad state first
(buttons/sticks/analog triggers/motion/touch/device kind), then
layers upstream's keyboard/mouse binding loop on top exactly as
upstream had it, so a bound key still overrides the gamepad the same
way it did before this merge. Upstream's L2/R2 button-flag derivation
is preserved, just computed once at the end from whichever value
(gamepad or a keyboard/mouse override) ends up in analogButtonsL2/R2.
- The background-events SDL hint is now set unconditionally (previously
only inside the "not yet initialized" branch), since upstream's own
VideoOutDriver already brings up SDL_INIT_GAMECONTROLLER before
PadInput is constructed, which meant the hint would never run.
No changes were needed in VideoOutDriver.cpp: PadInput lazily
initializes SDL_INIT_GAMECONTROLLER itself in
openFirstAvailableController() (already a no-op if the subsystem is up),
and the class's public interface (default-constructible, HandleEvent/
Update) is unchanged, so upstream's existing `PadInput padInput;` /
HandleEvent / Update call sites keep working without modification.
VideoOutDriver.cpp's own independent flip-queue/vblank-telemetry rework
was left untouched as out of scope.
Confidence: high for the keyboard/mouse binding path (untouched) and
for the gamepad button/stick/trigger path (byte-for-byte copy of the
pre-existing mapping); the new motion/haptics/touchpad code is novel
and builds/links cleanly but has not been run against real hardware.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Replace NotImplemented stubs with real implementations for
scePadGetInfo, scePadDeviceClassGetExtendedInformation/ParseData,
scePadGetExtControllerInformation, scePadSetLightBar,
scePadResetLightBar, scePadResetOrientation,
scePadSetMotionSensorState, scePadGetTriggerEffectState,
scePadSetProcessPrivilege, and scePadSetParticularMode, wiring them to
the new Pad:: output/orientation API. None of these NIDs are touched
by upstream's existing keyboard/mouse binding work, so this is a
clean additive change.
scePadSetVibration, scePadSetVibrationMode, and scePadSetTriggerEffect
are also given real implementations here, even though they were not
named in the audit's NID list: they are the only guest entry points
for the Pad::SetVibration/SetVibrationMode/SetTriggerCommand plumbing
added in the previous commit, so leaving them NotImplemented would
make the rumble/adaptive-trigger machinery unreachable from any title.
Every other previously-NotImplemented NID in this file (scePadGetHandle,
scePadSetAngularVelocityDeadbandState, scePadSetTiltCorrectionState,
scePadSetVibrationTriggerEffectWeakWhileEmbeddedMicInUse) is left
exactly as upstream had it; scePadOpen_nid_postfix, scePadRead_nid_postfix,
and scePadReadState are untouched (upstream's APS5_INVALID_ARG_EX
throw-based error handling is kept as-is, not replaced with plain
error-code returns).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Add PadTouchPoint, motion-sensor fields, and a Mahony gyro/accel
orientation filter to PadInputState/PadState; add PadOutputState and
PadTriggerRequest plus Pad::SetVibration/SetVibrationMode/SetLightBar/
SetTriggerCommand/ResetOrientation/SetMotionEnabled and
PadFetchOutput_nid_postfix for pushing rumble, light bar, and adaptive
trigger requests out to the host pad. PadInfo/device-type constants
needed by the extended pad info NIDs are added to Pad.hpp.
Upstream's own PadInputState addition (analogButtonsL2/R2) is kept and
the new motion/touch fields are layered on top rather than replacing
it. Reported acceleration is converted from the internal m/s^2 fusion
scale back to g (rest = 1.0 on the "up" axis), matching upstream's
existing acceleration_y = 1.0f convention for a pad without sensors.
PadPublishInput_nid_postfix keeps upstream's change-detection (skip
the update, and the reported timestamp, when nothing changed), extended
to cover the new motion/touch/deviceKind fields so a pad with live
sensors still republishes continuously. Pad::ReadState still throws
when called before scePadInit, as upstream did.
The pad_dump.txt debug logger and an unreferenced mouse-emulated
touchpad helper are intentionally not ported: both were dead code,
never invoked, in the source they came from.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Replace the stub AvPlayer export set with a general-purpose player state
machine covering the full API surface: sceAvPlayerInit/InitEx/PostInit,
AddSource/AddSourceEx, Start/StartEx, Pause/Resume/Stop/Close, IsActive,
CurrentTime, JumpToTime, SetLooping, SetAvSyncMode, SetTrickSpeed,
SetAvailableBandwidth, StreamCount/EnableStream/DisableStream/ChangeStream/
GetStreamInfo(Ex), and GetVideoData(Ex)/GetAudioData.
No real decoder is wired up: the player tracks lifecycle and timing state
and serves a fixed-length blank clip on a wall-clock media clock, firing
the READY/PLAY/PAUSE/STOP event callbacks a title expects from a real
playback session. This is enough for titles that gate progression on
AvPlayer's polling/event surface rather than on decoded frame content.
The non-native libSceAvPlayer/Export.cpp now forwards to the native
implementation via #include rather than carrying its own duplicate stub
definitions, consistent with how other libSceX/libSceX.native pairs in
this tree share one implementation.
Replace the unimplemented stubs with a working NONE -> INITIALIZED ->
RUNNING -> FINISHED state machine for the message dialog PRX. Open()
best-effort parses the SceMsgDialogParam layout to pick a sensible
default button (auto-focus-no variants answer No, everything else
answers Yes/OK), then auto-finishes the dialog after a couple of status
polls so a title that waits on a dialog for user input never blocks
forever. Progress-bar mode is instead closed by the title itself via
sceMsgDialogClose, with a time cap as a safety net. GetResult now fills
in a real SceMsgDialogResult (mode/result/buttonId) instead of leaving
the caller's buffer untouched.
Fills in guest-facing sceAgc* entry points across Acb/Cb/DcbDraw/DcbFlow/DcbState/Misc
that were still stubbed with NotImplemented_nid_no_patch on current upstream, one layer
below upstream's Recorder rearchitecture:
- Command/Control.{hpp,cpp} (new): WriteJump, WriteRewind, WritePredication,
WriteMemSemaphore helpers shared by the Acb/Dcb entry points below.
- Command/Memory.{hpp,cpp}: WriteCopyData, WriteAtomicMem helpers.
- Acb/Control.cpp: Jump/JumpGetSize, Rewind/RewindGetSize.
- Acb/Dispatch.cpp: DispatchIndirectGetSize.
- Acb/Memory.cpp: AcquireMemGetSize, CopyData(+Size), AtomicMem(+Size),
AtomicGdsGetSize, PrimeUtcl2(+Size).
- Acb/Sync.cpp: CondExec(+Size), WaitOnAddressGetSize, EventWriteGetSize,
QueueEndOfShaderActionGetSize, MemSemaphore.
- Cb/Dispatch.cpp: DispatchGetSize only (sceAgcCbDispatch itself left untouched --
upstream's modifier mask 0xa038u|0x41u there is correct as-is).
- DcbDraw/DrawIndexed.cpp: DrawIndexMultiInstanced(+GetSize), still unimplemented
even after upstream's own indexed-draw work.
- DcbFlow/Control.cpp: Jump, Rewind(+Size), and a real WaitUntilSafeForRendering that
emits AgcDriver::RenderingWaitPacketHeader (recognized by the executor's fence wait
in Driver.cpp) instead of upstream's plain-NOP stub, which the executor does not
special-case.
- DcbFlow/Memory.cpp: AcquireMemGetSize, CopyData(+Size), DmaDataGetSize,
AtomicMem(+Size), AtomicGdsGetSize, WriteDataGetSize.
- DcbFlow/Sync.cpp: CondExec(+Size), WaitOnAddressGetSize,
StallCommandBufferParserGetSize, MemSemaphore.
- DcbState/Predication.cpp: SetPredication only (the file's 3 GetSize functions are
left as upstream's diagnostic stubs, not real fixes).
- Misc/PacketInfo.cpp: sceAgcDcbGetSystemSoftwareVersion.
ABI correction: Command::WriteMemSemaphore takes the corrected 4-argument form
(address, waitForMailbox, signalType, operation). The Acb/DcbFlow sceAgc*MemSemaphore
entry points still expose the older (action, clientCode, address) guest signature;
their bodies now decode `action` into the signal/wait operation and the low two bits
of `clientCode` into signalType/waitForMailbox before calling the corrected helper.
Not ported (already superseded or out of scope per review): WriteMarker/WriteCustomNop/
WriteEventWrite/WriteCondExec/WriteDispatchIndirectAddress (duplicate upstream's
existing Marker/EventWrite/DispatchIndirect logic), Acb DmaData/DmaDataGetSize/
WriteData/EventWrite (already implemented upstream), DcbFlow EventWrite(+Size)
(upstream's version handles the 8-byte occlusion-address case more completely),
DcbDraw's other DrawIndex* entry points (already implemented upstream),
Misc/Trinity.cpp, Patch/WriteData.cpp, DcbState/Marker.cpp (all superseded by
upstream equivalents).
- DirectMemory: track each allocated block's type and extent in the
physical pool (DirectMemoryBlock), splitting the record on a partial
free, and expose DirectMemoryQueryBlock/DirectMemoryFreeRun. Wires
sceKernelDirectMemoryQuery to answer with the real allocated range
and type instead of a hardcoded one-page/type-3 guess, and
sceKernelAvailableDirectMemorySize to report the actual free run
instead of the whole remaining aperture. DirectMemory.cpp's mapping
path already tolerates MAP_FIXED overlap into a registered range and
already has honor-then-fallback address-hint handling and an
ignored-flags mask, so it is unchanged here.
- MemoryPoolExport: implement sceKernelMemoryPoolBatch/Commit/Decommit/
Expand/GetBlockStats/Reserve (previously all dead stubs) using the
existing DoMprotect/DirectMemoryAlloc/DoReserveVirtual primitives and
a small pool-state block counter.
- Module: wire sceKernelDlsym/sceKernelLoadStartModule/
sceKernelStopUnloadModule to the existing host-module loader
(dlopen_nid_postfix/dlsym_nid_postfix/dlclose_nid_postfix), replacing
dead stubs. sceKernelGetModuleInfoForUnwind/FromAddr are unrelated
and left as-is.
- Add FormattingWide.cpp implementing vswprintf_nid_postfix and
wprintf_nid_postfix, the only wide-char printf-family functions
upstream had left as unimplemented stubs (Formatting.cpp's checked
and unchecked narrow printf/scanf families are unaffected). Removes
the dead vswprintf_nid_postfix stub from Export.cpp.
- Add PreciseWait.hpp: std::condition_variable::wait_for cannot return
in under about one system tick on this MinGW toolchain regardless of
the requested budget, even with NtSetTimerResolution; PreciseSleepUs
uses a high-resolution waitable timer instead (~0.5ms vs ~15.6ms).
Header-only for now: its guest-side callers (Equeue/EventFlag/
Semaphore/AgcDriver wait loops) are out of scope for this change, so
it is not wired into them here.
Rework the local SaveData implementation into a general-purpose, title-agnostic
backend used by both the native library and the standard libSceSaveData path:
- Directory aliasing: long save directory names are hashed into short mount
point aliases (persisted to disk) so they fit the SDK's fixed-size mount
point buffer, with the aliases reversed on directory search.
- Wildcard directory-name search (%/_ patterns) with sorting and optional
reverse order, matching the DirNameSearch contract.
- Save-data "memory" slots: small per-user, per-slot blobs the title can
set up, read and write without mounting a directory, backed by files under
the save root with a companion parameter blob, size and range validation
on every access, and a dirty flag consulted on commit.
- Async-flavored operations (backup, commit, memory sync) that queue
SaveDataEvent records consumed through GetEventResult and can be bound to
kernel event flags, plus transaction-resource and cancel/abort bookkeeping.
- Atomic file writes (temp file + rename) so a mid-write crash never leaves a
torn save on disk, and corrected/duplicated SDK error code constants.
- Local storage app-status get/set/delete and transferring-mount support for
PS4-to-PS5 style save transfers.
The native library keeps its own lighter-weight mount/memory implementation
(short "/_sm/<slot>" mount point aliases via the path-alias table) while
gaining the same per-user memory-slot separation, atomic writes and bounds
checking; the two implementations were merged by hand where upstream had
independently touched the native Export.cpp in the same area (backup/event
queue, short mount points) to keep both sets of improvements.
None of this is game-specific: it is a general local save-data backend that
works for any title and tolerates any user id.
libSceNet: replace the always-fail stubs with a real offline network
stack. Sockets, epoll instances, memory pools and resolvers are tracked
in proper registries with create/destroy lifecycles; bind/listen/accept/
connect/send/recv/getsockopt/setsockopt/getsockname behave the way they
would on a console with no link up (bind and listen succeed locally,
connect/send fail with the errno a routeless host would give, blocking
calls such as accept/recv/epoll_wait return on close, abort or their
timeout). Infinite ("wait forever") timeouts are serviced in bounded
slices so a caller can never deadlock the process. Errno values match
the FreeBSD numbering the guest expects through sceNetErrnoLoc. Restored
sceNetGetsockopt and sceNetResolverStartAton (present upstream) using
the same registry-backed conventions as the rest of the rewrite.
libSceRudp: companion change giving the reliable-UDP library a genuine
context registry (init/create/bind/set-option/get-status) with
consistent error codes; connection attempts consistently fail since no
peer can ever be reached offline.
Forward relative motion, supported button transitions, and horizontal and vertical scrolling from the existing SDL event loop. Reset pressed buttons on focus loss without reporting a device disconnect, and track window close and refocus transitions.
Link libSceVideoOut to the mouse library using the existing Pad integration pattern. Add targeted coverage for API errors, event mapping, focus changes, history overflow, and reopening.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Keep the existing Export.cpp entry point and System V ABI while moving mouse state into the library implementation.`n`nTrack initialization, a single handle, button state, timestamps, and a bounded non-blocking event queue. Define and assert the guest MouseData layout and expose an input publisher for the host backend.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Upstream merged #25 and #26. Resolve DirectMemory.hpp and Equeue.hpp
by keeping this branch's side: the local error constants #26 fixed are
replaced by KernelErrors.hpp here.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018emyZ4Rk8yoSJvxTFBe4DL
fix(kernel,audioout,relinker): thread/mutex correctness fixes and --windows-gui
### libkernel (threads, mutexes, condition variables)
- **Deadlock in `scePthreadCondTimedwait` (normal/error-check mutexes):** `_owner` was not restored after the wait. If another thread locked and unlocked the mutex during the wait, the waiter woke up owning the mutex while `_owner` was empty. Its next `scePthreadMutexUnlock` returned `EPERM`, leaving the mutex locked forever (`lock → timedwait → unlock` pattern).
- **Wrong timeout code:** `SCE_KERNEL_ERROR_ETIMEDOUT` in `Cond.cpp` was `0x80020062`; it is `0x8002003C` (FreeBSD `ETIMEDOUT` = 60, matching `Semaphore.hpp`).
- **`scePthreadSelf()`** returned `nullptr` on Linux, and on both platforms for threads not created by `scePthreadCreate` (including the main thread). Such threads now get a lazily adopted, non-joinable handle (`scePthreadJoin`/`Detach` on it return `EINVAL`).
- **Linux `scePthreadExit`** skipped `FinishThread`, so `scePthreadJoin` got a garbage return value. Cleanup now runs from an RAII guard, so it survives glibc forced unwinding.
- **Linux detached threads** were never freed. They now use the same reference count as on Windows.
- **Recursive mutex unlock** by a non-owner, or with a zero count, was UB (`std::recursive_timed_mutex::unlock`). It now returns `SCE_KERNEL_ERROR_EPERM`, and `_owner`/`_count` are also saved and restored around a recursive cond wait.
- **`sceKernelLseek`** returned `int` instead of `off_t`; offsets above `INT_MAX` threw.
- **`sceKernelDeleteSema`** implemented: waiters are woken with `SCE_KERNEL_ERROR_EACCES` and the object is freed once they leave.
- `sceAudioOutOpen` accepted `freq == 0` / `len == 0`; the frequency was later used as a divisor. It now returns `SCE_AUDIO_OUT_ERROR_INVALID_SAMPLE_FREQ` / `INVALID_SIZE`.
On Linux scePthreadExit called pthread_exit, whose forced unwind runs
the personality routine of every guest frame. Those resolve to
libc.prx's __gxx_personality_v0, which cannot read libgcc's unwind
context and aborts, so guest_thread_self crashed on Linux.
Record a jump target in the thread start routine and longjmp back to it
from scePthreadExit instead. Like _endthreadex on Windows, this skips
the guest frames without unwinding them; the start routine still
releases the thread normally. Threads not created by scePthreadCreate
keep the pthread_exit fallback.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018emyZ4Rk8yoSJvxTFBe4DL
Bring in the resolved#25 branch, which already carries upstream main
including boykopovar/AnyPS5#10, and re-apply the KernelErrors.hpp
refactor onto the rewritten files:
- Equeue: drop the local EQUEUE_ERROR_* constants and use the shared
SCE_KERNEL_ERROR_* names.
- Pthread Attr/Thread: drop local error constants and include
KernelErrors.hpp.
- Pthread Cond/Mutex: take upstream; they no longer define local
SCE_KERNEL_ERROR_* constants.
- Semaphore: drop KERNEL_SEMA_ERROR_* in favour of KernelErrors.hpp.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018emyZ4Rk8yoSJvxTFBe4DL
Resolve the conflict with boykopovar/AnyPS5#10 in Pthread/src/Mutex.cpp
by taking upstream: its rewrite already returns EDEADLK as 0x8002000B.
The equeue and direct memory error code fixes are unaffected.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018emyZ4Rk8yoSJvxTFBe4DL
Resolve conflicts with boykopovar/AnyPS5#10 (sce module loading) and
later upstream changes.
- Pthread Cond/Mutex: take upstream. It already releases mutex
ownership across condition waits, returns ETIMEDOUT 0x8002003C, and
rejects unlocks from non-owners for every mutex type.
- Pthread Thread: keep upstream's lifecycle, Windows adoption and job
affinity; re-apply the POSIX fixes on top: reference-counted
release on join/detach/exit, self-join rejection on both platforms,
and scePthreadSelf adoption for threads not created by
scePthreadCreate.
- Semaphore: keep upstream's TimedWait::Condition and wait tracing;
re-apply sceKernelDeleteSema waking waiters with EACCES.
- Relinker: keep --windows-gui alongside upstream's --skip-sce-module,
trampoline-aware Patch signature and new Python tests.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018emyZ4Rk8yoSJvxTFBe4DL
feat(fiber): implement fibers on linux
The state machine, the cross-thread resume handling and the entry trampoline are now shared between platforms. Only the context switch differs:
- `Aps5FiberSwitchStack` saves the SysV callee-saved set (`rbp rbx r12–r15`, MXCSR and the x87 control word) instead of the Win64 set.
- `Aps5FiberTrampoline` passes the fiber in `rdi`.
- There is no TIB to update, so `CurrentBounds`/`SetBounds` do nothing on Linux.
fix(agc): keep BGRA color targets resident between draws
BGRA color targets fail the exact guest-texture-format lookup and fall back to a synchronous framebuffer round-trip for every draw. This keeps them resident using compatible RGBA storage with the original BGRA attachment view. Presentation checks the actual display channel order, attachment views request only attachment usage, and host-write barriers include the host stage.
This follows the existing linked PRX/Vulkan path. It adds no interpreter, separate runtime process, or new shader compilation path.
feat(agc): ACB markers, index buffer unbinding and address in errors
- The DCB marker helpers move from an anonymous namespace in `DcbState/src/Marker.cpp` to `Agc::Marker::Push`/`Pop` (declared in `Marker.hpp`). The ACB entry points use the same helpers, so ACB and DCB markers produce the same custom NOP packets. `SetMarker` is a push followed by a pop, and returns the push packet, as on the DCB. The color is ignored on both, as before.
- `sceAgcDcbSetIndexBuffer` emits the packet with address 0 instead of rejecting it. A non-null address still has to be 2-byte aligned.
- `Agc::Command::CheckAddress` includes the rejected address in its message.
feat(agc): DMA_DATA cache policy hints and GDS source/destination
- **Cache policy:** the source (bits 13–14) and destination (bits 25–26) cache-policy fields of `DMA_DATA` dword 1 are accepted. They're cache hints with no effect on the copied data. The remaining reserved bits are still rejected.
- **GDS storage:** GDS is modelled as one 64 KiB, zero-initialised store shared by the whole device, behind a mutex.
- **GDS source/destination:** select `1` reads from or writes to that store:
- the validator requires the high address dword to be 0 and the range to fit inside the 64 KiB;
- `Execute` copies between memory, immediate data and GDS in any combination;
- `ResolveStore` returns nothing for a GDS destination, since there's no guest memory to write, and for a GDS source it resolves the bytes from the store.
- Register and prefetch destinations are still rejected.
- Nothing is faked for shaders: a shader that uses GDS still fails validation (unsupported descriptor role).
fix(agc): reject primitive restart only for indexed draws
- `DecodeState` still reads `0x24b` (so it stays in the recorded draw-key registers) but no longer rejects on it.
- `DrawRejection` takes an `indexed` flag, and reports restart only for indexed draws.
- The driver's draw path rejects an indexed draw with restart enabled before the precheck, so indexed draws with restart are still refused when the precheck is off. Restart itself is still not implemented.
fix(agc): keep a replaced Vulkan device alive
In the presenter path, after `PrepareForReplacement()` (which flushes cached textures, publishes shadows and waits for idle), the old device is kept in a function-local static list instead of being released. Its child objects stay valid for as long as anything still refers to them. The cost is one idle device for the life of the process; the replacement happens once, at the first flip.
feat(json2): implement sce::Json values, strings, arrays, objects, parser and null-access callback
- **Layouts:** `String`, `Array`, `Object` and `Value` are pointer-sized handles to host-side storage. The title stores `String`/`Array`/`Object` at an 8-byte stride and `Value` in 0x20-byte slots, so none of them can be bigger. The pair an `Object::iterator` dereferences to has its key at +0x00 and its `Value` at +0x10, which the title reads directly. Array and object iterators are 8 bytes.
- **Parser:** a strict RFC 8259 parser.
- Numbers: integers that fit `int64` become `Integer`, larger non-negative ones `UInteger`, and everything else `Real`.
- Strings: `\u` escapes, including surrogate pairs, are decoded to UTF-8.
- Errors: on any error `parse` returns a negative code (`0x80920101`) and leaves the target value untouched.
- **Serialisation:** compact output. Strings are escaped; reals use `%.17g`, and a non-finite real throws.
- **Null access:** a typed getter on a value of another type, a missing key or an out-of-range index goes through the null-access callback. The callback's result is used when its type matches (any type for `operator[]`). Otherwise a static default value of the requested type is returned. `terminate` clears the callback.
- **Integer getters:** `getInteger`/`getUInteger`/`getReal` convert between the integer kinds and to real where the value fits.
- `setGlobalNullAccessCallBack` (NID `00oCq0RwSAY`) was identified by hashing its mangled name.
- `MemAllocator`'s base constructor and destructor install the abstract class's vtable. A derived allocator replaces it with its own, so its entries (which throw, like a pure virtual call) run only if a pure virtual is called. `Initializer::initialize` throws on a null parameter instead of silently accepting it.
- Mutating a value that isn't the expected type (`referArray` on a string, etc.) throws.
feat(libkernel): pread, pwrite, getdents and getdirentries on linux
- **pread/pwrite:** use the existing `NativePread`/`NativePwrite` and don't move the file offset. A null buffer with a non-zero size returns `EFAULT`, a negative offset `EINVAL`, and host failures go through `SceErrorFromErrno`.
- **getdirentries:**
- reads host `getdents64` records and converts them to the FreeBSD `struct dirent` layout the guest expects (`d_fileno` u32, `d_reclen` u16, `d_type` u8, `d_namlen` u8, NUL-terminated name, record padded to 4 bytes);
- `*basep` gets the directory position from before the read;
- when a record doesn't fit in the guest buffer, the descriptor is moved with `lseek` back to that entry's cookie, so the next call resumes there;
- if not even the first record fits, the call returns `EINVAL` without consuming anything, and a name longer than 255 bytes returns `ENAMETOOLONG`.
- **getdents** is `getdirentries` without `basep`.
- Adds the guest `EFAULT`, `EINVAL` and `ENAMETOOLONG` constants.
feat(userservice): user name, user number and accessibility settings of the initial user
They report the initial user, following `sceUserServiceGetGamePresets`:
- **Name:** `Player`. A buffer shorter than 17 bytes returns `SCE_USER_SERVICE_ERROR_BUFFER_TOO_SHORT` (`0x8096000A`).
- **User number:** 1.
- **Accessibility settings:** 0, the setting-off value on a fresh console.
fix(libc): don't walk guest frame pointers when reporting an unhandled exception
Only log __builtin_return_address(0), which doesn't depend on the guest's frames. After the fix, the log prints the exception type and the terminate handler prints what().
feat(libc): mspace memalign, malloc stats, thread-unsafe flag and nested mspaces
- Memalign uses the existing aligned allocation.
- Stats fill `SceLibcMallocManagedSize` (size checked against 0x28) from new `inUse`/`peakInUse` counters on the arena. The system size is the arena's extent.
- The thread-unsafe flag is accepted: the implementation always locks, so skipping locks is only an optimisation it doesn't need. Other flags are still rejected.
- An overlapping create is allowed only when the new range lies entirely inside a live block of the other mspace. Every other overlap is still rejected.
feat(libkernel): hinted and no-overwrite mappings, virtual range names and usleep
- **Non-fixed mapping with an address hint:** `MapAligned` threw `Non-fixed mapping address hints are not implemented`. On the PS5 the hint is where the search starts. On Linux the mapping is now placed at the first free, aligned range at or above the hint, found from `/proc/self/maps` and mapped with `MAP_FIXED_NOREPLACE` so nothing existing can be replaced. `RequireAvailable` is now only checked for fixed mappings, because a hint may point at used memory. Windows still throws.
- **`SCE_KERNEL_MAP_NO_OVERWRITE` (`0x80`):** it was rejected as an unknown flag. With `MAP_FIXED` on Linux it maps with `MAP_FIXED_NOREPLACE`, and it no longer takes the "remap fixed into registered" path, so it fails instead of replacing a registered range. The unsupported-flags error now includes the flag value.
- **Virtual range names:** `sceKernelSetVirtualRangeName` was `NotImplemented` and `sceKernelClearVirtualRangeName` wasn't exported. Names are now kept in a registry, split and trimmed on overlap. `sceKernelVirtualQuery` reports the name and splits its reported region at name boundaries. `sceKernelMapNamedDirectMemory` and `sceKernelMapNamedFlexibleMemory` now name the range instead of ignoring the name.
- **`usleep`** is exported (POSIX, beside `nanosleep`).
feat(input): support game controllers and configurable bindings
- Add optional per-game keyboard and mouse bindings through `anyps5-input.ini` or `ANYPS5_INPUT_CONFIG`. Unspecified actions keep their built-in bindings, and repeated action entries provide alternatives.
- Keep wheel presses and focus-loss state handling compatible with dynamically sized bindings. Report configuration errors through the existing video and pad failure path.
- Document the format and remove the resolved input-mapping debt item.
feat(libc): sscanf_s on linux
sscanf_s was a NotImplemented placeholder in libc/Export.cpp, and a retail title uses it to parse strings. It's now implemented on Linux. Windows still throws NotImplemented.
feat(agc): emit indexed indirect draws
This implements `sceAgcDcbDrawIndexIndirect` and `sceAgcDcbDrawIndexIndirectMulti`. They were stubs that aborted with "not implemented".
They follow the existing non-indexed `sceAgcDcbDrawIndirect` / `DrawIndirectMulti`:
- `DrawIndexIndirect` emits `DRAW_INDEX_INDIRECT` (0x25): data offset, base vertex / start instance SGPR locations, draw initiator (5 dwords, matching `GetSize` = 20).
- `DrawIndexIndirectMulti` emits `DRAW_INDEX_INDIRECT_MULTI` (0x38): the same fields, plus the draw-index location / count-indirect control word, count, count address and stride (10 dwords, matching `GetSize` = 40). The stride must be at least 20, the size of an indexed record.
fix: support SDK startup, linear framebuffers and indexed draws
Fix SDK startup with an empty allocator replacement table, add linear framebuffer presentation through the current presentation path, and implement explicit indexed draws with packet validation. Retain buffer-address regression coverage for the correction already upstream, and restrict the POSIX exception-runtime test to Unix so Windows test builds succeed.
Also fix two issues reproduced after rebasing: render-target format lookup probed unsupported formats by repeatedly throwing exceptions, costing about 78 ms per draw; the lookup now searches supported entries directly. Recorder buffers now use Windows FLS cleanup to avoid MinGW freeing emulated TLS storage before running their destructors. Cross-DLL tests check independent values and destruction on standard and native Windows threads.
Ported from shadPS4 (GPL-2.0-or-later) with system fonts removed, stubs made to throw,
and sceFontCloseFont implemented.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ButHENCbXXt8h4EZuWUabJ
The host-region fallback added with the Demon's Souls work calls VirtualQuery and
includes windows.h unconditionally, so libkernel no longer compiles on Linux.
On Linux, read the containing mapping and its permissions from /proc/self/maps.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ButHENCbXXt8h4EZuWUabJ
Every lock, unlock, signal and wait took the process-wide initialisation
mutex to read the handle, serialising all guest synchronisation. The
handle is now read atomically and the lock is only taken to initialise a
static initializer or to report a destroyed object.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0177gthrWEBBfBu5xJDXgBfo
The merge brought a NotImplemented scePthreadOnce_nid_postfix next to the
existing scePthreadOnce. The NID patcher gives the NID to the postfixed
symbol, so the stub replaced the working export and the title aborted at
its first once-initialisation.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0177gthrWEBBfBu5xJDXgBfo
When the presentation device was replaced, textures created on the old
device stayed in the global sampled and storage texture caches and kept a
reference to the destroyed TextureDetiler, whose VkDevice was then read
corrupted ("missing Vulkan function: vkResetDescriptorPool" at startup).
The replacement now flushes the old device's cached storage textures and
publishes every unit shadow before waiting for the device, and the device
teardown erases the cache entries that belong to it.
Patch author: boykopovar (fix-vulkan-texture-lifetime.patch, PR #5 review).
Co-Authored-By: boykopovar <boykopovar@gmail.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0177gthrWEBBfBu5xJDXgBfo
Brings in main up to 9958d26 (homebrew runtime, POSIX wrappers in
libkernel, sce_module guest modules and --skip-sce-module, the --to-intel
general pipeline, libSceRandom, libSceRtc, libScePosixForWebKit,
libRenoirCore, test wiring).
Resolutions where both sides implemented the same thing:
- libkernel pthread: main's structure (lazy static initialisation,
destroyed markers, MutexOperations/CondOperations, mutex protocol and
condattr clock) with this branch's TimedWait deadlines and condition
(precise timed lock/wait on Windows), wait tracing, the adaptive mutex
type 4, POSIX default ERRORCHECK mutexes, EDEADLK/EPERM results instead
of throws, and condition clocks honoured for absolute timeouts.
- libc locale: the guest Dinkumware ABI (_Locimp, facet vtables, short
ctype/case tables, locale ids, stream storage) is kept because guest code
inlines those layouts; main's C character functions are kept on top.
- libc stdio/strings/math: main's stream functions (guest FILE status
sync), strerror/perror, remove, formatting, string and math exports win
over this branch's duplicates.
- libc paths: main's working directory with this branch's path aliases
resolved on the normalised guest path.
- libkernel file: this branch's sceKernel* results as SCE errors, main's
POSIX wrappers and both fstat helpers.
- relinker: this branch's stub lowering keeps its trampolines through the
main executable path; guest modules refuse lowerings that need stubs.
- AGC driver: main's rendering wait is executed by this branch's workers.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0177gthrWEBBfBu5xJDXgBfo
sceAgcDcbDrawIndexIndirect and sceAgcDcbDrawIndexIndirectMulti emit
DRAW_INDEX_INDIRECT (0x25) and DRAW_INDEX_INDIRECT_MULTI (0x38) like their
non-indexed counterparts, with 20-byte records.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Convert 5 remaining pure stubs (log + return 0) to throwing with
literal NID, keep trailing return 0. Real SDL/state-tracking impls
(20 studio + 2 libfmod + C++ classes) untouched. Remove stale
logging-stub comments only around touched stubs.
Throwing: Cm2cmtCv8cA, EfM9xXvBmxk, Js90KQXVS4s, oCYWES02VPc, vVwA2cZA5e4
Copy the patched libcohtml.prx to libcohtml.Prospero.prx (exact DT_NEEDED name) via a post-build copy in the module CMakeLists, wired into the libs umbrella target. OUTPUT_NAME with a dot was rejected: the parent pipeline derives unpatched/patched paths from the directory target name, so renaming output would break it; dotted CMake target names are supported (e.g. libSceSaveData.native) but the parent-owned NID-patch rule is kept untouched. Adds DEPLOY.md deploy note. All 50 raw NIDs re-verified in the renamed file export table.
Minecraft Legends' libcohtml.Prospero.prx imports 23 NIDs from lib
libRenoirCore.PS5_v1 (docs/legends-unresolved-nids.json). Clear names are
unknown, so each export is exposed under its raw NID via APS5_EXPORT
alias (<NID>_nid_no_patch_cut), which nid_patcher strips to the
literal NID instead of hashing.
Stubs follow KytyPS5 UnresolvedImportStub policy (log call + return 0)
via APS5_LOG_OUT rather than throwing NotImplemented.
test: wire up the orphaned exception runtime test
- `core/libs/CMakeLists.txt`: registered `ExceptionRuntime.cpp` as `exception_runtime_tests`/`exception_runtime`, following the existing `Guest*.cpp` test pattern, linked against `libc`.
test(agc): fix and re-enable 3 of 8 bitrotted AGC driver tests
- `agc_driver_graphics_tests`: fixed the link failure by adding the three missing source files and linking `shader_recompiler_agc_driver`. Still fails at runtime against stale assertions accumulated over many commits of not being built (an expected "not implemented" message that texture support since removed, and a sampler test fixture value that no longer fits its 12-bit field). Left `EXCLUDE_FROM_ALL`; fixing the assertions is a separate pass across the whole 1150-line test file, not a build fix.
- `agc_driver_recompiler_tests`: root-caused but not fixed. It needs `COMPUTE_NUM_THREAD_X` set, and its pass condition checks for a "not implemented" stub error that no longer exists now that the real recompiler is in. Restoring its original intent needs a shader deliberately built to fail recompilation, which is a design decision, not something this PR should decide unilaterally. Left `EXCLUDE_FROM_ALL`.
- `agc_driver_tests`, `agc_shader_memory_tests`, `agc_driver_flip_tests` and `agc_driver_pm4_tests` already passed; registered them with `add_test` so none of the four can bitrot silently again.
fix: correct sscanf %x signedness and avoid a substr copy
- `core/libs/prx/libSceSysmodule/Export.cpp`: `devMajor`/`devMinor` now `unsigned int`.
- `core/libs/nid/include/nid/NidPatcherUtils.hpp`: two `substr(0, n)` calls replaced with `resize(n)`.
Kernel error codes were redeclared per file under three prefixes
(SCE_KERNEL_ERROR_, EQUEUE_ERROR_, KERNEL_SEMA_ERROR_), which let wrong
values go unnoticed. Define them once as 0x80020000 | errno for errno
1..94 and use the SCE_KERNEL_ERROR_ names everywhere. Values are unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
SCE kernel errors are 0x80020000 plus the FreeBSD errno. The equeue and
direct memory constants used an unrelated 0x8001xxxx range with mismatched
errno values (e.g. ETIMEDOUT was 0x80010023), so a guest checking
sceKernelWaitEqueue for SCE_KERNEL_ERROR_ETIMEDOUT saw an unexpected error.
SCE_KERNEL_ERROR_EDEADLK in Mutex.cpp held the EAGAIN value.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
SCE kernel errors are 0x80020000 plus the FreeBSD errno. The equeue and
direct memory constants used an unrelated 0x8001xxxx range with mismatched
errno values (e.g. ETIMEDOUT was 0x80010023), so a guest checking
sceKernelWaitEqueue for SCE_KERNEL_ERROR_ETIMEDOUT saw an unexpected error.
SCE_KERNEL_ERROR_EDEADLK in Mutex.cpp held the EAGAIN value.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- scePthreadSelf returned null on Linux and for threads not created by
scePthreadCreate (including the main thread); such threads now get a
lazily adopted, non-joinable handle
- scePthreadExit on Linux skipped FinishThread, losing the join value
- detached threads on Linux were never freed; use the reference count
already used on Windows
- unlocking a recursive mutex from a non-owner was undefined behaviour;
return SCE_KERNEL_ERROR_EPERM
- scePthreadCondTimedwait did not restore the mutex owner after waking,
so another thread locking during the wait made the waiter's unlock
fail with EPERM and left the mutex locked forever
- SCE_KERNEL_ERROR_ETIMEDOUT in Cond.cpp was 0x80020062 instead of 0x8002003C
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A zero frequency was stored and later used as a divisor when computing
the output block duration. Return SCE_AUDIO_OUT_ERROR_INVALID_SIZE and
SCE_AUDIO_OUT_ERROR_INVALID_SAMPLE_FREQ instead.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Dispatch cache with per-key value variants and data-only hits (flat-SRT leaves the recompiler
proves pure are refreshed into the resource template instead of re-captured), dispatch and draw
recipes replaying a proven prepare, register-keyed draw entries, template data refresh, unit
shadows in device-local slabs, 64 KiB block-unit storage tracking with windowed detile, DCC
clear-key proofs, per-class GPU timing, a CPU copy path with batch read tracking, present slot
ring, rate-limited reaps and lazy completion counting, plan-failure and poisoned source memos,
bindless image tables (runtime-indexed descriptor arrays from a CPU-read table) so the
per-frame compute program that failed its plan now compiles. Worker affinity opt-in, per-draw
logs behind APS5_TRACE_DRAWS, wait-timeout reports include the recorder's view of the label.
Fixes a use-after-free behind BDA-miss dispatch snapshots and the CPU-write stamp of
UnchangedSinceCollected. Intro-video stage: 154 -> ~500 presents per 10 s at 4K.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0177gthrWEBBfBu5xJDXgBfo
libkernel: a TimedWait service for condition variables, semaphores, event flags, rwlocks and
equeues with the scheduler tick; mutex/cond/sem corner cases the title hits; job worker
affinity is opt-in (APS5_JOB_AFFINITY). libc: calloc/realloc heap slot swap, a default
terminate handler with a backtrace, CPU topology helper. libSceRtc export fixes with tests.
libSceVideoOut: APS5_NO_PAD_INPUT ignores host input for unattended measurements,
APS5_FLIP_QUEUE_WAIT keeps a stalled process alive for a debugger. ApplicationHeap and
GuestRtc tests wired into the test build.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0177gthrWEBBfBu5xJDXgBfo
These EXCLUDE_FROM_ALL targets weren't registered with add_test, so
they silently bitrotted with no CI/ctest visibility:
- agc_driver_graphics_tests: fixed a link failure (Draw.cpp, Pipeline.cpp
and GraphicsPipelineCache.cpp were never added to the target's sources
when the test started calling into them). Still fails at runtime against
several stale assertions (a removed "not implemented" error message, a
sampler fixture value that doesn't fit its bitfield) accumulated over
many commits of not being built; left EXCLUDE_FROM_ALL pending an
assertion-maintenance pass.
- agc_driver_recompiler_tests: root-caused (missing COMPUTE_NUM_THREAD_X
register setup, plus a pass condition checking for a stub error message
that no longer exists now that the real recompiler is implemented) but
left unfixed and EXCLUDE_FROM_ALL — restoring its original intent needs
a shader deliberately built to fail recompilation, a design decision.
agc_driver_tests, agc_shader_memory_tests, agc_driver_flip_tests and
agc_driver_pm4_tests already passed; registered them with add_test too
so none of the five can bitrot silently again.
agc_driver_bda_device_tests: dropped from this commit's scope. Upstream
PR #20 already proposes the same one-line BdaContracts.cpp fix (matching
the runtime message's "signature" text), so BdaContracts.cpp is left
untouched here to avoid duplicating that fix. The test target stays
defined (EXCLUDE_FROM_ALL, still buildable by name) but is no longer
registered with add_test until #20 or an equivalent fix lands.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
ExceptionRuntime.cpp existed complete and working but was never
registered in CMakeLists.txt, so it never built or ran. Wired it in
following the existing Guest*.cpp test pattern.
The other three orphaned test files (PthreadStart.cpp, FileStreams.cpp,
Formatting.cpp) were left out: each has genuine bitrot against current
code (a moved header, fseek returning errno instead of throwing on an
invalid whence, and vsnprintf's expected va_list mutation) that needs a
source-level decision, not a CMake wiring fix.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
libSceSysmodule/Export.cpp parsed /proc/self/maps device major/minor
numbers into signed int with a %x format, which is undefined behaviour
per the C standard even though it happened to work on this target;
switched to unsigned int to match the format specifier.
NidPatcherUtils.hpp's StripNidPostfix built a truncated copy with
substr(0, n) where the prefix is already the string itself; resize(n)
does the same truncation without the extra allocation and copy.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Exports.cpp aliased the real std::uncaught_exception(s) mangled names
directly to __cxa_uncaught_exception(s)_nid_postfix instead of the
existing _ZSt18uncaught_exceptionv_nid_postfix/_ZSt19uncaught_exceptionsv_nid_postfix
wrappers, leaving the latter as dead code and breaking the file's own
bare-name -> matching-nid_postfix alias pattern (caught by fleet QA
review, no functional impact since it's a raw symbol alias and both
sides return in the same register).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
On native Linux these PRX shared libraries and their test executables
dynamically link real libstdc++/libgcc, so a plain throw went through the
system's __cxa_throw/_Unwind_RaiseException. That still invoked this
project's own __gxx_personality_v0_nid_postfix (the CIE's personality
pointer is a raw function address, agnostic to which unwinder is walking
the stack), but handed it libgcc's incompatible private _Unwind_Context
layout, corrupting every field Personality.cpp reads and aborting with no
exception message.
Fix: OwnPersonality() now recognises the bare __gxx_personality_v0 wrapper
on Linux too (previously Windows-only), and Exports.cpp exports the real
ABI names (__cxa_throw, __cxa_begin_catch/end_catch, __cxa_rethrow,
__cxa_allocate/free_exception, __cxa_call_terminate, __cxa_get_exception_ptr,
__cxa_current_exception_type, __cxa_init_primary_exception, the std::
terminate/uncaught_exception(s) mangled names, and the core _Unwind_*
entry points) via the existing GCC_GLOBAL_ALIAS assembler-alias mechanism,
so ELF symbol interposition makes this project's own implementation win
process-wide over libgcc_s.so.1/libstdc++.so.6. __cxa_init_primary_exception
is newly implemented; GCC 13's inline std::make_exception_ptr needs it and
nothing provided it before.
Fixes 7 previously-aborting tests: guest_rendering_wait, guest_buffer_reuse,
guest_shader_link, guest_system_exit_parameters, guest_once, guest_memory,
guest_search.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
feat(rtc): implement libSceRtc date and tick functions
- Ticks count microseconds since 0001-01-01 00:00:00 in the proleptic Gregorian calendar, up to 9999-12-31 23:59:59.999999. `sceRtcGetTickResolution` returns 1000000.
- Validation (`sceRtcCheckValid`, `sceRtcIsLeapYear`, `sceRtcGetDayOfWeek`) returns the matching `SCE_RTC_ERROR_INVALID_*` code (`0x80B50002`–`0x80B5000E`).
- Conversions: `sceRtcGetTick`/`SetTick`, `GetTime_t`/`SetTime_t`, `GetWin32FileTime`/`SetWin32FileTime`.
- Current time: `sceRtcGetCurrentTick`, `GetCurrentClock`, `GetCurrentClockLocalTime`. `sceRtcGetCurrentNetworkTick` uses the host clock.
- UTC and local time conversion through the host time zone.
- `sceRtcFormatRFC3339` (`YYYY-MM-DDThh:mm:ss.cc` plus `Z` or `±hh:mm`) and `sceRtcParseRFC3339`.
- Tick arithmetic (`sceRtcTickAdd*`) rejects results outside the valid range with `SCE_RTC_ERROR_INVALID_VALUE`.
- New exports: `sceRtcGetDaysInMonth`, `sceRtcTickAddMonths` and `sceRtcTickAddYears`. The last two clamp the day to the end of the target month (2024-01-31 + 1 month = 2024-02-29).
Ticks count microseconds since 0001-01-01 in the proleptic Gregorian
calendar, up to 9999-12-31 23:59:59.999999. Implement validation, tick
and date conversion, time_t and Win32 FILETIME conversion, UTC and
local time conversion through the host time zone, RFC 3339 formatting
and parsing, and tick arithmetic. Add sceRtcGetDaysInMonth,
sceRtcTickAddMonths and sceRtcTickAddYears, which clamp the day to the
end of the target month.
The network clock uses the host clock.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Fill the buffer from std::random_device and reject a null buffer or a
size above SCE_RANDOM_MAX_SIZE (64) with SCE_RANDOM_ERROR_INVALID, as
the system library does.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Tests in core/libs link against the prx shared libraries, which the
global -static flag rejects on Linux ("attempted static link of dynamic
object"). Drop -static in that directory on non-Windows hosts while
keeping the static GCC runtime.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The SDK's inline release wrapper passes gdsOffset 0 and gdsSize 1 for
every release, not only GDS ones. The packet ignores the range unless the
GDS data selector is used, so accept that default.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Guest mprotect calls on the executable's own segments failed with
"guest protection or unmap range is not registered" because only the
Windows build registered the main image. Register the PT_LOAD segments of
the main executable page by page, merging the protections of segments that
share a page.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Retail titles pass protections such as 0xC2 (CPU read/write plus the
0x40 and 0x80 device access bits). The device bits do not affect CPU
access and were rejected as unsupported.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
SCE_KERNEL_PROT_CPU_RW (0x02) and CPU_EXEC (0x04) include read access,
but were translated to write-only and execute-only host pages. GPU read
and write bits also need host access because the emulated GPU reads and
writes guest memory from the CPU. Write-only mappings made the AGC driver
reject guest data segments as unreadable.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
SceLibcMallocReplace lists calloc before realloc (malloc, free, calloc,
realloc, memalign, reallocalign, posix_memalign, ...), as the table in
retail titles shows. realloc therefore called the application's calloc
with the old pointer as the element count, and calloc called realloc.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
GCC on Linux rejects the attribute, which breaks the libs build since the
F11 fullscreen change. It has no effect on x86-64 Windows.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- AudioOut2: one SDL device per context; the hardware grain queue level
is derived from the SDL queued bytes so the title's poll-and-push loop
runs at real time; ports are mixed per push with 7.1 folded to stereo.
- libSceAjm.native: instance and batch APIs; ATRAC9 decoding with
variable-size frames inside superframes, padding, gapless parameters
and handle re-creation on re-initialisation.
- AudioOut v1: sceAudioOutOutput(handle, NULL) drains instead of
throwing.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0177gthrWEBBfBu5xJDXgBfo
Replaces the synchronous per-command execution model, and with it the
upstream render-target, pipeline-cache, tile-buffer, batched-draw and
memory-ownership commits (5a280ce, 7ed5a0b, 46c799d, 598caac, 40df528),
whose files are removed.
- Recorder: one open command buffer per device; dispatches, resident
draws, uploads, write-backs, labels, fills and copies record into it;
timeline-semaphore serials let drains wait without the GPU mutex;
completions run in order at reap.
- one worker thread per PM4 queue; labels and stores written by the GPU
into the host import; GPU-side DISPATCH_INDIRECT; the buffer-fill
kernel replaced by vkCmdFillBuffer; a dispatch cache validated by
write watch; filler packets tolerated; rejected submissions dumped.
- guest memory: page-state cache, 64 KiB write generations, host imports
with VK_EXT_external_memory_host, persistent mirrors of the executable
image, GPU copies of misaligned sub-ranges.
- textures: shader-written images stay resident with deferred
write-back (adjacent-generation rule for packed video planes), sampled
views of storage images, DCC key handling, addrlib swizzle equations,
bidirectional detiler.
- draws: MRT, more formats, dynamic viewport/scissor, cached pipelines,
resident 64 KiB targets, draws recorded into the recorder.
- ShaderResources: two-stage build, descriptor and sampler caches, a
content-keyed resource cache; presentation from the resident image.
- a label deferred behind a completion is no longer re-stored by the
CPU at reap time unless a write-back overwrote it.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0177gthrWEBBfBu5xJDXgBfo
- libc: reserve guest memory in one arena below the PS5 map limit with
MEM_WRITE_WATCH (GuestArena) and a caching guest heap; the allocation
registry gains a generation counter, an invalidator callback for the
driver's page cache and a pin waiter for leased ranges. This replaces
the fault-based GuestMemoryTracking/GuestMemoryBacking layer, whose
files are removed.
- libkernel: mmap/mprotect/munmap on the arena, flexible memory budget,
real sceKernelVirtualQuery; POSIX pthread layer, rwlocks, timed locks,
TSD, event flags; 0.5 ms scheduler tick and high-resolution sleeps;
TSC/clock/time functions; file APIs return SCE errno codes; the APR
file-streaming API.
- libc: vectored crash reporter with backtraces for fatal exceptions,
SIGABRT, UCRT invalid parameters and process exit; SSE4a EXTRQ/INSERTQ
emulation for Intel hosts; %ls/%lc/%S/%C with the guest's 16-bit
wchar_t; hand-written setjmp/longjmp for the guest jmp_buf; a path
alias table for short save-data mount points; more string, stdio and
math exports.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0177gthrWEBBfBu5xJDXgBfo