24 KiB
24 KiB
Project technical debt
Build
- Building on Windows requires a specific version of mingw - MinGW-w64 GCC 15.2.0 (
winlibs-gcc15,x86_64-ucrt-posix-seh) - Even compiled prx libraries on Windows require nearby (static linking of these dependencies causes conflicts):
- libgcc_s_seh-1.dll
- libstdc++-6.dll
- libwinpthread-1.dll
Silent stubs
Throughout the project, every function at every stage either does exactly what it's supposed to or throws an exception. Everywhere... except:
- libSceSaveDataDialog.native
- libSceCommonDialog
- libSceErrorDialog - the error dialog runs the state machine but shows nothing; the error code passed to
sceErrorDialogOpenis only logged - libSceHmd implements only the disconnected-headset path: initialization succeeds, device queries report
NotDetected, and opening a device returnsDeviceDisconnected. Headset support, tracking, rendering and additional HMD exports are not implemented; SDK-level ABI compatibility and in-game behaviour remain unverified. - libSceAudioPropagation implements only the no-acoustic-propagation path: the system keeps a 16-byte header in the title's CPU memory (no GPU memory), rooms, portals, sources and materials are tracked handles, attributes are validated and have no effect, no rays are requested and sources report no audio paths. Ray results, path calculation and audio paths are accepted only when empty and throw otherwise;
sceAudioPropagationSourceRenderwrites silence (zeroes) to each source's output buffer for the given size, without a dry signal. Objects still alive when their system is destroyed become unusable, and their later destroy or unregister is a no-op: PPSA21567 releases its reference-counted room, portal and source owners just beforesceAudioPropagationSystemDestroy, so the order for every object is not proven. Occlusion, reflections and reverb from level geometry are absent; in-game behaviour remains unverified. - libSceNpCommerce - the PS Store icon show/hide calls do nothing
- sceVideoOutOpen validates the priority and CPU affinity that the open param requests for the VideoOut service thread but does not apply them: the port's present and vblank threads are host threads, and guest priorities and affinities do not reach host scheduling
- The shader recompiler skips baryctric coordinates (is not even passed to SpirvTargetOptions at row 212).
- libSceAvPlayer:
sceAvPlayerSetLogCallbackaccepts a callback that is never called, as the player produces no log messages, andsceAvPlayerSetAvailableBandwidthhas no effect, as it governs HLS sources, whichsceAvPlayerAddSourcedoes not implement. - sceAvPlayerSetTrickSpeed (libSceAvPlayer) with a negative speed runs the clock backwards but delivers no frames; when a forward speed is set again, playback resumes from the rewound time.
Unknown function info
- sceAvPlayerAddSource (libSceAvPlayer) - requests up to 4 additional decode-ahead video framebuffers from the memory replacement beyond
num_output_video_framebufferswhen memory is available; the console's internal buffering behaviour is unknown - sceVideoOutOpen (libSceVideoOut) - the open param's first word is unknown (PPSA21564 passes 16; it is not the byte size, since the affinity mask is at offset 16); only 16 is accepted. Whether the param continues past offset 24 is also unknown
- sceRtcParseDateTime (libSceRtc) - accepted format assumed to be the ISO 8601 subset
YYYY-MM-DDTHH:MM:SS[.ffffff](T/t/space separator, optional fractional seconds) with the sibling RFC 3339 zone suffix (Zor±HH:MM); a string without a zone is taken as UTC, and anything outside this shape throws instead of returning a parse error, unverified against hardware - AMPR WriteAddressFromCounterPairOnCompletion (libSceAmpr) - the pair of an even counter n is assumed to give counter n in the low 32 bits and n + 1 in the high 32 bits. Wait compare values, wait flush and counter index ranges follow the ampr_emu reimplementation; the flush is accepted and has no effect, as commands run in order
- AMPR markers (libSceAmpr) - signatures taken from the ampr_emu reimplementation, not confirmed on a title:
sceAmprCommandBufferSetMarkerWithColortakes the color by pointer, the push and measure variants by value. Colors are not recorded - sceFontGetRenderScaledKerning (libSceFont) - arguments, the cleared output and the bound renderer check taken from
cellFontGetRenderScaledKerningin RPCS3 (PS3 predecessor of the library), not confirmed on a title. The kerning is thesceFontGetKerningone at the render scale - sceFontGetPixelResolution (libSceFont) - signature taken from the IDA type database of Orbital, not confirmed on a title. The value is the one the library's driver reports (64 for FreeType); the argument checks and the cleared output follow
sceFontGetLibrary - sceAgcSetSubmitMode (libSceAgc) - mode values unknown; only 0 is accepted
- zARR5aCmkoY (libSceAgc) - unknown name, signature
- qj7QZpgr9Uw (libSceAgc) - unknown name
- fd5Bp5tGTgo (libSceAgc) - unknown name
- dolOmWH+huQ (libSceAgc) - unknown name
- V++UgBtQhn0 (libSceAgc) - unknown name
- gQkqkLttcpw (libSceAgc) - unknown name, signature
- sceAgcDcbPrimeUtcl2 (libSceAgc) - assumed to write the packet
sceAgcAcbPrimeUtcl2writes: PRIME_UTCL2 has the same 5 dwords on the graphics and compute rings. Not confirmed on a title. Both write a NOP of that size, as there is no TLB to prime - sceKernelInternalMemoryGetModuleSegmentInfo (libkernel) - unknown signature
- sceKernelSyncOnAddressWait (libkernel) - the only known caller passes a null timeout and a name string as the fourth argument; the timeout is assumed to point to microseconds like the other kernel waits, and the name is ignored
- sceKernelMapNamedFlexibleMemoryInternal (libkernel) - flag 0x8000 unknown; only the sceKernelMapNamedFlexibleMemory flags are accepted
- sceLibcInternalBacktraceForGame (libSceLibcInternal, implemented in libc) - unknown signature
- sceLibcInternalHeapErrorReportForGame (libSceLibcInternal, implemented in libc) - unknown signature
- _sceLibcInternalThreadAtexit, _sceLibcInternalThreadDtors (libSceLibcInternal) - FreeBSD
__cxa_thread_atexitsemantics assumed; a null or non-image destructor and an allocation failure throw - _sceLibcInternalForceTlsDestructor (libSceLibcInternal) - unknown return type and behaviour; a title's
libc.prxcalls it from__cxa_finalizewith the module handle of a non-null dso - __progname (libkernel) - unknown data export
- pthread_barrierattr_setpshared (libkernel) - PTHREAD_PROCESS_SHARED throws: FreeBSD 9.0 libthr rejects it with EINVAL and 11.0 accepts it, and which one the console follows is unknown
- sceSslClose (libSceSsl) - unknown signature
- sceSslGetSerialNumber (libSceSsl) - unknown signature
- X+4jdIS75P0 (libSceAudioIn) - unknown name, signature
- sceAudioOutSetMixLevelPadSpk (libSceAudioOut) - effect of a negative mix level unknown; only 0 to 32768 (0 dB) is accepted
- sceAudioOutSetMixLevelPadSpk (libSceAudioOut) - no source applies the level (shadPS4 only stores it); it is assumed to be a linear gain on the port's own output, and the -9 dB default (11626) is applied to every pad speaker port, including those of titles that never call the function
- sceAudioOutGetLastOutputTime (libSceAudioOut) - signature and behaviour taken from the shadPS4 and fpPS4 reimplementations of the PS4 library, not confirmed on a PS5 title: the time is the process time at which
sceAudioOutOutputorsceAudioOutOutputsaccepted the port's last block, not the time the block reached the device - AOWqIYsgVHs (libSceContentExport) - unknown name, signature
- GQTObcITIXI (libSceShare) - unknown name, signature
- scePsmlMfsrGetContextBufferRequirement1100, scePsmlMfsrCreateContext1100, scePsmlMfsrGetDispatchMfsrPacket1100 (libScePsml_debug) - argument layouts unknown; only 0x8A810001 (not initialized) is returned
- BnMAMrsfVWo (libc) - unknown name, signature
- scePngEncEncode (libScePngEnc) - whether rows may stay unfiltered when
filter_typenames a subset of the filters is unknown; as in shadPS4, they may only for 0 and for the all-filters mask - AudioIn, NpSessionSignaling and PlayerInvitationDialog exports added without an implementation have assumed signatures
- libSceAudioPropagation (libSceAudioPropagation) - signatures and struct descriptors recovered from PPSA21567's calls (#481), not from documentation. The system options layout is unknown (only checked for non-null); the fourth argument of
sceAudioPropagationSourceCalculateAudioPathsis unknown;sceAudioPropagationSourceGetAudioPathis assumed to output an 8-byte path handle. The meaning of theRenderInfoword at +0x28 is unknown (PPSA21567 and PPSA21564 pass 2); only 2 is accepted. Both titles pass oneRenderInfoper call: a count of 0 throws, and larger counts are handled element by element without proof. No error code is known, so invalid input throws instead of returning one - sceAvPlayerStartEx (libSceAvPlayer) - start info layout unknown; it is ignored and playback starts as with
sceAvPlayerStart - sceAvPlayerInit / sceAvPlayerInitEx (libSceAvPlayer) - behaviour without a memory replacement unknown; frame and sample buffers then come from the guest heap
- SceAvPlayerVideoEx (libSceAvPlayer) - frame rate field and encoding unknown; it is left zero in frame and stream info
- sceAjmDecMp3ParseFrame (libSceAjm.native) - signature, result layout and rate tables taken from the shadPS4 reimplementation of the PS4 library, not confirmed on a PS5 title: the layer field is not checked and MPEG-2.5 stops at 64 kbps
- sceAjmBatchJobGetCodecInfo, sceAjmBatchJobGetGaplessDecode (libSceAjm.native) - the
RUN_GET_CODEC_INFOflag (0x800), the ATRAC9 codec info layout and its next frame size are taken from the shadPS4 and RPCSX reimplementations, not confirmed on a PS5 title; a run job without buffers returns result 0, as in shadPS4. The gapless sideband reports the total and skip counts the title set and does not count them down: RPCSX does the same, shadPS4 counts them down and BryKytyPS5 returns its current counts - AJM Opus decoder (libSceAjm.native, codec 24) - the initialize parameter layout (
u32 channels, u32 sample rate, u32, seen as2, 48000, 0) and the little-endianu16byte count before each packet come from one title (The Smurfs Dreams); only 48000 Hz and a zero third word are accepted - sceHttpParseResponseHeader (libSceHttp) - unknown signature
- sceHttp2GetMemoryPoolStats (libSceHttp2) - unknown signature
- sceNetGetMemoryPoolStats (libSceNet) - unknown signature
- sceHttpSetRequestStatusCallback (libSceHttp) - no reference implements it (shadPS4 only logs and returns 0); when the callback runs and what status it gets is unknown
- sce::Np::CppWebApi::Common::IntrusivePtr (libSceNpCppWebApi) - the 0x18-byte layout (object, deleter,
LibContext*) and the offset of the 32-bit reference count in the pointee (0x00, 0x30 forVector) come from the module bundled with one title (PPSA21564); other SDK versions are not checked. The destructor throws on the last reference of a pointer without a deleter: destroying the object needs its destructor and theLibContextallocator, which are not implemented - sceNpSessionSignalingGetMemoryInfo (libSceNpSessionSignaling) - unknown signature
- sceNpSessionSignalingGetConnectionStatistics (libSceNpSessionSignaling) - unknown signature
- sce::Np::CppWebApi::Common::String (libSceNpCppWebApi) - the 0x20-byte layout (32-bit reference count, buffer at 0x08, buffer size at 0x10,
LibContext*at 0x18) comes from the module bundled with one title (PPSA21564); other SDK versions are not checked. The destructor throws for a non-null buffer: releasing it needs theLibContextallocator, which is not implemented - sceNpTrophy2UnregisterUnlockCallback (libSceNpTrophy2) - unknown signature
- sceSystemServiceDisableMediaPlay (libSceSystemService) - unknown signature
- sceSystemServiceReenableMediaPlay (libSceSystemService) - unknown signature
- sceVoiceSetMuteFlag (libSceVoice) - unknown signature
- snwprintf_s (libc) - follows C11 K.3.9.1.3 with
RSIZE_MAXassumed to beSIZE_MAX >> 1. A runtime-constraint violation only returns a negative value:set_constraint_handler_sis not exported and the console's default handler is unknown. An invalid multibyte%sargument is copied byte by byte instead of being reported as an encoding error, as invswprintf - libSceUlt queues - the added
sceUltQueuePop,sceUltQueueTryPush,sceUltQueueDestroyandsceUltQueueDataResourcePoolDestroysignatures are inferred from the existing push/pop and object APIs. Queue destruction is assumed to reject blocked callers withULT_ERROR_BUSYand otherwise discard queued data; pool exhaustion returnsULT_ERROR_AGAIN. These rules, alignment checks and shared slot limits have not been confirmed on PS5 hardware or a title. Non-null queue and data-pool option parameters throw because their layouts are unknown.
Functional
- libSceUlt queues use preallocated host storage instead of the supplied guest work area; its existing size formula and the 512-byte object layouts remain unverified. Waiting-queue pool thread limits and waiter priority ordering are not implemented. Finalization wakes blocked queue callers with
ULT_ERROR_STATE. - MIMG
tfeandlwenever write the status VGPR after the data. On hardware it is written only when a texel fetch hits an unmapped page of a partially resident texture, or, forlweon sample/gather, when the LOD is below the T#MIN_LOD_WARN; texture memory is always resident here, andlweon sample, gather andimage_get_lodthrows. - The shader recompiler ignores
s_setreg_b32: writes to MODE (float rounding and denormal controls) and the other hardware registers have no effect, ands_getreg_b32reads of the MODE round fields report round to nearest even even afters_setreg_b32wrote another mode. The initial round mode from the shader's program registers is not read either. - Shader recompilation currently occurs right before it was transferred to Vulkan with caching, but should be moved to the relinker stage. For this purpose, shader/recompiler was written completely independently from libs/prx.
- v_fma_f64 is fused exactly only for normal inputs: with a subnormal input it is a separate multiply and add, which rounds twice.
- v_mullit_f32 follows the hardware measured with the MODE register at IEEE=1 and denormals kept (a signaling NaN src0 is quieted, a positive denormal src2 counts as positive): the recompiler does not read MODE, so other IEEE/denormal settings are not modelled.
- The executable file that relinker generates opens the console when launched, which is inconvenient for playability.
- libSceJpegEnc encodes 4:2:2 sampling requests with 4:2:0 chroma subsampling, and grayscale requests as a 3-component JPEG with neutral chroma instead of a single-component one: the JPEG encoder (stb) only produces 3-component 4:2:0 and 4:4:4 images.
- v_rcp, v_rsq, v_sqrt, v_log, v_exp, v_sin and v_cos (f32 and f16) use the driver's approximation for finite results, not the console's: the low bits can differ. Only NaN, invalid, zero and infinite results and the exact sin/cos zeros are chosen on the bits. v_sin_f32/v_cos_f32 with inputs beyond ±256 cycles were not compared with the console.
--to-inteldoes not lower RDPRU/MCOMMIT; the matcher fails the relink instead. SHA-1 and SHA-256 instructions with a RIP-relative operand fail the relink.- The length-changing path of the instruction rewriter is not used by the converter: it does not adjust VEX/0F38/0F3A RIP-relative operands, data-to-code references (relocations, FDEs, jump tables) or segment sizes, so every substitution keeps the instruction length.
- The Linux placement of the
--to-intelstubs in the ELF patcher is covered only by a synthetic test. - The libc SSE4a trap emulation on Windows is superseded by
--to-inteland remains only until the relinked title has been verified without it. --to-intelguest module trampolines are covered only by a synthetic relinker test; no game title has been verified with them on Linux or Windows.--to-intelreplaces the approximate VEX.128 register forms of VRSQRTPS and VRCPPS with correctly rounded 1/sqrt(x) and 1/x, not with the AMD approximation: its tables are not public. Intel's approximation of 1/sqrt(1.0) is 0x3F7FF000, and two Newton-Raphson steps on it settle on 0.99999994 instead of 1.0; a renormalised identity quaternion then turns into a NaN axis in PPSA21564, which the console does not show. Refined results now reach the exact value; unrefined ones can still differ from the console in the low bits. Each site costs an out-of-line stub (two jumps, a spill below the red zone, SQRTPS/DIVPS). The 256-bit, scalar, legacy and memory forms keep the native instruction, as does a 4-byte site with no movable instruction after it for the jump (5 sites in PPSA21564).- sceKeyboardGetKey2Char (libSceKeyboard) translates only the 101-key (US) arrangement and throws for the 106-key (Japanese) one; Ctrl and Alt do not change the character.
- libSceAudiodec throws for the 24-bit PCM word size (
iBwPcm0): its sample layout is unknown. ATRAC9 decoding is covered only by configuration and error tests, as no ATRAC9 encoder is available for a fixture. - sceAjmDecMp3ParseFrame (libSceAjm.native) throws when the original file length is requested (
parse_oflnon-zero): reading it from the frame's Xing/Info, VBRI or Fraunhofer data is not implemented. - The output modifier (
mul:2,mul:4,div:2) follows the hardware with the IEEE mode off and f32 denormals flushed, the LLVM graphics default; the shader's MODE register is not read, and the hardware ignores the modifier in the other modes. On f16 results it is ignored, as on the hardware while f16 denormals are enabled; with them flushed the hardware applies it. - libScePlayerInvitationDialog simulates dialog completion without displaying UI or sending invitations; its parameter ABI remains unverified.
- 64-bit LDS atomics (
ds_*_u64,ds_*_b64,ds_*_f64) read and write the two dwords under a workgroup lock stored after the guest LDS, as LDS is a 32-bit array without 64-bit atomics. They are atomic with respect to each other only: 32-bit accesses to the same dwords issued concurrently are not ordered by the lock. 64-bit GDS atomics throw.ds_min/max(_rtn)_f64andds_cmpst(_rtn)_f64follow the NaN and signed-zero rules measured for the f32 forms; the f64 forms were not measured on hardware. - Thread exit destructors (libSceLibcInternal) run when a libkernel thread finishes; on the main or a host thread only
_sceLibcInternalThreadDtorsruns them, asexitdoes, else they are dropped