Commit Graph
336 Commits
Author SHA1 Message Date
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årdandClaude Opus 5.5 f4f68d37cc File dialogs: Offer PS1 disc images (.cue, .ccd, .mds, .mdf, .bin, .img)
Windows also gets a filter of its own for them. iOS's picker takes any
file and Android's doesn't filter by extension.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-23 15:50:28 +02:00
Henrik RydgårdandClaude Opus 5.5 ea26b3c7dd SDL: Quit when the main window is closed, with --game-window open too
SDL sends a quit only when the last window closes, so with the game
window open, closing the main one did nothing.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 23:04:01 +02:00
Henrik RydgårdandClaude Opus 5.5 5009724d91 Windows: --game-window, on Vulkan
A second Win32 window, added as a Game output like the SDL one. Keys
typed into it still go to the emulator; the mouse doesn't. It's for
testing multiple outputs (standing in for a TV over AirPlay) until real
multi-window support takes it over.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 20:41:35 +02:00
Henrik RydgårdandClaude Opus 5.5 76d0d37941 Outputs: Vulkan too, for --game-window and the iOS TV mode
The SDL game window gets its Vulkan surface the same way the main window
does, so it should work on Linux too. Windows and OpenGL aren't done.
EmuScreen asks the draw context for the output's size, which follows a
recreated Vulkan swapchain.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 20:11:36 +02:00
Henrik RydgårdandClaude Opus 5.5 014f6dceea Outputs: Name the device in the menu message
"In menus on Henrik's iPhone" if the platform gives us the name the user
gave the device, otherwise "In menus on your iPhone" (or Mac). iOS only
gives the name with an entitlement Apple has to grant, so for now it's
the model there.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 18:42:53 +02:00
Henrik RydgårdandClaude Opus 5.5 d491fc90cf Secondary outputs, and --game-window on Mac to show the game in a second window
The ScreenManager keeps a list of secondary outputs, each with its own
swapchain, recreated after a lost device. Platform code adds, resizes and
removes them from any thread through Native_AddOutput() and friends, which
take effect at the start of the next frame.

Each frame, every output is drawn by the topmost screen that claims it
(Screen::renderOutput). EmuScreen claims Game outputs: it presents the
game there, laid out for that output, and leaves it out of the backbuffer,
where the touch controls and the menus stay. Not in non-buffered mode,
which draws straight into the backbuffer.

--game-window opens such an output on Mac, with Metal. It's a smoke test
for multiple swapchains, and a stand-in for an AirPlay display.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 18:42:53 +02:00
Henrik RydgårdandClaude Opus 5.5 8d7ce57fa8 Metal: Hook up the backend on Mac, with the null GPU for now
Selectable with --graphics=metal, the backend choice in settings and the
Mac menu bar. SDL creates a Metal view for it, and headless renders
offscreen. Games run on the null GPU until there's a GPU/Metal.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-19 12:02:22 +02:00
Henrik Rydgård 0b557116c2 Merge pull request #22561 from eraycep/fix-sdl-input-pixel-density
SDL: Use window pixel density for input coordinates
2026-10-14 21:46:36 +02:00
Eray Cepni cc089011ca SDL: Use window pixel density for input coordinates
Convert mouse and touch coordinates using window pixel density instead
of display scale. This fixes offset clicks on X11 with fractional
display scaling.
2026-10-14 17:02:04 +03: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 b4d5d53b8a ImDebugger: Enable text input while an imgui text field is active
Since db8ff43, a leftover local shadowed lastImguiEnabled_ in runImDebugger,
so TEXT_GOTFOCUS was never sent and SDL never started text input for imgui.
Drive it from io.WantTextInput instead, so it's only on while editing.

The regular UI and the debugger now say independently whether they want text
input, and the platform only gets TEXT_LOSTFOCUS once neither does, so leaving
an imgui field doesn't break type-to-search on the screen underneath.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-11 18:08:00 +02:00
Henrik RydgårdandClaude Opus 5.5 0af1cae39c SDL: Generate text from key events when SDL_StartTextInput fails
SDL 3.4.0 to 3.4.4 refuse text input on Wayland compositors without
zwp_text_input_v3, such as WSLg's Weston, so no SDL_EVENT_TEXT_INPUT ever
arrives and text fields can't be typed into. Fixed upstream in later 3.4.x.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-11 17:59:23 +02:00
Henrik RydgårdandClaude Opus 5.5 b4ec29111b Microphone: Let the host say whether it wants polling, rather than checking for SDL
The CPU-thread polling added for SDL was keyed off defined(SDL), which
headless and Core are built with too, hence the extra headless check.
Ask the host instead, with SYSPROP_MICROPHONE_NEEDS_POLLING, so other
hosts can hand their input over the same way.

startMic now sends the same startRecording command for every non-Win32
host, taking the rate from curSampleRate like the SDL path did. The
Android path read it from param, which leaked, and which is null when
coming from onMicDeviceChange.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 17:20:48 +02:00
Chriopter 1670f5d1f9 SDL: Add microphone recording and device selection. 2026-10-09 00:18:31 +02:00
Henrik RydgårdandClaude Opus 5.5 5f261bd7ff Utility: Stand in for the HtmlViewer, offering to open the page in a browser
Instead of the PSP's web browser, a dialog shows the URL the game wants
and opens it in the host's browser on X, or backs out on O. Either way the
game sees the browser closed normally. Platforms that can't open a URL
(the new SYSPROP_CAN_LAUNCH_URL) only offer to back out. Only plain
printable-ASCII http(s) addresses are handed over, and on Linux without a
shell.

What the firmware does (sceUtility_Driver, 6.61, plus
utility/dialog/htmlviewer): the HtmlViewer has its own state apart from the
other dialogs, so they don't block each other, and its calls return
WRONG_TYPE until one has started. The request size picks the 2.00 to 3.00
layout, and InitStart allocates 3.5MB of user memory (4.5MB with options
bit 0x400 from 2.70 on), failing with 800200d9 without it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-25 12:50:23 -06:00
Henrik RydgårdandClaude Opus 5 463bd7acf9 SDL: Prefer Wayland when we're in a Wayland session
SDL doesn't reliably pick Wayland on its own - on a machine with a
working Wayland compositor but no XDG_SESSION_TYPE it still chose x11,
putting us on XWayland. Ask for Wayland when WAYLAND_DISPLAY is set,
respect SDL_VIDEO_DRIVER if the user set it, and fall back to letting
SDL choose if Wayland then fails to initialize.

Also log the video driver we ended up with, which should help triage
the Wayland/X11 reports.

Fixes #21080

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JvJR8oJNSCimCM9KXVLjfq
2026-09-05 14:09:24 -06:00
Henrik Rydgård 9368198d90 Merge pull request #22226 from 4RH1T3CT0R7/fix/sdl-launch-folder-linux
SDL: Open local files and folders with xdg-open on Linux
2026-09-05 07:58:01 -06:00
Artem Lytkin ec9eb7230e SDL: Open local files and folders with xdg-open on Linux
Since 1.20 the "Show Memory Stick folder" button and the log folder
button in developer tools call System_LaunchUrl with LOCAL_FOLDER or
LOCAL_FILE. The SDL implementation only handled macOS there, so on
Linux the click did nothing. Before that they went through the
SHOW_FILE_IN_FOLDER request, which already forks xdg-open.

Move that fork/exec into a LaunchXdgOpen helper and use it from both
places. The child now calls _exit after a failed exec so it doesn't
run the parent's atexit handlers.
2026-09-05 01:07:46 +03:00
Henrik RydgårdandClaude Opus 5 f10a62f23e SDL: Auto-hide the mouse cursor in fullscreen, like on Windows
Previously the cursor was only hidden when entering fullscreen or
starting a game, and never came back on mouse movement. Now it hides
half a second after the mouse stops moving and reappears when it moves
again, which also covers the touch-controls case that used to be
excluded entirely.

Fixes #20572

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JvJR8oJNSCimCM9KXVLjfq
2026-09-04 13:10:53 -06:00
Henrik Rydgård a0873e5b0e Enable HTTPS on Linux, through naett's libcurl backend
naett has had a complete libcurl backend all along; we just never built it,
so Linux ran with HTTPS_NOT_AVAILABLE. That means no homebrew store over
HTTPS, and RetroAchievements talking to plain http://retroachievements.org.

libcurl is loaded with dlopen rather than linked, the same way we handle the
Vulkan loader, so it stays a soft dependency: we need the curl headers at
build time, but a build made here still starts on a machine without libcurl
installed - it just reports HTTPS as unavailable, exactly like today. Distro
packagers get the behavior they'd expect either way, and certificate
validation comes free from the system CA store.

New net::HTTPSAvailable() answers "did that work", and SDLMain folds it into
SYSPROP_SUPPORTS_HTTPS, which everything downstream already degrades on.

Four fixes to the backend itself, all noted in ext/naett/README-ppsspp.md:

- panic() called exit(1) on a pipe or curl_multi_perform failure. Taking the
  emulator down because a download failed isn't acceptable - the backend now
  disables itself and requests complete with naettGenericError.
- CURLINFO_RESPONSE_CODE writes a long into res->code, which is an int. Eight
  bytes into four, getting away with it only because the next field absorbs
  the zeroes.
- curl_easy_setopt is varargs and wants a long for these options; int literals
  and int variables are UB on LP64.
- naettPlatformCloseResponse called through a null function pointer when
  libcurl was missing. Found by testing that path, which segfaulted.

CI needs libcurl4-openssl-dev (curl-dev on Alpine) or it would quietly keep
building without HTTPS.
2026-09-02 17:42:04 +02:00
Henrik Rydgård 04a6166c90 Android: Remove some unused code 2026-08-31 11:02:32 +02:00
Katharine Chui 435033e439 Avoid frame pacing issues with SDL_GetPowerInfo on linux
SDL_GetPowerInfo on linux asks upower through dbus for power
information, which can block DrawFPS in UI/DebugOverlay.cpp and in
turn the main thread. Run SDL_GetPowerInfo on another thread
instead to avoid the issue.
2026-08-19 01:33:56 +02:00
Henrik Rydgård a44c2c0bde Replace System_SendDebugOutput with a registered callback
I normally try to avoid registrations when not needed, but in this case
only headless uses this, so it's motivated.
2026-08-11 22:36:47 +02:00
Henrik Rydgård abb57c620f Adjust some log levels 2026-08-09 22:10:54 +02:00
Henrik Rydgård 07e63c345c Add SAVE_STATE to BrowseFileType 2026-08-09 19:03:08 +02:00
Henrik Rydgård c490d4ef36 Headless SDL: Add support for Vulkan rendering 2026-08-06 11:06:03 +02:00
Katharine Chui c39205496c bring back VulkanContext::SetCbGetDrawSize for linux wayland
It was removed during https://github.com/hrydgard/ppsspp/pull/21982

On Linux Wayland however this can be observed without:
34:25:550 Vulkan/VulkanContext.cpp:1401 I[G3D]: surfCapabilities_.current: -1x-1
34:25:550 Vulkan/VulkanContext.cpp:1406 I[G3D]: surfCapabilities_.current after clamp: -1x-1 min: 1x1 max: 32768x32768 computed: 1x1 cbdraw
2026-08-06 00:29:21 +02:00
Henrik RydgårdandClaude Sonnet 5 5bd1ff8066 Move remaining manual command line parsing into CmdLine.cpp
Headless.cpp, NativeApp.cpp, and SDLMain.cpp each still hand-parsed a few
argv flags directly (mount/log/state/ignore/loglevel in headless and the
app, xres/yres/dpi/scale in SDL), duplicating and in some cases conflicting
with the shared CommandLineOptions parser. Consolidate all of it into
CmdLine.cpp/.h so there's a single source of truth, and drop the now-dead
remain_argc/remain_argv filtering in SDLMain.cpp since NativeInit no longer
reads argv itself.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PfFvWzpHxErWgRhKqqSewN
2026-08-05 16:02:49 +02:00
Henrik Rydgård 16206d18ab Simplify the EmuThread API again 2026-08-05 09:48:51 +02:00
Henrik Rydgård 58c70f312a SDL: Initialize g_display before starting the EmuThread
Avoid racing between EmuThread and main thread.
2026-08-05 09:21:43 +02:00
Henrik Rydgård 5eb4772644 Minor EmuThread refactor 2026-08-05 00:15:56 +02:00
Henrik Rydgård be922eca62 Make OpenGL render thread shutdown more robust. 2026-08-04 16:44:55 +02:00
Henrik Rydgård ced24079cb Error handling cleanup, with some Claude help 2026-08-03 23:53:48 +02:00
Henrik Rydgård 72a80363d9 Update the SDL DPI handling 2026-08-03 23:26:46 +02:00
Henrik Rydgård b6d7c18f39 Try to eliminate a race condition 2026-08-03 23:09:07 +02:00
Henrik Rydgård 0f4f1d7091 More SDL GL context refactor 2026-08-03 17:52:56 +02:00
Henrik Rydgård 1c0740c4b9 SDL: Simplify graphics context fallback 2026-08-03 14:54:49 +02:00
Kevin Reinholz 20e747e594 Fix build with clang when not on a supported platform 2026-07-26 13:48:40 -07:00
Henrik Rydgård cb623f725c Get rid of the SDL-specific Vulkan graphics context 2026-07-26 19:10:46 +02:00
Henrik Rydgård 4b869a025e Move SDL stuff out of SDLVulkanGraphicsContext 2026-07-26 19:10:46 +02:00
Henrik Rydgård 3eb056ad86 Move Common/GraphicsContext.h to Common/GPU/GraphicsContext.h 2026-07-26 13:58:17 +02:00
Henrik Rydgård 6020fbcf0e Remove bad calls to ThreadStart/ThreadEnd from SDLMain.cpp 2026-07-26 13:44:53 +02:00
Henrik Rydgård 63f9d08de7 Buildfix 2026-07-26 12:14:34 +02:00
Henrik Rydgård ea3a2a2e84 Use the common EmuThread in the Android backend 2026-07-26 11:54:50 +02:00
Henrik Rydgård 7f218acc53 Change the GraphicsContext interface to be more consistent 2026-07-26 10:22:00 +02:00
Henrik Rydgård 85f8715660 Break the circular dependency caused by putting EmuThread in core using an interface 2026-07-24 15:31:42 +02:00
Henrik Rydgård 86c8e9ae68 Minor code cleanup 2026-07-24 15:31:41 +02:00
Henrik Rydgård 2489f5c581 Some CMakeLists.txt reorganization, use EmuThread from SDL 2026-07-24 15:31:41 +02:00
Henrik Rydgård afe4d5beaf Buildfixes, dependency shuffling to make things more logical 2026-07-24 14:43:34 +02:00