The console's mouse reports relative motion, so the host cursor can never line
up with the cursor a title draws. While a title has a mouse open and the
window is focused the host cursor is hidden and captured, released on focus
loss or while the pad's mouse-to-stick toggle is on. Motion deltas are scaled
from the presented image's size in window units to the title's display
resolution with sub-pixel carry, so the title's cursor travels as far as the
host pointer would, on scaled desktops and letterboxed windows alike.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The NID -q-vbO859Tw, declared as sceVideoOutUnknown_q_vbO859Tw for
PPSA02530, hashes to sceVideoOutDeleteVrrActiveStatusEvent. It removes the
handle's VRR status registration from the queue like the other Delete*Event
calls, the counterpart of sceVideoOutAddVrrActiveStatusEvent.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017WeVmjnnPPKdxVTpr2Vjtw
anyps5-input.ini accepts LeftStickDeadzone and RightStickDeadzone (whole
percent, 0 to 90), a radial deadzone on the controller sticks whose
remaining travel is rescaled to the full range, and MouseSensitivity
(above 0, at most 10), which replaces the fixed factor of 1 for mouse
look. The defaults keep the current mapping exactly.
sceVideoOutSubmitChangeBufferAttribute2 threw when a buffer of the group
had a flip pending, and Marvel's Wolverine makes that call with flips in
the queue. A flip now takes its buffer group when it is reserved, in
submission order, so flips submitted before the change keep the
attributes their buffers were rendered with and later flips use the
new ones.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Elden Ring Nightreign (PPSA25380) imports the function, which no library
exported, so the title failed to load. The option is ORed into the buffer
attribute and a null attribute throws. Options other than 0 and 8 still
throw when the buffers are registered.
The flip queue's condition variable went through winpthreads, whose
timed waits end on GetTickCount64 steps: the present thread's 10 ms poll
for SDL events and the pad, taken while no flip is queued, ended 11 to
24 ms later on Windows, and WaitForFlipRoom's 60 s bound had the same
granularity. Use TimedWait::Condition, which waits on an event and a
high-resolution timer, so the poll ends at 10 ms and a submitted flip
still wakes the present thread at once.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Unsubscribe an event queue from the output mode events that
sceVideoOutAddOutputModeEvent registers, the same way the flip and
vblank events are removed. Deleting a registration that does not exist
succeeds, and a null queue or an invalid handle throws.
Co-Authored-By: Gemini 3.8 Flash <noreply@google.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
A flip packet names a buffer index; the buffer was looked up when the
command buffer was submitted, so a title that registers its buffers
after submitting the first frame failed with "flip buffer is not
registered". The buffer is now resolved when the GPU reaches the flip,
as the hardware does. A flip whose buffer is still unregistered then
presents black and completes (see TechnicalDebt).
Uncharted: Legacy of Thieves Collection (PPSA05684) submits its first flip before registering its buffers and stopped with "flip buffer is not registered".
A title that opens a main and an overlay port flips both, and every flip
was presented as a whole frame, so the window alternated between the two
buses: PPSA01736 shows its intro on the main bus and an empty overlay,
and the intro blinked black on every other frame. Overlay flips now
complete and signal their events without being shown. Compositing the
overlay over the main output is not implemented.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Measured on a PS5 (firmware 13.60) through dlopen of
libSceVideoOut.sprx on a handle the payload opened.
sceVideoOutInitializeOutputOptions writes 0xFF to byte 2 of the 64-byte
options and returns INVALID_ADDRESS for a null pointer.
sceVideoOutIsOutputSupported checks the handle, then the reserved
arguments, then the mode, then the options. It never answers 0: a mode
the display lacks returns UNSUPPORTED_OUTPUT_MODE, and a value that is
not a mode returns 0x8029001E. Options must keep the initialized words,
except word 3.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
LibwuIonIBw registers video out event id 16, which the host never triggers because its VRR state does not change; kP2L8t3j-aM returns 0 without effect.
A flip still queued or in presentation when the title closes its port is discarded, as on hardware, rather than stored as a driver failure. A closed port no longer terminates the presentation thread nor surfaces from Shutdown. The lifetime test now expects cancellation and the reopen mode is registered in ctest.
Three homebrew titles from #1578 import it and stop at start-up without
it: ps5-opengl (PPSA99005), EVO-PLAYER-PS5 (PPSA99039) and
ProsperoRadio (PPSA99001).
It reports the port's resolution as the full and pane size and the
refresh rate ID as sceVideoOutGetOutputStatus does. The 48-byte layout
follows the declarations in ps5-opengl and EVO-PLAYER-PS5, which agree;
the screen size is 0 and the flags are 0. An invalid handle or a null
status throws, as in the other status getters.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The driver created a windowless Vulkan device at the first dispatch and
replaced it with a windowed one at the first flip. The replacement built a
second device and re-imported every host import, and the first flip paid
for it.
VideoOut now creates its window when it starts (the first VideoOut call),
at the default 1920x1080 output, and attaches it to the driver
(AgcDriverAttachWindow) before the call returns. The driver creates its
device with that window, so GPU work and presentation use one device.
Present no longer creates or replaces a device. A device created by GPU
work before VideoOut started is still replaced, now in AttachWindow.
A failure to create the window or the device is thrown from that first
VideoOut call instead of terminating the presentation thread.
Tests:
- video_out_flip_tests onedevice: GPU work, then a flip, leaves one device.
- pacing makes its first presentation span vblanks with GPU work queued
ahead of the flip; it relied on the device being created at the flip.
- unavailable expects the failure from sceVideoOutOpen.
- guest_video_out_wqhd_detection writes a param.json for the window title
and is skipped without a display or Vulkan device unless
ANYPS5_REQUIRE_DISPLAY is set.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Lets an open port report 2560x1440 output (resolution 4). The output
status here is 1080p or 2160p, so the call changes nothing it reports.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
sceVideoOutRegisterBuffers2 threw "DCC presentation is not implemented"
for category 1 (DCC-compressed) buffers, which PPSA26344 registers. Such
a buffer now needs DCC metadata and the tiled layout, and dcc_control may
only use the CB_DCC_CONTROL block layout bits 0x10026c.
At a flip the keys are read behind their recorded writers, one byte per
256 bytes as in the driver's DCC model. Uncompressed keys present the
stored texels as before; a uniform clear code presents its color with a
GPU clear of the scaler's source image; a pending storage image is used
when it serves the keys. Mixed or unreadable keys, clear codes the
display format has no DCC encoding for, register-clear keys over a
pending image and a clear color wider than 32 bits throw. Buffers
without DCC take the old path.
sceVideoOutRegisterBuffers2 and sceVideoOutSubmitChangeBufferAttribute2
threw for every buffer attribute option other than 0. PPSA26344 builds
its display buffers with option 8 through the libSceAgc helper linked
into it, so its first registration failed.
Option 8, VIDEO_OUT_BUFFER_ATTRIBUTE_OPTION_STRICT_COLORIMETRY (name
and value from KytyPS5), is now accepted and presented as option 0;
every other option still throws. What the console changes for it is
unknown and recorded in TechnicalDebt. The rejection now names the
tiling mode, pitch, aspect ratio and option it was given.
video_out_flip_tests decode checks that option 8 describes the same
buffer as option 0 and that options 1, 32 and 40 are rejected.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
and throws for any non-zero word after it. Its layout matches shadPS4's
ServiceThreadParams instead: an unknown first word (16), a set-priority flag
and a priority (256..767), a set-affinity flag and a 64-bit CPU mask at
offset 16. PPSA21564 passes 16, 1, 0x100, 1 and 0x1FFF, so it stops at
startup on main.
sceVideoOutOpen now validates each field and reads the mask only when its
flag is set, so a 16-byte param with both flags clear still works. The
priority and affinity are not applied, since the present and vblank threads
are host threads; this and the unknown first word are listed in the
technical debt.
Ten libSceVideoOut and two libScePad error constants had values that
belong to other errors of the same library (for example INVALID_HANDLE
was 0x80290003 and RESOURCE_BUSY / SLOT_OCCUPIED were swapped). They now
match KytyPS5, shadPS4 and fpPS4, which agree on all of them.
Co-Authored-By: Claude <noreply@anthropic.com>
Keyboard input follows libSceMouse: the video out event loop forwards SDL
key and focus events, whose scancodes are USB HID usages, and the library
keeps the pressed keys, modifiers and lock LEDs in a 16-entry history for
sceKeyboardRead and a snapshot for sceKeyboardReadState.
sceKeyboardGetKey2Char translates the 101-key arrangement; the 106-key
one throws and is listed as technical debt.
KeyboardData holds 16 key codes (96 bytes), not 6.
Co-Authored-By: Claude <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>
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.
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>
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>
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
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>