Commit Graph
50204 Commits
Author SHA1 Message Date
Henrik RydgårdandClaude Opus 5.5 16544a3bd3 Display: Don't call a flip listener after it's been removed
DisplayFireFlip() copied the listener list and called the copy without the lock, so a debugger
connection closing on its own thread could free its GPU stats subscriber while the CPU thread was
about to call it. Headless crashed (or hung) in WebSocketGPUStatsState::FlipListener() with
scripts that open a connection per command. Hold the lock across the calls, as LogManager does for
its callbacks, so __DisplayForgetFlip() returns only once the listener can't be running.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 18:19:21 +01:00
Henrik Rydgård 9c9eefa358 Merge pull request #22891 from hrydgard/adhoc-joiner-22886
Ad hoc: Fix NBA 2K13's joiner (scan list, relay self-connect, PtpFlush timing)
2026-11-02 17:55:51 +01:00
Henrik RydgårdandClaude Opus 5.5 ae2835838e Ad hoc: PtpFlush waits until the sent data would have reached the peer
On a PSP a non-blocking flush right after a send returns WOULD_BLOCK, and 0 once the data is in
the peer's buffer, about 4.5 ms plus 2.4 us per byte, and GetPtpStat counts the bytes as unsent
until then (pspautotests net/adhoc/pair/ptpflush). PPSSPP's flush returned 0 at once. NBA 2K13's
host sends the match info, flushes until it gets 0 and closes; with the instant flush it closed in
the same frame, and the joiner, which checks for a disconnect before reading, never read the last
chunk ("There was a problem transferring the match information").

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 17:04:03 +01:00
Henrik RydgårdandClaude Opus 5.5 7ee4cf67ea Ad hoc: Keep the scan list while connected
GetScanInfo returned nothing while in a group. On a PSP the list from the last scan stays after
Create, Join and Disconnect, and only a scan attempted while connected empties it (pspautotests
net/adhoc/pair/scaninfo, added here along with ptpflush). NBA 2K13's joiner looks for the group it
just joined in the list and leaves when it isn't there.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 17:04:03 +01:00
Henrik RydgårdandClaude Opus 5.5 38d94e02f2 Ad hoc relay: Refuse a PTP connect to yourself with no listener at once
A PSP refuses it immediately (pspautotests net/adhoc/ptp, "Connecting to nobody"), while the
relay held it for about 4 seconds before giving up. NBA 2K13's joiner connects to each entry of
its peer table in turn, itself first, and gave up on the group before it got to the host.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 17:04:03 +01:00
Henrik Rydgård ae21ead0d8 Merge pull request #22889 from hrydgard/input-latency
Android: Minor input and audio latency improvements
2026-11-02 16:49:06 +01:00
Henrik Rydgård ef6ca2a303 Merge pull request #22887 from hrydgard/fix-stencil-rebuild-cost
Reinterpret: Write the stencil from the source, in the same render pass
2026-11-02 15:48:41 +01:00
Henrik RydgårdandClaude Opus 5.5 0ad07d1560 Reinterpret: Write the stencil from the source, in the same render pass
Rebuilding the stencil after a reinterpret (89fabe21fb) copied the whole
destination to a temp buffer and redrew the stencil from it in a pass of its
own. Tantalus games reinterpret about 70 times a frame, and on an M1 with
Vulkan that made MX vs ATV Untamed 44% slower (GPU bound).

Now a stencil variant of the reinterpret shader reads the source the same way
the color reinterpret does and draws the stencil from its alpha, into the same
rectangle right after it, so it lands in the same render pass and needs no
copy. One draw with stencil export, otherwise a clear and one per alpha bit.

The 1141 dumps in ppsspp-framedumps render identically before and after, on
Vulkan (export) and OpenGL (per bit) on macOS. Split Second, OutRun and
Ultimate Ghosts 'n Goblins dumps go through this path.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 14:09:07 +01:00
Henrik RydgårdandClaude Opus 5.5 f1a76fde80 Docs: The Android version string no longer lags behind
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 09:24:33 +01:00
Henrik RydgårdandClaude Opus 5.5 32b67c0c55 CMake: Declare git-version.cpp as a byproduct of the GitVersion step
Ninja only knew git-version.cpp from its timestamp at the start of the
build, so when the GitVersion step rewrote it, the object wasn't rebuilt
until some later build happened to notice. An Android APK built right
after a commit could carry the previous commit's version string.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 09:24:03 +01:00
Henrik RydgårdandClaude Opus 5.5 9add5a78f3 Android: Report each frame's work to an ADPF performance hint session
Emulation does a burst of work each frame and then waits, so the scheduler
sees a mostly idle thread and moves it to slow cores at low clocks. On
Android 13+, report the frame thread's CPU time per frame against a target
of half a frame. CPU time leaves out the frame limiter's sleep and any
blocking on vsync or the GPU. Idea from Azahar.

Does nothing on devices without hint session support.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 09:04:26 +01:00
Henrik RydgårdandClaude Opus 5.5 445ecb46dc Android: Let Oboe pick the callback size, grow the buffer on underruns
setFramesPerDataCallback forced callbacks of PROPERTY_OUTPUT_FRAMES_PER_BUFFER
frames, which made Oboe add a block adapter holding back an extra buffer
whenever that doesn't match the burst. On a Galaxy S21 Ultra the MMAP stream
has a 96 frame burst against a 192 frame property. NativeMix takes any size.

The buffer was fixed at two bursts, 4 ms there, with nothing to recover from
underruns. Use Oboe's LatencyTuner, which starts at two bursts and adds one
per underrun, and log the underrun count when the stream closes.

Also take the lock when clearing the error and info strings.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 09:04:26 +01:00
Henrik RydgårdandClaude Opus 5.5 1d477fa248 Android: Request unbuffered dispatch of touch and joystick input
Android batches touch moves and joystick axis events until the next UI
vsync, up to a frame of latency. On API 30+, ask for them unbatched.
Non-pointer sources only apply to the focused view, so the surface view
now stays focused.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 08:52:24 +01:00
Henrik RydgårdandClaude Opus 5.5 5ea0921301 Ctrl: Let a press shorter than the sample interval be seen once
A press and release that both land between two sceCtrl samples were
lost. Now the next sample sees the button pressed. Idea from Azahar.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 08:52:24 +01:00
Henrik Rydgård fc9ca4d1f7 Merge pull request #22885 from Kethen/aemu_postoffice_enet
bump aemu_postoffice
2026-11-01 23:05:31 +01:00
Katharine Chui 274da28e09 hasten aemu_postoffice enet pumping
this is to address long retransmission delays
2026-11-01 22:44:59 +01:00
Katharine Chui 13efba30c6 bump aemu_postoffice
- various bug fixes
- allow disabling enet when creating relay and adhocctl server objects
- pdp_peek_next_size can now be used to check whether a pdp session has no packet or an upcoming 0 size packet
2026-11-01 22:43:24 +01:00
Henrik Rydgård d0cb768568 Merge pull request #22875 from hrydgard/misc-fixes
HLE: Media and IO fixes from the review branches
2026-11-01 19:11:07 +01:00
Henrik Rydgård 0525608cb7 Merge pull request #22881 from hrydgard/savestate-discid-mounts
Savestates: disc ID and named mounts; headless can boot a state as-is
2026-11-01 18:42:12 +01:00
Henrik Rydgård 44f1f44be7 Merge pull request #22883 from Rularia/ice-test
MIPSAnalyst: Add Koori no Bohyou (NPJH50186/ULJS00247) picking pass readback (Follow-up to #22514 and #22610)
2026-11-01 17:34:27 +01:00
Rularia cc99fb01a1 Koori: rsingle source-buffer readback 2026-11-02 00:14:34 +08:00
Rularia 906fc16170 Update ReplaceTables.cpp 2026-11-01 22:42:55 +08:00
Henrik RydgårdandClaude Opus 5.5 bf2c81e37d Headless: Don't save states while running from a state without its game
The game runs without its disc there, so a state saved from it would keep that broken
environment. Saves are refused, and so is --save-state together with a state to boot.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 15:41:23 +01:00
Rularia 70ab07755d Update ReplaceTables.cpp 2026-11-01 22:10:23 +08:00
Rularia 5c7632d99b Update MIPSAnalyst.cpp 2026-11-01 22:08:57 +08:00
Henrik Rydgård fb93fad41c Merge pull request #22880 from hrydgard/gamebutton-cleanup
GameButton code cleanup
2026-11-01 11:42:50 +01:00
Henrik Rydgård 7bbbe813e0 Merge pull request #22879 from hrydgard/dependabot/github_actions/actions/setup-java-6.1.0
build(deps): bump actions/setup-java from 6.0.1 to 6.1.0
2026-11-01 11:38:37 +01:00
Henrik RydgårdandClaude Opus 5.5 5c37b0d798 Headless: Count failed disc reads when booting a state, and benchmark such states
The count is opens of files missing from the disc, and reads and seeks on handles whose file
was dropped as the state loaded, from the load on. It tells how far a game booted without its
disc has strayed from its usual path. headless_bench.py takes bare .ppst files and directories
of them (--state-dir), and reports the count with the timings.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 11:15:35 +01:00
Henrik RydgårdandClaude Opus 5.5 8122a5ec70 Headless: Boot a savestate without its game
Running a .ppst boots a placeholder program, with the disc ID and boot type peeked from the
state, then loads the state over it. An ISO game gets a disc with nothing on it, which the
mounts now load into by name. Meant for measuring performance with states that can be kept
without the games; the app still refuses to boot a state.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 11:04:26 +01:00
Henrik Rydgård ec1246b221 Deduplicate text rendering code from GameButton 2026-11-01 10:49:59 +01:00
Henrik Rydgård b11a2b173e inline the image drawing functions 2026-11-01 10:29:43 +01:00
Henrik Rydgård ede471aee6 Merge DirButton into GameButton 2026-11-01 10:24:34 +01:00
Henrik RydgårdandClaude Opus 5.5 09f65a860c SaveState: Store what the game was booted from, and read a state's start without loading it
SaveStart (still version 6) also stores whether the game was booted from an ISO, a PBP, an
ELF or a disc directory. PeekBootInfo decompresses only the start of a state to read them with
the disc ID, so a boot from a state alone can be set up before the state is loaded.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 09:54:54 +01:00
dependabot[bot] ae7c593b87 build(deps): bump actions/setup-java from 6.0.1 to 6.1.0
Bumps [actions/setup-java](https://github.com/actions/setup-java) from 6.0.1 to 6.1.0.
- [Release notes](https://github.com/actions/setup-java/releases)
- [Commits](https://github.com/actions/setup-java/compare/v6.0.1...v6.1.0)

---
updated-dependencies:
- dependency-name: actions/setup-java
  dependency-version: 6.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-11-01 08:45:43 +00:00
Henrik Rydgård 3f5a79bfbc Simplify 2026-11-01 09:33:44 +01:00
Henrik RydgårdandClaude Opus 5.5 60dc6687f2 SaveState: Store mounts by prefix, with the size of each one's state
Mounts were stored by position with no size, so adding, removing or reordering one broke
every older state, or silently fed sections to the wrong filesystem. Now a load pairs them by
prefix, skips a mount it doesn't have, and leaves one the state doesn't have as it is. Older
states load as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 09:26:47 +01:00
Henrik RydgårdandClaude Opus 5.5 3f6b55ff53 SaveState: Store the disc ID and version, first in SaveStart
Fixed width, at the start of the first section, so the game a state belongs to can be read
without loading it, to boot from a state alone. A load into a different game is logged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 09:26:47 +01:00
Henrik RydgårdandClaude Opus 5.5 42d3206bcf Move GameButton out of GameBrowser.cpp into its own file
The icon-with-text drawing helpers and the large list dimensions move
with it, exported since DirButton uses them too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 00:06:19 +01:00
Henrik Rydgård 659e05c0a3 Merge pull request #22874 from hrydgard/mac-file-panel-sheets
Mac: Show file panels as sheets, and restore keyboard focus after them
2026-11-01 00:04:04 +01:00
Henrik Rydgård 77904479f9 Refactor work 2026-10-31 23:37:48 +01:00
Henrik RydgårdandClaude Opus 5.5 7004cdad0f sceIo: Check devctl 0x01F20003's output pointer
It checked the argument and wrote the UMD size to outPtr unchecked.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 22:59:11 +01:00
Henrik RydgårdandClaude Opus 5.5 06bcebffd0 IO: Fix sceReg overruns, savestate IO sync, small state bugs
- sceRegGetKeys looped to the requested count instead of the category's,
  reading past the key list, and its size check could overflow.
  sceRegGetKeyValue wrote an INT to a buffer smaller than 4 bytes, which
  the ByName variant already refused.
- Savestates now wait for async IO even while stepping, when a plain
  sync returned at once and a read in flight could land in the loaded
  memory.
- A bad POPS layout index in a savestate fails the load instead of
  indexing past the table.
- sceNpDrm's EDATA check stored ReadFile's s64 result in a size_t, so an
  error passed the length check. The PGD ioctl handed uninitialized
  stack bytes to pgd_open when the file was short.
- A negative chnnlsv key length from the guest context indexed before
  the key buffer.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-31 22:59:11 +01:00
Henrik RydgårdandClaude Opus 5.5 1c980fc104 Media: Fix size math, Atrac decoder state and the SAS race
- The ringbuffer's packets * packetSize went straight into the media
  engine's allocations. It's clamped to what a savestate can hold, and
  the put callback's return value is clamped before it sizes the
  validation demuxer. A ringbuffer with no packets no longer divides by
  zero.
- sceMpegAvcCsc with a range starting past the frame gave a negative
  width. sceMpegBaseCsc* reject a stride that overflows the size math,
  and the MJPEG output size could overflow 32 bits.
- MpegDemux clamps the header's stream offset, and doesn't push PES
  payload past what's been read. read16/read24/readPts relied on the
  unspecified evaluation order of | for their byte order. A negative
  stream offset made every later savestate fail to load.
- Atrac: DecodeForSas clamps the split packet so the second copy stays
  in the stack buffer. A zero frame size from the file is rejected
  before it's divided by. decodeTemp_ is reallocated when SetData
  changes the channel count. The standalone decoder only has buffers
  for two channels, so it clamps the count it's given.
  AtracSasBindContextAndGetID indexed with a negative ID and
  dereferenced a missing context.
- Psmf's player tempbuf path could read past the 64KB buffer from the
  stream table or EP map offset.
- sceMpegDelete didn't forget the context's PMP state, so a new context
  at the same address skipped the PMP codec setup and crashed.

Releasing an Atrac ID or setting its data now waits for a SAS mix in
progress, which can be decoding from it on the SAS thread.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-31 22:59:11 +01:00
Henrik Rydgård fd42bb6dcb Merge pull request #22873 from hrydgard/adhoc-size-timing
sceNetAdhoc: PDP, PTP and PollSocket: Time cost approximations
2026-10-31 22:50:45 +01:00
Henrik RydgårdandClaude Opus 5.5 fc2a33ba94 sceNetAdhoc: PDP and PTP sends and receives, and PollSocket, take longer the more they handle
pspautotests net/adhoc/sizes measures, roughly: PdpSend takes 50 us plus
20 ns a byte (to a peer, to everyone, to nobody or to itself), PdpRecv
of waiting data 15 us plus 11 ns a byte, PtpSend 95 us plus 70 ns a
byte, PtpRecv 25 us plus 12 ns a byte, and PollSocket 20 us plus 1 us a
socket. We charged 10-50 us whatever the size, and nothing at all for a
PdpSend to a MAC nobody has.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 22:26:55 +01:00
Henrik RydgårdandClaude Opus 5.5 bcd6d250e6 Mac: Restore focus after the file panel's sheet is gone
Logging after the panel closed showed the app still active but no key window,
so keys beeped until the window was clicked. Making the window key in the
completion handler doesn't stick (the sheet is still attached then), so do it
on the next runloop pass. The Dock bounce isn't needed, and only
[NSApp activate] is kept, for the case where the app did lose activation.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 22:25:05 +01:00
Henrik RydgårdandClaude Opus 5.5 cb121270bd Mac: Reactivate the app after a file panel, and drop input while one is up
Keyboard focus still didn't come back after a panel closed. The panel runs
out of process, and SDL's own Cocoa file dialog works around the same thing
by activating the Dock and then the app again, so do that too.

SDL handles input for its windows itself, so the sheet didn't stop clicks
and keys from reaching the UI under it. Drop presses and motion in
ProcessSDLEvent while a panel is open.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 22:18:50 +01:00
Henrik RydgårdandClaude Opus 5.5 7ed8e590ea Mac: Show file panels as sheets on the window, so focus returns to it
The open and save panels were run with runModal and no owner window, and
after one closed, focus didn't return to the SDL window. Attach them as
sheets to the key (or main) window instead, which also stops them from
blocking inside SDL's event pump.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 22:13:39 +01:00
Henrik Rydgård 45657cc9ba Merge pull request #22872 from hrydgard/inet-size-timing
sceNetInet: Send, receive, poll and select: time cost approximations
2026-10-31 22:00:15 +01:00
Henrik RydgårdandClaude Opus 5.5 7cee9c8065 sceNetInet: Send, receive, poll and select take longer the more they handle
pspautotests net/inet/sizes measures, roughly: a send over WiFi takes
125 us plus 40 ns a byte, a receive of waiting data 35 us plus 14 ns a
byte, and poll and select grow worse than linearly with the number of
sockets, from 13 us for one to about 700 us for 64. We charged a flat
4 us to receive, nothing to send, and 11-15 us to poll and select,
whatever the size. The costs are now rough functions of the bytes and
sockets, for all the send and receive calls including sendmsg and
recvmsg.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 21:38:50 +01:00