Commit Graph
16390 Commits
Author SHA1 Message Date
Henrik Rydgård 2816d6a409 Merge pull request #22818 from hrydgard/adhoc-arg-checks
Adhoc: Check function arguments more like the real thing.
2026-10-28 10:29:26 +01:00
Henrik RydgårdandClaude Opus 5.5 de175c7d03 proAdhoc: Say why MAC comparisons ignore the first byte
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 09:52:55 +01:00
Henrik RydgårdandClaude Opus 5.5 e0a6a662f4 sceNet, sceNetAdhoc: Cite the tests for behaviour that's the PSP's
Several comments called PSP behaviour a workaround for one game: PDP
send and receive returning 0 and writing the length back, Scan while
connected reporting ALREADY_CONNECTED, PtpOpen connecting by itself,
connecting a connected socket returning 0, PtpAccept's optional peer
address and port, the malloc stat's pool size, and matching dropping
hellos from a host mid-join. The pspautotests recorded on PSPs show the
PSP does all of these, so say that, and keep the games as examples.

Also bumps pspautotests for the new adhocctl Disconnect events and the
pair/matching3 test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 09:52:55 +01:00
Henrik RydgårdandClaude Opus 5.5 591cec315e sceNetAdhocMatching: Put the game workarounds behind compat flags
CancelTarget on a MAC that isn't a peer, and Start on a context ID that
doesn't exist, faked success for every game. On the PSP they fail with
UNKNOWN_TARGET and INVALID_ID (pspautotests net/adhoc/matching). Only
the games they were added for keep them now:
MatchingCancelUnknownTargetSucceeds for Soulcalibur: Broken Destiny, and
MatchingStartUnknownIdSucceeds for GTA: Vice City Stories.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 09:52:40 +01:00
Henrik RydgårdandClaude Opus 5.5 011f6b1d98 sceNetResolver: Work without sceNetResolverInit, like the PSP
On a PSP, Create, lookups, Stop and Delete all work before Init and after
Term, and a second Init fails with 0x80000020 (pspautotests
net/inet/offline). Instead of starting out initialized, which Outrun 2006
needed, drop the init requirement, so every game gets the PSP's
behaviour.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 09:52:22 +01:00
Henrik RydgårdandClaude Opus 5.5 03076115bd sceNet, sceNetApctl: Check arguments like the PSP
From pspautotests net/inet/offline, recorded on a PSP:

- sceNetGetMallocStat(NULL) gives 0x80410103, and sceNetThreadAbort and
  sceNetFreeThreadinfo on something that isn't a thread 0x80410104.
- sceNetApctlAddHandler takes two handlers (the internal handler calls
  aren't limited), DelHandler tells an impossible ID (0x80410A82) from a
  free one (INVALID_ID), and GetState(NULL) and
  GetBSSDescIDListUser(NULL size) give 0x80410A03. A NULL buffer in
  GetBSSDescIDListUser asks for the size instead of failing.

GetState before Init and GetInfo while disconnected still succeed: the
first check was disabled on purpose at some point, and the simulated
infrastructure connection relies on the second.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 09:52:22 +01:00
Henrik RydgårdandClaude Opus 5.5 8a48a157d4 sceNetResolver: Don't fault on a NULL address, and check arguments
sceNetResolverStartNtoA with a NULL address pointer wrote to address 0
and stopped the game. From pspautotests net/inet/offline, recorded on a
PSP: a NULL name or address gives INVALID_PTR, an empty name 0x80410418,
a NULL buffer in Create INVALID_PTR, and Stop with nothing running
ALREADY_STOPPED (the check was inverted). PollAsync and WaitAsync check
the resolver ID, and PollAsync its status pointer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 09:52:22 +01:00
Henrik RydgårdandClaude Opus 5.5 0904b47639 sceNetAdhocMatching: Check arguments like the PSP
From the net/adhoc/matching and limits pspautotests, recorded on PSPs:

- Create: a bad mode gives INVALID_MODE, rxbuflen has to be at least
  6 * maxnum + 4, host and P2P contexts need nonzero hello and keep-alive
  intervals, init_count can't be negative and rexmt_int can't be 0. At
  most 15 contexts exist at once.
- Start on a running context gives IS_RUNNING. Start2 takes each
  thread's partition after its stack size, not before.
- Stop and Delete on unknown IDs give INVALID_ID, and Delete on a running
  context IS_RUNNING (internal cleanup still stops and deletes).
- GetHelloOpt fails before Start, copies at most the game's buffer and
  leaves the length alone. It used to write the whole hello past the
  buffer.

CancelTarget on an unknown peer still succeeds, as Soul Calibur needs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 09:52:22 +01:00
Henrik RydgårdandClaude Opus 5.5 58d73cbbc6 sceNetAdhoc, adhocctl: Check arguments like the PSP
From the net/adhoc pspautotests (pdp, ptp, poll, limits, adhocctl,
gamemode), recorded on PSPs:

- PDP and PTP: NULL pointers and nonzero flags give INVALID_ARG, before
  the socket ID is checked. Zero and multicast addresses give
  INVALID_ADDR, ports 0 and 65535 INVALID_PORT, and send lengths over
  65523 or NULL data INVALID_DATALEN. A length of 0 sends nothing and
  succeeds. Zero buffer sizes, retransmit settings and backlogs are
  accepted. PdpRecv takes a NULL sender address or port. Running out of
  socket IDs gives SOCKET_ID_NOT_AVAIL, and out-of-range IDs on
  delete/close INVALID_SOCKET_ID. PollSocket rejects flags other than
  NONBLOCK.
- adhocctl: Init checks its stack size, priority and ad hoc ID;
  AddHandler needs Init, allows the same function twice and takes at most
  4 handlers; DelHandler on an unknown ID gives ID_NOT_FOUND; bad group
  names give adhocctl's INVALID_ARG; GetParameter and GetPeerList fail
  outside a group.
- Game mode: a NULL group name and a bad minimum are rejected,
  GetGameModeInfo fails outside game mode, and the entry timeout reports
  adhocctl's TIMEOUT.

The DBZ Shin Budokai 2 workaround that replaces the game's local MAC with
ours stays, so another console's MAC is still accepted when creating a
socket.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 09:52:22 +01:00
Henrik RydgårdandClaude Opus 5.5 79537d18bd sceNetInet: errno per thread as on hardware, and the socket table
errno:
- A thread that hasn't made a call yet reads 0x80410001 from GetErrno,
  as the PSP has no errno record for it until then. errno is saved in
  savestates now, in a new sceNet section version.
- socket(), close() and setsockopt() clear it when they succeed.
- Running out of descriptors is EMFILE, at 255 like the PSP, and an
  unconnected UDP socket sending without an address EDESTADDRREQ, which
  Winsock calls ENOTCONN.
- On Windows, ENOBUFS, EPROTOTYPE, ENOPROTOOPT, EMSGSIZE, ENETRESET and
  EDESTADDRREQ now map to the PSP's errnos. They only did elsewhere.
All from pspautotests net/inet/errors, options and errnothread.

The socket table:
- Descriptor numbers are handed out round-robin up to 255, as on the PSP
  (net/inet/states), rather than the lowest free one.
- Closing frees the slot even if the host's close fails, and Close and
  CloseAll take the lock the rest of SocketManager does.
- accept no longer leaks the host socket when it runs out of numbers.
- bind no longer asks UPnP to forward port 0, and closing the socket
  removes its forward, unless another socket still uses the port.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 09:50:48 +01:00
Henrik RydgårdandClaude Opus 5.5 5610c9ff9b sceNetInet: Validate arguments, failing with errno set
Bad arguments now fail the way the PSP fails them, with -1 and errno
set, rather than reaching the host or returning something else:
- A descriptor that isn't open is EBADF. The result used to be EBADF's
  number, 9, which looks like success (pspautotests net/inet/errors).
- Buffers and addresses the host reads or writes directly are checked to
  lie in game memory, failing with EFAULT, rather than letting a host
  recv or send run past the end of it.
- socket() with anything but an AF_INET TCP, UDP or raw socket, with a
  protocol that fits, is EPROTONOSUPPORT (net/inet/errors).
- bind with an address shorter than 16 bytes is EINVAL, and with another
  family than AF_INET EADDRNOTAVAIL (net/inet/errors).
- shutdown with a how other than 0-2 is EINVAL (net/inet/states).
- sendto with an address shorter than 16 bytes is EINVAL, which Winsock
  calls EFAULT, and Sendmsg with any control data, or a short address,
  EINVAL (net/inet/msg).
- poll reports a negative fd as POLLNVAL like any other that isn't open,
  rather than failing (net/inet/polledge).

The pspautotests update brings in the new net/inet tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 09:02:20 +01:00
Henrik Rydgård 302e408069 Merge pull request #22817 from hrydgard/play-crash-fixes-3
Fixes for crashes from the 1.20.5 beta Play reports: savedata list count, GL startup race
2026-10-27 23:07:17 +01:00
Henrik Rydgård 5c84203bbe Merge pull request #22512 from hrydgard/inet-select-wait
sceNetInet: Wait in emulated time instead of blocking the host
2026-10-27 22:17:24 +01:00
Henrik RydgårdandClaude Opus 5.5 ad9c65ae39 EmuThread: Run the graphics context's ThreadStart before starting the emu thread
On OpenGL the render thread's ThreadStart fills in the GL strings and
picks the buffer strategy, while the emu thread, started just before
it, could already be in NativeInitGraphics reading them. A Play report
crashed walking the strings map in BuildReportingInfo. ThreadStart also
resets the exit flags, which could undo an early exit by the emu
thread. Libretro already starts its emu thread in this order.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 22:11:09 +01:00
Henrik RydgårdandClaude Opus 5.5 e10ebbeb44 Savedata: Keep the list count at 0 when a name in the list is rejected
The multi-name path counted names straight into saveDataListCount, so
returning on a path traversal name left a count behind with the list
already freed by Clear(). The next savestate then serialized that many
entries from a null list and crashed in Do(std::string). Count on the
side, and don't write entries for a list that isn't there.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 22:04:45 +01:00
Henrik Rydgård 476d020c58 Merge pull request #22810 from hrydgard/custom-driver-options
Implement support for setting two common driver flags for Turnip (custom Adreno driver)
2026-10-27 18:03:09 +01:00
Henrik RydgårdandClaude Opus 5.5 a4fe8e8f17 sceNetAdhoc: Don't fault on NULL pointers the PSP accepts
sceNetAdhocPdpSend with NULL data and a length of 0, sceNetAdhocPdpRecv
with a NULL sender MAC or port, and sceNetAdhocPtpSend with a NULL length
pointer all raised a memory exception before the call ran, which stopped
the game. On a PSP the first two succeed and the last returns INVALID_ARG
(net/adhoc/pdp and net/adhoc/ptp in pspautotests).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 17:13:45 +01:00
Henrik RydgårdandClaude Opus 5.5 6056ec419a Headless: Run several instances that talk to each other over ad hoc
--instance=N sets PPSSPP_ID, so each instance gets its own 127.0.0.N address
and MAC; headless left it at 0, which made its address 127.0.0.0.
--realtime keeps emulated time from running ahead of the wall clock. Only
display flips paced headless, and a test that doesn't draw never flips, so
two instances waiting for each other over the network timed out at once.
--adhoc-server runs the built-in ad hoc server.

Tools/adhoc_multi.py runs a multi-console pspautotest (X_host, X_client,
X_client2, ...) on one instance per role, with the built-in server or, with
--relay, a local aemu_postoffice in relay mode.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 17:13:45 +01:00
Henrik RydgårdandClaude Opus 5.5 bd56e07bb0 sceNetInet: Fix the blocking socket waits on Windows
Headless only started Winsock (net::Init) for the debugger, so on Windows
every socket call failed with WSANOTINITIALISED. Start it always.

Winsock's select() fails on empty sets, where POSIX waits out the timeout, so
a select() used as a sleep (the VSH's Skype) returned an error at once. With
no host sockets to check, select and poll now just report nothing ready.

Look up host sockets without GetHostSocketFromInetSocket, which asserts on a
socket closed while a call waits for it, and whose -1 can't be caught with
< 0 on Windows, where SOCKET is unsigned.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 17:04:09 +01:00
Henrik RydgårdandClaude Opus 5.5 be9383c08f sceNetInetPoll: The timeout is in milliseconds
Like POSIX poll(), as pspautotests net/inet/blocking shows. We took it as
microseconds, so every poll timeout was a thousand times too short.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 17:03:59 +01:00
Henrik RydgårdandClaude Opus 5.5 22e0a1a536 sceNetInet: Wait for blocking socket calls in emulated time
Host sockets are always non-blocking, so a game's blocking recv(), accept()
and so on came back with EAGAIN at once, and connect() and poll() blocked the
whole emulator in the host call instead. Now recv, recvfrom, send, sendto,
accept, connect, poll and select try once, and if the call would block on a
blocking socket (no SO_NBIO or MSG_DONTWAIT), the thread waits and a
CoreTiming event retries it every millisecond. It ends when the call completes
or fails, or when SO_RCVTIMEO/SO_SNDTIMEO runs out in emulated time.

Sockets accepted on Linux are made non-blocking too: unlike BSD and Windows,
Linux doesn't pass that on from the listening socket. select() rejects a
tv_usec of a second or more with EINVAL.

Hardware behaviour from pspautotests net/inet/blocking.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 17:03:59 +01:00
Henrik RydgårdandClaude Opus 5.5 72a0cd1879 sceNetInetSelect: Wait in emulated time instead of blocking the host
select() ran on the CPU thread with the guest's timeout (5.5 seconds when it
gave none), so the whole emulator stopped for as long as it waited. The VSH's
Skype uses select() with no sockets as a sleep, 0.65-0.95 s at a time, and ran
at a crawl: almost no emulated time passed, and the UI barely moved.

Now the sockets are checked without blocking. If none is ready, the thread
waits and a CoreTiming event polls again every millisecond until one is, or
the timeout runs out in emulated time. A null timeout now waits for as long as
it takes. Pending waits are saved in savestates.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 17:02:03 +01:00
Katharine Chui 262416ad90 fix adhocctl regression by restoring wrongly removed logic
- 23efd22efb : Fix Stuck issue on some games (Dissidia 012, Full Auto 2, etc) when Failed to connect to Adhoc Server (faked success)
- 7ec860c24f : Adhoc: Stop waiting for a login that has already failed
2026-10-27 15:02:04 +01:00
Henrik Rydgård 2ee1a0bea7 Merge pull request #22811 from hrydgard/misc-logic-fixes
Misc logic fixes from a Claude code review
2026-10-27 12:35:59 +01:00
Henrik Rydgård 176f56da8d Implement support for setting two common driver flags for Turnip (custom Adreno driver)
enable_tp_ubwc_flag_hint and storage_8bit are now available as check
boxes on the driver setup screen.

Fixes #22808
2026-10-27 12:16:25 +01:00
Henrik RydgårdandClaude Opus 5.5 4c7dd44351 TextDrawer: Remove the current font and scale
Drawing now takes the style and scale too, like measuring, so the text
drawers have no font state left. UIContext keeps its current style and
passes it, and fills it in from the theme if nothing has set one yet.
PPGe passes its one font.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 11:54:10 +01:00
Henrik RydgårdandClaude Opus 5.5 561badca05 sceAudio: Check sceAudioInput's arguments and routing modes like the PSP
pspautotests audio/sceaudio/input and audio/sceaudio/routing.

- sceAudioInput fails until sceAudioInputInit, then checks that the
  sample count is a nonzero multiple of 64 before checking the rate
  (11025, 22050 or 44100 only). A rate of 0 now gets the PSP's error
  instead of the USB mic's. Init takes about 3ms.
- A blocking mic input woke with the byte count rather than the sample
  count that the non-blocking call returns.
- The routing functions are exported by both sceAudio and
  sceAudioRouting, and the latter had its own copy that ignored the
  stored modes. Both now share the one in sceAudio, with the ranges
  checked. SetVolumeMode returns 0, not the previous mode, and both
  modes start at 0.

sceAudio's savestate section goes to version 5 for the input init flag.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 10:56:46 +01:00
Henrik RydgårdandClaude Opus 5.5 3880999ada Misc HLE: Fix heap leak, USB waits, RNG indices and small races
- sceHeapDeleteHeap never freed the heap's memory. Allocation failure
  returned -1 rather than a null pointer, and a near-4GB size wrapped.
- The USB wait timeout resumed threads that were no longer waiting on
  USB, and UsbUpdateState resumed them too, and never rescheduled.
- The Mersenne Twister drew from mt_[index_] with the index taken from
  guest memory. It's now taken modulo the state size. sceSfmt19937
  checks its index, and that fill arrays are at least a state long,
  which the library writes regardless of the length it's given.
- sceCccEncodeUTF16's surrogate test also caught U+F800 - U+FFFF, which
  includes the fullwidth forms.
- sceAudioRoutingSetVolumeMode stored the routing mode.
- A sample rate of 0 to sceAudioInput or the camera mic divided by zero,
  and a huge sample count sized a host buffer. sceP3daBridgeCore's sizes
  could wrap. sceRtc's tz offset could overflow tm_min.
- Camera shutdown freed the frame buffer and config without the lock
  the capture thread uses. GPS data is set from the platform's location
  thread, so it's now locked too, and the satellite index is bounded.
- A loop in the sys event handler list hung the unregister.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-27 10:39:45 +01:00
Henrik RydgårdandClaude Opus 5.5 0b30638e65 HLE: Fix SAS thread wakeup, SAS raw output size, ME and syscon bounds
- The SAS thread waited without checking the state first, so a mix
  queued before it got to the wait was missed, and the next drain hung.
  The state is now atomic too.
- SAS raw output mode writes four planes, twice the size it asked for.
- DMACplus colour conversion with a huge stride overflowed its size
  math. The syscon serial data index wasn't bounded on reads, writes or
  load.
- Replace_memcpy_swizzled copies whole 16x8 blocks, more than the
  pitch * h it asked for. The God Eater depth hook tested the color
  buffer twice instead of the depth buffer, and its size could wrap.
- GranularMixer used 1/0 before the first FPS sample, and read the
  granule being written next when the queue was empty.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-27 10:38:32 +01:00
Henrik Rydgård 57161a245e Merge pull request #22803 from hrydgard/more-ui-work
DisplayLayoutScreen layout tweaks, fix sceImpose "HOME" screen issues
2026-10-27 09:53:02 +01:00
Henrik Rydgård 81a7c7e78c Code cleanup, logging improvement 2026-10-27 09:32:52 +01:00
Henrik RydgårdandClaude Opus 5.5 455209b43e Net: Fix use-after-pop, the resolver after loads, inet sockaddr/poll
- The apctl, NpAuth and NpMatching2 event loops kept references to the
  front of their deque after popping it, so callbacks could get the
  next event's arguments. NpMatching2 also dereferenced its optional
  opt param when it was null.
- The resolver was left stopped after any savestate load or reboot,
  which broke Outrun 2006 (it relies on it starting out running).
- Getpeername/Getsockname with a namelen under 2 copied a negative size.
  They now write the PSP's 16-byte sockaddr truncated to namelen, with
  sa_len 16, as pspautotests net/inet/poll shows on hardware.
- Poll handed an fd that isn't open (-1) to FD_SET. It now reports
  POLLNVAL for it and counts it, as on hardware (net/inet/poll).
  Setsockopt read past a local u32 for larger options, and passed a
  negative optlen to the host. A zero cmsg_len looped forever.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 08:43:28 +01:00
Henrik RydgårdandClaude Opus 5.5 e9fa393546 Kernel: Match GetModuleIdList and heap allocation to hardware
pspautotests modules/idlist shows that sceKernelGetModuleIdList still
writes a partial entry at the end of the buffer (a size of 6 gives two
entries), which the previous commit had stopped. A NULL buffer or a
negative size returns ILLEGAL_ADDR without writing the count.

sysmem/kernel/heap shows sceKernelAllocHeapMemory returning null for
sizes near 4GB, rather than wrapping. The WithOption variant already
checked this. The plain one now does too.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-26 22:05:55 +01:00
Henrik RydgårdandClaude Opus 5.5 22b6fcbf22 Kernel: Fix sysclib strchr/strrchr, TLS pool leak, FPL counter
- sysclib strchr/strrchr searched for the whole string, not the
  character, so they returned 0 for any nonzero c.
- A thread ending with blocks from more than one TLS pool leaked every
  other block, since the restarted loop's ++iter skipped an entry.
- FPL's nextBlock grew by up to numBlocks per allocation and eventually
  overflowed into a negative block index. Old states with a negative one
  now reset it rather than failing to load.
- sysclib strncpy bounded its copy by the source's valid size only, not
  the destination's.
- sceKernelAllocHeapMemory wrapped for sizes near 4GB, and
  sceKernelGetModuleIdList could write a partial entry past the buffer
  size and dereferenced a missing module.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-26 21:42:06 +01:00
Henrik RydgårdandClaude Opus 5.5 210be3b311 Savestate: Keep MipsCall actions of type 0
Action type IDs start at 0, and the first one registered is
ActionAfterMipsCall, but MipsCall::DoState used 0 to mean no action.
So every call made with __KernelCallAddress lost its action chain on
load: the thread's wait state was never restored when the call
returned, and chained actions never ran.

Version 2 of the section marks a missing action with -1.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-26 20:13:59 +01:00
Henrik Rydgård 85f9d8985b Merge pull request #22797 from hrydgard/ui-naming-translations
Translation sweep: missing strings, wrong categories, and a langtool scanner
2026-10-26 17:54:26 +01:00
Henrik RydgårdandClaude Opus 5.5 1b60f76e58 Translate error messages once, from keys the source names
GameManager translated install errors when storing them, and the install
screens then looked the translated text up again as a key. It now stores the
category and key, and translates when asked. The raw ISO install error gets
the existing "Installation failed" string.

Some other errors went around as strings that were then used as keys:
- A missing savestate file now has its own error code, ERROR_FILE_MISSING,
  instead of a key in the failure reason.
- The PKG reader's reasons are technical English, so they're now shown
  untranslated under the translated "This PKG file isn't a PSP game update".
- The netconf dialog looked up the channel number. Only "Auto" is translated
  now, using the WLAN Channel setting's string.
- Adds the missing "Failed to read old directory" for memstick moves.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-26 17:04:20 +01:00
Henrik RydgårdandClaude Opus 5.5 097f5e7023 Lang: Fix the wording of some UI strings
The MIPSTracer page's "log file" is the trace file, and some strings had odd
spacing, grammar or capitalization. The auto load savestate toast now uses the
setting's key instead of a duplicate one, and the English fallbacks in code
match en_US.ini.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-26 16:41:12 +01:00
Henrik RydgårdandClaude Opus 5.5 a2170728f5 UI: Look up strings in the sections where they're translated
These were looked up in a different section from the one with the translation,
so they always showed in English (the savedata error messages, "Done!" after
moving the memstick, "Switch UMD", "Ask for network permission" and others).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-26 16:20:03 +01:00
Henrik RydgårdandClaude Opus 5.5 c1f9f77a9e Fix Core.vcxproj.filters, broken by the POPS boot commit
0b1e1a9bb3 put the PopsMMIO entries inside the MeMMIO ones, leaving
unclosed tags, so Visual Studio couldn't load the filters. Also adds
the missing Util\KL4E.h.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-26 15:11:29 +01:00
Henrik Rydgård 17a61343d1 Merge pull request #22792 from hrydgard/more-ui-fixes
Settings: General tab, pause screen save state refresh, UI polish
2026-10-26 12:59:33 +01:00
Henrik Rydgård fe76beb04e Merge pull request #22789 from LunaMoo/xmb-home-exit
Xmb home exit
2026-10-26 12:59:17 +01:00
Henrik Rydgård e443e84d3c sceHprm: Write zeroes to the latch buffer in sceHprmPeekLatch too
We don't support the headphone remote buttons, so we just leave
the buffer all zeroes. Previously we didn't write, which could cause
games to register a ghost "track forward" or the other buttons.

Should fix the DJ Max 2 OST track-forwarding problem in #7468.
2026-10-26 12:46:31 +01:00
Henrik Rydgård 4cb7ddb50c More misc UI polish 2026-10-26 12:10:10 +01:00
Henrik RydgårdandClaude Opus 5.5 0ce79d4d7a Pause screen: Update the save state slots when a save finishes writing
Saves are written on a worker thread, so a state saved just before opening the pause
menu may not be on disk yet when the slots are listed, and the slot stayed empty.
Post SAVESTATE_SLOT_SAVED when a slot save is written, and recreate the pause
screen's views on it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-26 11:49:44 +01:00
LunaMooandClaude Opus 5.5 90cea302b9 HOME button quit screen, with the firmware's art when available
As on a PSP: pressing HOME in a game shows "Do you want to quit the game?"
over it. The game keeps running but gets no input while it's up (sceCtrl
samples are blanked). Left/right picks Yes or No, the confirm button (our
Confirmation button setting, or what compat forces) chooses, the other face
button or HOME closes it, and Yes/No can be tapped. The volume keys change
the game volume a step at a time, shown on the volume bar.

Yes runs the game's registered exit callback first, like the PSP does,
showing "Please wait..." meanwhile. Then, if the XMB launched the game, the
XMB is booted again; otherwise it's back to the game browser, like Exit to
menu. If the callback hasn't ended the game in 10 s, it's quit anyway. Not
in the XMB itself, the PS1 emulator (its own HOME menu) or GE dumps.

It lives in UI/ImposeHome.cpp; EmuScreen only feeds it input and frames and
draws it over the PSP display.

With a firmware dump installed, it's drawn with the firmware's own art from
flash0:/kd/resource/impose.rsc, which is what impose.prx draws it from:
prerendered text for each system language (the question, Yes/No normal and
highlighted, Enter/Back, Please wait...), the button icons, the lines, the
volume bar, the battery and the clock glyphs. The format is documented in
ImposeHome.cpp. Without one, the same screen is drawn with our font and
simple shapes at the same positions.

Where impose.rsc doesn't say where things go, the layout follows
impose_02g.prx (6.61), decrypted and disassembled:
- The screen is filled with 0x9CE7 (#393939); the images are opaque.
- Lines at (80, 96) and (80, 175); impose.prx grows them from the middle
  when it opens, which isn't done here.
- Volume bar: the speaker at (28, 223), 30 steps from x 62, 12 apart. It
  shows our game volume in the PSP's 30 steps.
- Button guide: the cross icon always left, the circle right, "Enter" and
  "Back" next to whichever confirms and cancels.
- Status bar: the battery at (450, 5) (60% and up full, 30% two bars, 12%
  one, then empty), the clock ending next to it at y 5: "M/D H:MM", or
  "D/M" for the DD/MM/YYYY format, no leading zero on the month, day or
  hour, AM/PM for the 12-hour clock.

The clock is the emulated PSP's local time (__RtcGetCurrentLocalTime, new),
in the system's date and time formats. The battery is this device's, since
the emulated PSP's is always full; a device without one shows it full.
For that, Windows now reports -1 for SYSPROP_BATTERY_PERCENTAGE without a
battery (was 100), as SDL already did; SDL polls the battery even when the
status overlay doesn't show it, and the overlay leaves it out when there's
none.

Core side: __CtrlSetGameInputBlocked; __KernelCanExitToVSH and
__KernelRequestExitToVSH to quit to the XMB from outside a syscall; and
__KernelInvokeRegisteredExitCallback(toVSH), so a callback that returns
without exiting ends in the XMB rather than powering down.

New strings: "Do you want to quit the game?", "Please wait..." (Dialog).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NB244iFpvm14JH2FbwHXeQ
2026-10-26 11:39:48 +01:00
Henrik Rydgård 3aec770b22 Set Auto rotation to default, move more settings around. 2026-10-26 11:36:59 +01:00
Henrik Rydgård 29b690eebf Merge pull request #22786 from LunaMoo/umd-inserted-reset
UMD: Put the disc back in the drive on every boot
2026-10-25 23:00:56 +01:00
Claude 66422a6123 UMD: Put the disc back in the drive on every boot
The XMB ejects the disc when it boots without one, and __UmdInit resets
the rest of the UMD state but not UMDInserted. So after visiting the XMB,
any game booted next saw an empty drive and waited forever for its disc
(Brandish: The Dark Revenant stops after registering its UMD callback),
until PPSSPP was restarted.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 22:29:54 +01:00
Henrik RydgårdandClaude Opus 5.5 d0e3141f43 FFmpeg: Vendor what PPSSPP uses into ext/ffmpeg, drop the submodule
The ffmpeg submodule held prebuilt libraries for every platform next to the
sources (about 1.5 GB checked out), and nothing uses those any more. Only the
needed sources are copied in, from the submodule's commit, along with every
header and template they include. The path is new, so checking out commits on
either side of this works.

It's also cut down to what PPSSPP uses: the H.264, AAC, MP3, ATRAC3 and ATRAC3+
decoders, the H.264 parser, the demuxers as before, and the FFV1 encoder, AVI
muxer and file protocol for AVI dumping. config.h takes its CONFIG_ values from
FFmpeg 3.0.2's own configure run with just those enabled. The raw H.264 demuxer
stays even though nothing opens raw H.264: probing PSMF data uses it to identify
the video stream's codec, which otherwise comes out as none.

On top of that:
- The files nothing links (configure would build them, but they're never pulled
  out of the static library, going by the GCC link map) are left out: mostly
  libavutil's crypto and hashing and the alternative DCT/IDCT/FFT versions.
- libswresample isn't built, now that nothing uses it.
- The H.264 decoder only does 8-bit video, which is all the PSP has. The SPS
  parser rejects any other bit depth, and the DSP files no longer build their 9-
  to 16-bit variants, which the linker kept because the init functions pick one
  by bit depth at run time.

That's 160 files to compile instead of 277, and 391 of FFmpeg's vendored, about
5.8 MB. The README in ext/ffmpeg has what was done, the PPSSPP patches in the
copy, how to add a component, and the tradeoffs.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-25 22:27:54 +01:00