Commit Graph
48780 Commits
Author SHA1 Message Date
Henrik RydgårdandClaude Opus 5.5 b58dd17c2e iOS: Show paths in the app's container as ~/...
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 01:52:48 +02:00
Henrik RydgårdandClaude Opus 5.5 bfdf532965 CI: Build the tvOS app and the iOS and tvOS libretro cores
Adds b-tvos.sh and b.sh --tvos.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 01:15:41 +02:00
Henrik RydgårdandClaude Opus 5.5 3a8a1799ee Add a tvOS build of the app
Shares the iOS frontend, with camera, location, motion, photo/document
pickers, share sheet, clipboard, microphone, battery and rotation compiled
out. The view controller is a GCEventViewController, so controllers only
reach us through GCController, and the Siri Remote is read as a micro
gamepad and sent as arrow/enter/escape/back keys. tvOS has no persistent
storage besides NSUserDefaults, so the memory stick lives in Caches for now.

Configure with -DIOS_PLATFORM=TVOS. The MoltenVK submodule gets the tvOS
slice from the same stock v1.4.2 release.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 01:06:55 +02:00
Henrik RydgårdandClaude Opus 5.5 20d1a58806 CMake: Only build FreeType along with AtlasTool, its only user
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 01:06:09 +02:00
Henrik RydgårdandClaude Opus 5.5 7c9765d02c Add PPSSPP_PLATFORM(TVOS), skip sigaltstack on tvOS
tvOS doesn't have sigaltstack, which broke the libretro tvOS build. The
exception handler now runs on the faulting thread's stack there.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 00:42:33 +02:00
Henrik Rydgård dd6bd1a53d Merge pull request #22529 from hrydgard/android-hidden-bar-insets
Android: Don't leave room for system bars we have hidden
2026-10-12 21:59:03 +02:00
Henrik Rydgård 503b36bf5a Merge pull request #22531 from hrydgard/libchdr-no-warnings
Windows: Turn off annoying compiler warnings in dependencies
2026-10-12 21:58:52 +02:00
Henrik Rydgård fe018ee1e9 Merge pull request #22533 from hrydgard/search-backspace-utf8
Type-to-search: UTF-8 character support, ignore § and other Latin-1 symbols
2026-10-12 21:58:40 +02:00
Henrik Rydgård 4a00ee7667 Merge pull request #22532 from hrydgard/mac-drag-drop
SDL: Boot a file dropped onto the window
2026-10-12 21:58:27 +02:00
Henrik RydgårdandClaude Opus 5.5 671b6ce397 Type-to-search: Backspace removes a whole UTF-8 character, ignore § and other Latin-1 symbols
Backspace popped a single byte, leaving half of a multi-byte character behind.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 21:30:32 +02:00
Henrik Rydgård 4c48f85664 Merge pull request #22527 from hrydgard/vulkan-prerotate-270
Android: Pre-rotate reverse landscape on Vulkan again, fix insets for hidden bars
2026-10-12 19:45:55 +02:00
Henrik Rydgård b947316f4b Merge pull request #22528 from hrydgard/darwin-memory-reserve
Darwin: Reserve space for the memory views instead of probing for it
2026-10-12 19:45:43 +02:00
Henrik RydgårdandClaude Opus 5.5 ac8b4c31b3 SDL: Boot a file dropped onto the window
SDL3's Cocoa window already accepts file drags (as do the other SDL
video drivers), we just never handled SDL_EVENT_DROP_FILE.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 19:41:38 +02:00
Henrik RydgårdandClaude Opus 5.5 b230f0f7ca Windows: Turn off warnings for libarmips and glslang
Same as libchdr: they're submodules we don't patch.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-12 19:27:19 +02:00
Henrik RydgårdandClaude Opus 5.5 b8dfcef597 Windows: Turn off warnings for libchdr
It's a submodule we don't patch, and at /W4 it produced a wall of
conversion warnings in every build.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-12 19:25:26 +02:00
Henrik RydgårdandClaude Opus 5.5 60c06d4f03 Darwin: Reserve space for the memory views instead of probing for it
On iOS, the base search stepped up from 0x100000000 in 8MB increments,
right through the app's binary and early heap: about 100 failed
vm_remaps (each logged twice) every time a game started. On macOS,
Find4GBBase freed its probe allocation before the views were mapped.

Now the kernel picks a free range of exactly the span the views need,
which stays reserved and inaccessible, and the views are mapped over it
with VM_FLAGS_OVERWRITE. One try, no race, and the gaps between views
fault. Unmasked (macOS), ask for 4GB alignment first, which lets the
ARM64 JIT pointerify. The old search remains as a fallback.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 19:08:03 +02:00
Henrik RydgårdandClaude Opus 5.5 4daa789c5e MemMap: Fix the view index in Memory_TryBase's cleanup loop
It checked views[i], the view that failed, instead of views[j], so after
a failed try it could release views it should skip, or skip ones it
should release.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 19:08:03 +02:00
Henrik RydgårdandClaude Opus 5.5 3afb17f7d4 Android: Don't leave room for system bars we hid
Before Android 11, decorFitsSystemWindows(false) sets LAYOUT_STABLE, and
the system bar insets then keep the space of hidden bars. So in
landscape, where the status bar is always hidden, the UI had an empty
band at the top (seen on a Galaxy S8 and a Pocophone F1). Count only
the bars we show, and reapply the insets after changing that.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 18:59:06 +02:00
Henrik RydgårdandClaude Opus 5.5 09e9c0176b Fix the scissor clamp for 90 and 270 degree pre-rotation
With 270 degree pre-rotation, the rotated y runs along the physical
height, but was clamped to the physical width, so scissors on the left
of the screen moved. This was #15773, which got that pre-rotation
disabled. The 90 degree case had the bounds swapped too, but only too
loose there.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 18:59:06 +02:00
Henrik RydgårdandClaude Opus 5.5 0886063fba Vulkan: Pre-rotate reverse landscape again
The 270 degree pre-rotation was disabled in e6b7817cc6 for #15773 (UI
disappearing in reverse landscape on a Poco X3 Pro), which left reverse
landscape to the compositor, and every present returning SUBOPTIMAL. Try
it again: rotation is handled in place now, and the stale extent after a
rotation is fixed, so it needs retesting on Adreno.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 18:59:06 +02:00
Henrik RydgårdandClaude Opus 5.5 0b6ffd7c5e Android: Don't leave room for system bars we hid
Before Android 11, decorFitsSystemWindows(false) sets LAYOUT_STABLE, and
the system bar insets then keep the space of hidden bars. So in
landscape, where the status bar is always hidden, the UI had an empty
band at the top (seen on a Galaxy S8 and a Pocophone F1). Count only
the bars we show, and reapply the insets after changing that.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 18:56:07 +02:00
Henrik Rydgård b419238f81 Merge pull request #22526 from hrydgard/crash-review-jni-ui
Claude code review: Fix crashes in the Android JNI layer and UI screen lifetimes
2026-10-12 18:17:01 +02:00
Henrik Rydgård 54d2f7efe1 Merge pull request #22522 from hrydgard/resync-gamecontrollerdb
Re-sync gamecontrollerdb.txt with SDL_GameControllerDB, add a sync script
2026-10-12 17:34:51 +02:00
Henrik RydgårdandClaude Opus 5.5 866cf89b65 Make the resized flag atomic
On Android it's set on the Java UI thread right after writing g_display,
and read on the render thread, which then copies the dp size into the UI
bounds just once. With a plain bool the render thread could see the flag
before the new size.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 17:22:41 +02:00
Henrik RydgårdandClaude Opus 5.5 f7ec86c5d5 Android Vulkan: Don't trust a stale surface extent after a rotation
Since rotation is handled in place, the swapchain is recreated right
after surfaceChanged, and the surface can still report the previous
orientation's extent. On a Galaxy S8+ this happened in about one in four
rotations, leaving a portrait swapchain on a landscape window or the
other way around, squashed into half the screen until the next rotation.

If the extent is exactly the window size transposed, use the window size.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 17:22:41 +02:00
Henrik Rydgård 7bef6ccdda Merge pull request #22524 from LunaMoo/GOWpatchfix
Fix gow vortex patch by making sure changed register value get's used
2026-10-12 17:13:53 +02:00
Henrik Rydgård e1c76b68e5 Merge pull request #22523 from hrydgard/coded-arms-accurate-splines
Add AccurateSplines compat flag, enable for Coded Arms
2026-10-12 17:12:24 +02:00
LunaMoo bbbe195bdf fix gow vortex patch by making sure changed register value get's used in JIT 2026-10-12 16:40:43 +02:00
Henrik RydgårdandClaude Opus 5.5 08649f0f15 UI: Make switchScreen replace the whole screen stack
It only replaced the top screen, but most callers switch from a dialog:
Play on the game screen, the store, the installers, the framedump
launcher. The screens under it stayed alive, so launching a game from the
game screen and exiting it left [MainScreen, MainScreen], one more each
time.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 16:21:10 +02:00
Henrik RydgårdandClaude Opus 5.5 82ae32d985 GameScreen: Return to the main screen properly after removing a game
"Remove From Recent" and "Delete Game" called switchScreen(new MainScreen)
from a popup, which only replaces the top screen, so the old MainScreen
and the GameScreen of the removed game stayed in the stack underneath.

Close the GameScreen instead once the popups above it are gone, and have
MainScreen refresh its browsers.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 16:16:11 +02:00
Henrik RydgårdandClaude Opus 5.5 6d9a54d60d Android: Don't restart the microphone on resume after it was stopped while paused
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 14:41:19 +02:00
Henrik RydgårdandClaude Opus 5.5 56580581e0 Android: Check for Java exceptions after content URI calls
ContentUri catches Exception, but an Error got through, and none of the
native wrappers checked. A thrown int call returned 0, which reads as
SUCCESS, and the exception stayed pending, so the next JNI call aborted.
copyDocument/moveDocument are API 24/25 while the folder browser is
offered from 21, so those threw NoSuchMethodError there - now they return
a failure so the callers fall back.

Also convert non-URI names to Java's modified UTF-8.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 14:41:19 +02:00
Henrik RydgårdandClaude Opus 5.5 bfa0ef9d1f Android: Small crash fixes in the activity and shortcut creation
- Catch takePersistableUriPermission failing in ShortcutActivity, as
  DocumentResultProxyActivity already does. Some pickers don't grant it.
- Treat a cancelled permission request (empty results) as denied.
- Handle getCacheDir() returning null, like getFilesDir().
- Don't let the input device debug string, read from the render thread,
  throw ConcurrentModificationException into native code.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 14:41:19 +02:00
Henrik RydgårdandClaude Opus 5.5 51a799623c Android: Fix GPS and infrared crashes on devices without them
requestLocationUpdates() throws IllegalArgumentException for a provider
that doesn't exist (WiFi-only tablets, TVs, Chromebooks), which crashed
any game opening the GPS. Register each provider separately.

Without an IR blaster, the IR service is null, and InfraredHelper was
created anyway, so a sceSircs call NPE'd. Also catch transmit() failing,
like the SecurityException on API 21/22.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 14:41:19 +02:00
Henrik RydgårdandClaude Opus 5.5 46e576a402 Attach the NPDRM ISO dump thread to JNI
It does file I/O, which goes through Java for a content URI memstick, and
getEnv() asserts on an unattached thread.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 14:33:00 +02:00
Henrik RydgårdandClaude Opus 5.5 54b83bf850 SaveState: Drop queued operations at shutdown
Process() doesn't run while achievements block execution at boot, so
exiting then left the auto-load queued. The next game ran it, loading the
previous game's state, and calling back into the deleted EmuScreen.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 14:32:59 +02:00
Henrik RydgårdandClaude Opus 5.5 bd992e2f17 SoundEffectMixer: Hold the lock while mixing
UpdateSample() can replace and free a sample that Mix() is reading on the
audio thread, such as when changing the achievement sound while
previewing it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 14:32:59 +02:00
Henrik RydgårdandClaude Opus 5.5 12ec7478b2 Memstick: Ignore the back key while moving data
The Back choice is hidden during the move, but the key still closed the
screen. The destructor then blocked the UI thread until the move was
done, and FinishFolderMove() never ran, leaving the config pointing at
the old, now emptied folder.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 14:32:59 +02:00
Henrik RydgårdandClaude Opus 5.5 24d8955531 UI: Handle a caller finishing itself from dialogFinished()
That set dialogFinished_ to the caller, which processFinishDialog() then
deleted while it was still in the stack, leaking the popup. Take the
pointer out first and loop. Nothing does this now (MemStickScreen and
DevMenuScreen work around it), but it's easy to do by accident.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 14:32:59 +02:00
Henrik RydgårdandClaude Opus 5.5 a7229ce1c8 UI: Don't let a popup complete twice during its fade-out
ignoreInput_ doesn't stop a tap outside the box or Enter on the default
button, which both call TriggerFinish() again during the lead-out, firing
OnCompleted and the choice's OnChange a second time.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 14:32:59 +02:00
Henrik RydgårdandClaude Opus 5.5 8a4d53996f UI: Fix stale and null search view pointers in tabbed screens
noSearchResults_ and clearSearchChoice_ only exist with the search tab,
which depends on orientation, and were never reset. Rotating with a
filter set wrote into the deleted views, and GAMESETTINGS_SEARCH, which
goes to every screen in the stack, hit null ones on screens without
search controls.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 14:32:49 +02:00
Henrik RydgårdandClaude Opus 5.5 27899cc875 UI: Give views in lazily created tabs the views requester token
GetRequesterToken() only returns the views token inside CreateViews(),
but tabbed screens create every tab other than the first on demand, and
the persist restore after CreateViews() can create one too. So text
inputs and file choosers there (Networking tab nickname, search filter,
RemoteISO and achievement settings) registered their [this] callbacks
under the screen token, which a recreate doesn't forget. Open the native
input box, rotate, press OK, and the callback wrote through the deleted
view.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 14:32:49 +02:00
Henrik RydgårdandClaude Opus 5.5 0754544e27 UI: Don't recreate a screen's views while a popup is on top of it
Popups are transparent, so the screen under one still renders, and
render() ran DoRecreateViews(). A RecreateViews() on that screen (a
resize or rotation on DisplayLayoutScreen or TouchControlLayoutScreen,
MainScreen on RECENT_FILES_CHANGED from the recent-files thread, the
achievements login finishing) then deleted the choice that opened the
popup. Closing the popup wrote through it and called its handlers.

Leave the old views in place until the screen is back on top, where
update() recreates them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 14:32:38 +02:00
Henrik RydgårdandClaude Opus 5.5 88018255c2 Android: Don't read the screen stack from the UI thread on Back
NativeIsAtTopLevel() made a virtual call on the top screen from the Java
UI thread, while the render thread could be deleting it. Two quick Back
presses could hit that. Cache the flag in ScreenManager::Update()
instead, like passInputToMapper_ (now atomic too).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 14:32:29 +02:00
Henrik RydgårdandClaude Opus 5.5 531a75f045 Add AccurateSplines compat flag, enable for Coded Arms
- Fixes #21391

Makes the hardware backends tessellate Bezier patches and splines with the
GE-exact evaluation the software renderer uses. Fixes the z-fighting glow
under the floor grates in Coded Arms.

AGENTS.md: Put "- Fixes #N" first in commit messages

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-12 14:04:38 +02:00
Henrik Rydgård 6b203f050d Merge pull request #22521 from hrydgard/savedata-zip-root
Install savedata zips that contain a single save folder's files in the root
2026-10-12 13:58:02 +02:00
Henrik RydgårdandClaude Opus 5.5 2363a10a77 Re-sync gamecontrollerdb.txt with SDL_GameControllerDB, add a sync script
- Fixes #18091

The upstream part hadn't been synced since 2023. Tools/update_gamecontrollerdb.py
replaces it with the current upstream file and keeps PPSSPP's own mappings,
dropping those whose GUID upstream now has (after SDL's old-GUID conversion),
since a later line overrides an earlier one. 193 of 207 were covered,
including the PS3 and 8BitDo Ultimate 2C one-offs.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-12 13:49:49 +02:00
Henrik Rydgård 8d8009840e Merge pull request #22511 from hrydgard/android-inputbox-fixes
Claude code review: Android inputbox fixes
2026-10-12 13:20:25 +02:00
Henrik Rydgård 8c0c848a38 Merge pull request #22518 from hrydgard/input-dropout-fixes
Claude code review: Fix some control input bugs
2026-10-12 13:06:15 +02:00
Henrik Rydgård 8250585092 Merge pull request #22520 from hrydgard/coded-arms-lockon
Coded Arms Contagion: Add readback hock for lock-on, fix other readback issues
2026-10-12 12:45:03 +02:00