Commit Graph
6107 Commits
Author SHA1 Message Date
Henrik Rydgård f9baffccb6 Setting reorganization, some changed strings, soft drop shadows for text on game screen 2026-10-31 01:22:27 +01:00
Henrik Rydgård 67763e48a1 Add an "info textview" with a border. 2026-10-31 00:27:10 +01:00
Henrik Rydgård d09a9ffa11 Correct corner radius of popups to match inner rounded things 2026-10-29 15:12:55 +01:00
Henrik RydgårdandClaude Opus 5.5 7103341202 GL: Halve the defragmented push buffer when the big allocation fails
When a frame spilled over into several push buffers, Defragment freed
them and asserted if one block of their summed size couldn't be
allocated. On 32-bit devices that contiguous allocation fails where the
pieces fit, which Play reports from 32-bit ARM show at the start of a
frame. Halve the size until it fits; a smaller buffer just spills into
more buffers again, as it would have before defragmenting.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 02:05:35 +01:00
Henrik RydgårdandClaude Opus 5.5 dfa22e5532 Build the built-in relay server in every build system
Add aemu_postoffice's relay server to the Visual Studio, UWP, legacy
Android and libretro builds, next to the client. In the Visual Studio
projects its objects get their own names, since Common already has
Log.cpp and the client's enet.c. aemu_postoffice now leaves out pthread.h
where it isn't used, which MSVC doesn't have.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 14:48:47 +01:00
Henrik Rydgård 0a2568f4ef Round more things. Remove the underline from popup titles, cleaner look 2026-10-27 21:58:32 +01:00
Henrik RydgårdandClaude Opus 5.5 6ea7cf7be2 OSD: Round the corners of on-screen notifications
Half the radius of a Choice. Covers notices, progress bars, the
leaderboard tracker and RetroAchievements popups (not the listed
achievements on the achievement screens).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 21:49:06 +01:00
Henrik RydgårdandClaude Opus 5.5 e67543d604 UI: Pad the inside of popups
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 21:47:06 +01:00
Henrik RydgårdandClaude Opus 5.5 6efdad7cea UI: Round the popup buttons
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 21:47:06 +01:00
Henrik RydgårdandClaude Opus 5.5 916dfab834 UI: Round the corners of popups
FillRoundRect falls back to a square FillRect for drawables it can't
round, and a ViewGroup with round corners set rounds its background.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 21:47:06 +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ård 4c49233a39 Merge pull request #22813 from hrydgard/notice-view-style
NoticeView: Round corners like a Choice, pad the contents, fill the width
2026-10-27 14:30:09 +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årdandClaude Opus 5.5 a941ad634d NoticeView: Round corners like a Choice, pad the contents, fill the width
RenderNotice and MeasureNotice take padding (added inside the background)
and the corners to round. The drop shadow moves out of RenderNotice to the
floating OSD notices, since views don't have one. Without layout params, a
NoticeView is FILL_PARENT wide like a Choice.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 12:17:31 +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 dc1e9e50fc TextDrawer: Measure in a given style without switching fonts
Measuring took the current font and scale, so UIContext switched to the
style being measured and back. On first draw the font to switch back to
could be an empty one, which the UWP drawer asserts on.

MeasureString and MeasureStringRect now take the style and scale, and the
backends' MeasureStringInternal measures in the style it's given.
SetOrCreateFont, which sets the font drawing uses, is shared, and the
backends only implement EnsureFont, which creates a font if needed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 11:45:04 +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ård b4c096d13c Tweaks on DisplayLayoutScreen.cpp 2026-10-26 23:42:20 +01:00
Henrik Rydgård 4d26021a9b More round stuff 2026-10-26 23:08:25 +01:00
Henrik Rydgård 5c2a17f120 Give InfoItem backgrounds 2026-10-26 23:01:21 +01:00
Henrik Rydgård acc9fe9283 Somewhat better organization of UI settings 2026-10-26 23:01:21 +01:00
Henrik Rydgård 734d56a1d3 Tweaks to RetroAchievements screen 2026-10-26 23:01:21 +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 3c398657df ImDebugger: Route the soft keyboard through the System request layer
Instead of a hook and four Android_* functions declared in
ImDebugger.cpp, the debugger calls System_SetSoftKeyboardForced(), and
the platform reports a closed keyboard with
UIMessage::SOFT_KEYBOARD_HIDDEN.

"Keep keyboard after switching apps" is passed along with the request,
and the activity's onStop ends a keyboard that shouldn't persist, so the
native side no longer tracks app pauses.

The debugger is now also told when it's hidden. Frame() isn't called
then, so hiding it with the hotkey used to leave the keyboard up.

The keyboard button and its Misc menu options are only shown when
SYSPROP_KEYBOARD_IS_SOFT is set, which Android now reports too. iOS and
UWP on Xbox report it as well, but don't implement the request yet.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-26 16:36:49 +01:00
Henrik Rydgård aa9dfa85f6 Merge pull request #22788 from hrydgard/iphone-duo
iOS: iPhone Duo support (insets on the cover and inner screens)
2026-10-26 14:04:22 +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
Henrik Rydgård 3aec770b22 Set Auto rotation to default, move more settings around. 2026-10-26 11:36:59 +01:00
Henrik RydgårdandClaude Opus 5.5 89d7d69551 Metal: Tell 16-bit format support by GPU family, not by platform
The simulator check didn't compile on macOS, where the define doesn't exist.
The simulator's device reports only the Apple1 and Apple2 families, so require
Apple3 instead, which every device iOS 15 runs on has. Also silence the BC
format availability warnings in DataFormatToMetal, since GetDataFormatSupport
already checks for iOS 16.4.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-26 10:34:29 +01:00
Henrik RydgårdandClaude Opus 5.5 8c8ecc8c32 Metal: Check the 16-bit texture formats through the context
The iOS simulator reports an Apple GPU but doesn't have the packed 16-bit
formats, so creating one tripped Metal's validation and aborted the app.
thin3d now maps them and only reports them as supported on an Apple GPU outside
the simulator, and GPU_Metal asks GetDataFormatSupport like the Vulkan backend
does. Without them, textures decode to 8888.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-26 09:50:10 +01:00
Henrik RydgårdandClaude Opus 5.5 f364f297f1 Touch controls: Use the full width when the side insets are only for a top corner
On the iPhone Duo's cover screen, the camera sits in a box in the top right
corner, which gives a side inset down the whole right edge in portrait. The
controls are far below it, so they lose width for nothing. iOS 27.1 reports
the box as an occlusion region, and from that we report how far down the side
insets are needed (SYSPROP_DISPLAY_SIDE_INSETS_BOTTOM). When that's within the
top third, the game screen and the touch layout editor skip the side insets.
The rest of the UI, including the FPS counter, still keeps them.

The regions can show up after the size and insets have settled, so the insets
are now recomputed on every layout, and a screen recreates its views when its
layout mode changes, since the touch controls are placed for the bounds they
were created in.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-26 09:39:49 +01:00
Henrik RydgårdandClaude Opus 5.5 cccb296050 UI: Only even out the side insets in landscape
In portrait, a camera cutout is at the top, so a one-sided side inset is a
real edge and mirroring it just wastes space. The iPhone Duo's cover screen
has its sensor bar on the right in portrait, which left an equally wide
empty strip on the left of the main screen.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-25 23:21:12 +01:00
Henrik RydgårdandClaude Opus 5.5 178aaadf1a iOS: Build and run on the simulator
Adds an arm64 simulator platform to the iOS toolchain. The simulator build
renders with Metal only: it doesn't link MoltenVK, and loads Vulkan at
runtime like the libretro core, so Vulkan reports itself unavailable and
the config falls back to Metal.

b-ios-simulator.sh builds the App Store variant and runs it on the booted
simulator, or on one of a given device type, for App Store screenshots of
devices we don't have.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-25 22:48:02 +01:00
Henrik Rydgård 3a41fca43d Merge pull request #22782 from hrydgard/play-crash-fixes-2
Fixes for crashes and ANRs from the 1.21-beta1 Play reports
2026-10-25 20:22:21 +01:00
Henrik Rydgård 8585cc77bf Merge pull request #22761 from cscd98/libretro-vr
Add Stereoscopic and Immersive VR to libretro core
2026-10-25 20:00:14 +01:00
Henrik RydgårdandClaude Opus 5.5 70f205f2ff Take output screenshots after the ImGui debugger has drawn
The screenshot readback ran in ScreenManager's post-render callback, and
on Vulkan it ends the backbuffer render step. renderImDebugger() draws
after that, so taking a screenshot with the debugger open made its first
SetViewport() write through a null render step (an assert in debug
builds, a Play crash report in release). Do the readback at the end of
the frame in NativeFrame instead, which also puts the debugger in the
screenshot, and remove the now unused callback.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-25 19:44:21 +01:00
Henrik RydgårdandClaude Opus 5.5 2ce1164725 Log: Don't open the log file while holding its lock
SetFileLogPath() held logFileLock_ while creating the folder and opening
the file, and both log (CreateDir at INFO, OpenCFile for content URIs and
on errors). Logging to the file takes logFileLock_, so the thread
deadlocked on itself, and every thread that logged after it blocked too.
A Play ANR shows the loading thread stuck in CPU_Init's
SetFileLogPath, and the main thread waiting on the same lock to log a
key press.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-25 19:37:37 +01:00
Henrik RydgårdandClaude Opus 5.5 daf46b1dbc Don't set up a signal alt stack in the memory fault handler
sigaltstack() is per thread. InstallExceptionHandler() runs in CPU_Init()
on the loading thread, which exits after boot, while the faults come from
the CPU thread and UninstallExceptionHandler() runs on the emu thread. So
our stack was never used, and the uninstall "restored" the loading
thread's previous alt stack onto the emu thread. On Android that's the
one bionic gives each thread and frees when the thread exits, so every
later fault on the emu thread ran its handler on freed memory. A Play
crash report shows scudo finding a corrupted chunk header when freeing our
stack in UninstallExceptionHandler().

The alt stack came with the Dolphin code, which needs it to handle its own
stack overflows. Ours only handles guest memory faults, so let the handler
run on the faulting thread's stack, or the alt stack that thread already
has. This also leaves a libretro frontend's alt stack alone.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-25 19:37:23 +01:00
Henrik Rydgård 518795e35f Cut down on outdated/useless REPORTing and logging 2026-10-25 17:33:44 +01:00
Henrik RydgårdandClaude Opus 5.5 b91bd6af86 Settings: Build the settings screen from pages described as data
Each tab is now a SettingsPage: a list of items (headers, settings, buttons,
hints, links to other pages) that a function builds and views are created
from. Settings are added with page->Setting(&g_Config.x), which takes
the label, the kind of view, the range or choices, units, labels for special
values and the default from the config. The pages keep what depends on the
UI (which settings to show and when, enable rules, and behavior that needs the
screen), and reach the screen through the page's SettingsPageHost.

A page can link to other pages, which open on top of it in the same tab,
under a bar showing where you are, like Tools > Developer tools > Graphics,
where the earlier pages can be clicked to go back to them. The bar has back,
search and help buttons, and the back key also goes back a page (or out of a
search) before leaving the screen. Each page remembers its scroll position.
In portrait there's no tab strip: a page links to the tabs, and the bar shows
just the current page's title. Rotating keeps showing the same page. Moving
between pages only focuses an item when navigating with a keyboard or
controller.

The developer tools are now pages linked from the Tools tab, instead of a
screen of their own. The in-game developer menu and
--start-screen=developertools open the settings on that page. The toggles of
live state (the remote debugger and the MIPS tracer) show and change it
through functions, and pretending to be in-game for the notification tests is
a flag on the OSD. The memory map and memstick tests, only reachable from
commented-out code, are removed.

Search lists the matching settings from all tabs and the pages they link to,
grouped by where they are. Each result goes to the setting on its page,
scrolled to and highlighted (outlined, when picked with a mouse or touch), or
for a page, opens it. This replaces the search tab and the old filter that
hid the views that didn't match, and with them ShowSearchControls. Changing
tabs leaves the search.

The pages, the bar and search are in SettingsPagesDialogScreen, between the
tabbed dialog screen and the settings screen, so the other tabbed screens
keep plain tabs.

Other visible changes:
- Reset buttons that went to the wrong value now go to the real default: the
  touch control auto-hide delay (was 20 seconds instead of 8), the mouse
  wheel delay (1 ms, below its own range, instead of 80) and the UI size (0
  instead of -1 on desktop). The alternative speeds get a reset button.
- Units are shown on more sliders (frames, MHz, seconds, Hz), and popups no
  longer spell out what 0 means in the units, since the zero label does.
  Units of up to three characters (%, x, ms, MHz) aren't translated.
- The Android HW scaler hides the scales the display is too small for,
  instead of cutting the list short.
- Choices are translated in the setting's own section.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-25 15:26:58 +01:00
Henrik RydgårdandClaude Opus 5.5 30c9dd3b45 UI: Let clickable views be highlighted without the focus
SetHighlighted outlines the view, following its round corners, to point it
out without giving it the focus, which would turn on keyboard navigation.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-25 13:44:44 +01:00
Henrik RydgårdandClaude Opus 5.5 1c067f32a4 UI: Add ScrollView::ScrollToCenter and GetEnclosingScrollView
For bringing a given view into the middle of the scroll view it's in, rather
than just into sight like focusing does.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-25 13:44:43 +01:00
Henrik Rydgård 965b07c527 A lot more round corner fixes and layout fixes. 2026-10-25 10:28:40 +01:00
Henrik RydgårdandClaude Opus 5.5 5567f51eb8 UI: Don't apply the large-screen inset on phones and tablets
They're held close and have their own system insets.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-25 09:41:38 +01:00
Henrik RydgårdandClaude Opus 5.5 8e353761c7 UI: Let scroll views extend under the bottom inset when they don't quite reach the edge
A vertical ScrollView that extends into the bottom inset (like a navigation bar) adds
that much space after its contents, so the end can be scrolled out from under it.
It only did that when the view reached the very bottom of the screen, and then added
the whole inset. Since 58fa522d48 inset the content area of dialog screens on
screens over 600 dp, a phone like the S21 Ultra (617 dp wide) got a 1.7 dp inset,
which turned the extra space off. Add exactly the part of the view that lies in the
inset instead, and skip the bottom shadow in that case.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-25 09:41:38 +01:00
Craig Carnell 28ac694bf6 Add libretro VR support 2026-10-24 17:32:15 +01:00
Henrik RydgårdandClaude Opus 5.5 58fa522d48 UI: Limit the width of dialog screens, and keep content off the edges of large screens
Dialog screens (tabbed, two-pane, simple and the others built on
UIBaseDialogScreen) center their content at up to 1400 wide, instead of
stretching settings rows and buttons across very wide windows.

On large screens, those screens and the main screen also get an inset on all
sides, since controls right at the edge are hard to see there. It grows with
the screen's smaller dimension, from nothing at 600 to the full inset at
1000, and is always full on TVs. The game, popups, and the screens that
position things to match the game's screen (display layout, touch control
layout and tests, custom button and visual mapping) are left as they were.

The root's bounds are computed by UIScreen::GetContentBounds, since
UI::Margins can't hold widths this large.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-24 16:12:01 +02:00
Henrik Rydgård 695fc865ab Fix some look problems on TabbedDialogScreen 2026-10-24 14:12:53 +02:00
Henrik RydgårdandClaude Opus 5.5 b54056685e UI: Space ChoiceGroups from their container instead of their own margins
ChoiceGroups no longer have hardcoded margins. A new ChoiceGroupList holds them,
with padding and spacing that give the same look as before. Settings tabs, developer
tools, the two-pane settings columns, the pause menu and the rest put their groups in
one, and a few screens adjust its padding and spacing to their layout.

Also add the two groups in the remote disc streaming settings that were created but
never added, and make the settings search look inside groups: it only checked a tab's
direct children, so with ChoiceGroups a filter hid everything.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-24 14:01:58 +02:00