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) <[email protected]>
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) <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>