fix(build): link json and fiber tests with libc
Fix test linking by adding `libc` to the `guest_json_tests` and `fiber_tests` link dependencies, resolving the missing `__gxx_personality_v0` symbol.
Ran all 54 CTest tests in. The build was successful.
Currently **50 passed, 4 failed**.
`guest_json` and `fiber` passed.
The following tests failed with code `0xc0000139`:
- `agc_driver`
- `agc_shader_memory`
- `agc_driver_flip`
- `agc_driver_pm4`
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>
Fix/frame flicking
## Summary
Fixed corrupted frames caused by guest input buffers being overwritten before GPU execution.
## Cause
Draws referenced mutable guest memory. The CPU could overwrite an input buffer after the draw was recorded but before the GPU consumed it.
## Detection
Instrumentation compared input-buffer contents at draw recording and GPU execution. Corrupted frames contained mismatches in buffers used by affected draws; adjacent correct frames did not.
## Changes
The recorder now creates per-draw copies of read-only CPU input buffers and keeps them alive until GPU completion. Each draw uses descriptors referencing its preserved data.
Buffers with pending GPU writes remain on the existing path and are not copied from CPU memory.
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.
- Optimization/SrtWalker/SrtPlanBuilder.cpp: PlanBuilder::Collect now requires
RuntimeValidator(...).Run(inst) before folding an offset built from a Phi merging a
constant on one path with a per-invocation value on another. Confirmed upstream's
Collect is unchanged since the fork (still just offset->HasImmediate()), so a Phi
that reports HasImmediate() on its constant edge alone could still be folded into
the wrong, divergent SRT slot.
- RdnaDecoder + Translation: adds an IMAGE_BVH_INTERSECT_RAY (opcode 0xE6) decode path
and a TranslationContext::imageBvhIntersectRay stub that reports a clean hardware
miss (all result dwords 0xFFFFFFFF) instead of faulting on an undefined MIMG opcode.
No BVH/ray-tracing support exists upstream at all, so this is an honest "not
supported yet" stub, not a silent wrong answer.
- SpirvBackend/RectListShaders.cpp: raises the accepted spirvVersion ceiling to
0x10500 and truncates excess fragment interpolants to the tightest per-vertex
tessellation component limit instead of hard-refusing the whole rect-list draw.
A rect-list draw is a tile clear, so a pixel shader's result comes from its
constants and render target; truncated interpolants are simply left unwritten,
which upstream's own "missing" (unexported) parameter handling already tolerates.
Dropped after checking against current upstream (both would be redundant or
out of scope):
- ResourcePlanKnownToFail / SpirvWords (Recompiler.cpp/hpp): upstream already has an
equivalent mechanism for both. SourceEntry::planFailure (std::exception_ptr) already
memoizes and rethrows a failed IrResourcePlan build, and RecompileResult::spirv is
already the refcounted/hashed SharedSpirv class (see Recompiler.hpp), not a plain
vector. Porting either would have added a second, competing mechanism.
- ScalarInstructions.cpp SAVEEXEC changes: skipped. The audit could only confirm 3 of
6 64-bit SAVEEXEC cases were converted in the prior patch, which is a half-finished
edit rather than a complete correctness fix; not safe to port without re-deriving
sSaveexec()'s full semantics from scratch.
- ControlFlowInstructions.cpp vMovrelsB32/vMovreldB32 hardening (offset & 0xFF mask +
kMaxM0RelativeWindow cap): skipped as optional per review; upstream's core fix for
this file is otherwise already in place.
- All diagnostic-only stderr tracing (IrBuilderCore.cpp, ResourceTracker.cpp,
ShaderInfoCollector.cpp, SrtDescriptorEvaluation.cpp, SrtEvaluator.cpp,
SpirvMemoryInstructions.cpp) and the superseded Optimization/ResourceProgram.hpp
API (replaced upstream by CaptureResources/SourceHandle/ResourceCapture): not
ported, no functional change or already gone upstream.
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>
The Windows PE lazy-import GOT slot was written as a bare 4-byte RVA,
but the .reloc entries generated for the .gtls/data sections use
IMAGE_REL_BASED_DIR64, which only adds the load delta to whatever is
already stored at the slot. A bare RVA therefore resolved at runtime
to (loadBase - ImageBase + rva) instead of the intended stub address,
pointing into unmapped memory whenever the module was not loaded at
its preferred base.
Write the full 8-byte preferred-VA form (ImageBase + stubRva) instead,
matching DIR64 semantics, and generate a base relocation entry for
each lazy-stub GOT slot. The .reloc section is now built after the
lazy stubs are written into their target sections rather than before,
since it previously captured only the relocations known at that
point and missed the newly patched slots entirely.
fix(video): terminate process on gpu and presentation thread failures
Now, any expression that reaches the handlers of a GPU worker, presentation thread, or vblank calls std::terminate() and terminates the entire process.
A closed window is just one of these cases. Previously, the handlers stored and propagated the error, which allowed the process to continue.
The normal shutdown with stopping all guest threads is not implemented.
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`.
refactor(agc): make frame timing logs optional by cmake option
Added the CMake option `APS5_ENABLE_TIMING_LOG`, which defaults to `OFF`. To enable it: `-DAPS5_ENABLE_TIMING_LOG=ON`.
`[FrameTiming]` log for each frame is only output if this option is enabled.
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.