Compare commits

..

381 Commits

Author SHA1 Message Date
Charles Lombardo
ebbe4d20d4 android: Rename "Input Overlay" to "Overlay Options" 2023-06-01 23:59:14 -04:00
Charles Lombardo
47c3c2fc35 android: Adjust import/export saves dialog 2023-06-01 23:59:14 -04:00
Charles Lombardo
c2d150b4ae android: Warning dialogs for key errors 2023-06-01 23:59:14 -04:00
bunnei
6b00f8ea72 android: vk_turbo_mode: Remove unnecessary device recreation.
- Fixes a rare crash.
2023-06-01 20:08:38 -07:00
bunnei
cf5f8e889c android: EmulationFragment: Remove unnecessary surface destroy on pause. 2023-06-01 20:08:00 -07:00
bunnei
f2af99c3f0 android: renderer_vulkan: Fix crash with surface recreation. 2023-06-01 20:07:18 -07:00
bunnei
60b62a96ea android: Fix presentation layout on foldable and tablet devices. 2023-06-01 17:58:42 -07:00
Charles Lombardo
b1bc31b53e android: Enable overlay scale/opacity dialog 2023-06-01 17:58:42 -07:00
PabloG02
dfb7feb72f Add image to card_game.xml to preview in the Layout Editor 2023-06-01 17:58:42 -07:00
PabloG02
ec2dbbc0bd Save the position of buttons as a percentage 2023-06-01 17:58:42 -07:00
Charles Lombardo
1fab20b323 android: Don't crash the app when selecting a zip that causes a SecurityException 2023-06-01 17:58:42 -07:00
bunnei
89832701f6 input_common: Fix virtual amiibos 2023-06-01 17:58:42 -07:00
bunnei
7ed303e1c8 android: audio_core: Avoid shutdown hang. 2023-06-01 17:58:42 -07:00
bunnei
dd3c6bd261 android: ForegroundService: Handle null intent. 2023-06-01 17:58:41 -07:00
bunnei
18b9852957 android: ImportExportSavesFragment: Cleanup strings. 2023-06-01 17:58:41 -07:00
bunnei
ee5d6f6379 Update src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/ImportExportSavesFragment.kt 2023-06-01 17:58:41 -07:00
PabloG02
e325962aa0 Remove ?. 2023-06-01 17:58:41 -07:00
PabloG02
ee218b461c Check if folder exists before letting the user import/export saves 2023-06-01 17:58:41 -07:00
PabloG02
7b535a57ea Add save import/export in UI 2023-06-01 17:58:41 -07:00
bunnei
e706877539 android: Use ext-android-bin for external binaries. 2023-06-01 17:58:41 -07:00
Charles Lombardo
f168c265ce android: Fix FPS text getting cut off by rounded display corners 2023-06-01 17:58:41 -07:00
Charles Lombardo
1cea0b00c1 android: Prevent deleting the settings file while a game is running 2023-06-01 17:58:40 -07:00
Charles Lombardo
f01fcfa95b android: Fix link text color for base theme dialog 2023-06-01 17:58:40 -07:00
bunnei
00d7cb82fa android: Various fixes for CI. 2023-06-01 17:58:40 -07:00
bunnei
7aedafd85d android: externals: Update libadrenotools, use useLegacyPackaging. 2023-06-01 17:58:40 -07:00
Charles Lombardo
24c987c937 android: Re-enable service notification 2023-06-01 17:58:40 -07:00
Charles Lombardo
7097965e44 android: Ensure keys are loaded before populating games list 2023-06-01 17:58:40 -07:00
Charles Lombardo
7f1e4428d4 android: Use dialog fragment for the reset settings dialog 2023-06-01 17:58:40 -07:00
Charles Lombardo
264552effe android: Upgrade AGP to 8.0.2 2023-06-01 17:58:40 -07:00
Charles Lombardo
f50c44b916 android: Show notification permission page during setup 2023-06-01 17:58:39 -07:00
Charles Lombardo
3ee8361f1f android: DIsable FPS counter by default 2023-06-01 17:58:39 -07:00
Charles Lombardo
1e5ef3a4ac android: Improve searches with one character
The Jaccard algorithm is great for searches with 2 or more characters but nothing is returned for searches with one character. To get around this, just search with JaroWinkler for single character searches.
2023-06-01 17:58:39 -07:00
Charles Lombardo
fdf6ca762d android: Stop building x86 packages in APKs
This was really only meant for building the app to run in an emulator. If this is necessary, just add manually.
2023-06-01 17:58:39 -07:00
Charles Lombardo
eb01d7be13 android: Add FPS toggle 2023-06-01 17:58:39 -07:00
liushuyu
d386f6aea0 CI: use the verify pipeline to do releases 2023-06-01 17:58:39 -07:00
Charles Lombardo
ef2d005b49 android: Clean up app build.gradle
Removes the conflicting declaration of "version" and changes to versionCode that did nothing.
2023-06-01 17:58:39 -07:00
bunnei
577a705985 video_core: vk_rasterizer: Decrease draw dispatch count for Android. 2023-06-01 17:58:39 -07:00
bunnei
7fa72778dc android: config: Expose VSync as a configurable setting. 2023-06-01 17:58:38 -07:00
bunnei
7c6ccd51c5 android: GPU: Enable async presentation, increase frames in flight. 2023-06-01 17:58:38 -07:00
Charles Lombardo
29494d0eb7 android: Enable onBackInvokedCallback
For now this enables the ability to see the new Android 13 back gesture animations but later we can create custom animations that follow the back gesture.
2023-06-01 17:58:38 -07:00
Charles Lombardo
1eab858fa4 android: Remove deprecated use of onBackPressed() 2023-06-01 17:58:38 -07:00
Charles Lombardo
7ee805cb85 android: Add option for touch overlay haptics
Disabled by default
2023-06-01 17:58:38 -07:00
Charles Lombardo
2ebb26059e android: Improve missing game handling
Previously the app would crash if you selected a game that no longer existed. Now we show an error message and reload the games list to remove any invalid games from the list.
2023-06-01 17:58:38 -07:00
Charles Lombardo
354518f689 android: Clean up dependencies
Additionally updates material and androidx core libraries
2023-06-01 17:58:38 -07:00
Charles Lombardo
cea423720f android: Delete java code style file 2023-06-01 17:58:38 -07:00
Charles Lombardo
10c9643a74 android: Settings UI tweaks
New spacing and fonts for list items
2023-06-01 17:58:38 -07:00
Charles Lombardo
11814f1477 android: Simplify setup in search and games fragments 2023-06-01 17:58:38 -07:00
Charles Lombardo
a5d2bef46f android: Use collapsing toolbar layout in settings 2023-06-01 17:58:37 -07:00
Charles Lombardo
688996cb1b android: Remove unnecessary JvmStatic/JvmField annotations 2023-06-01 17:58:37 -07:00
Charles Lombardo
9b8e3539a1 android: Fix navigation rail animation in rtl layout 2023-06-01 17:58:37 -07:00
Charles Lombardo
e462f5ce12 android: Use cutout insets on setup fragment 2023-06-01 17:58:37 -07:00
Charles Lombardo
d2a311c0cb android: Button to reset all settings 2023-06-01 17:58:37 -07:00
Charles Lombardo
cd21311fa4 android: Use proguard file in relWithDebInfo 2023-06-01 17:58:37 -07:00
Charles Lombardo
e0521de294 android: Fix background color within inset areas 2023-06-01 17:58:37 -07:00
Charles Lombardo
dafb419e6e android: Shortcut to settings activity on reselection 2023-06-01 17:58:37 -07:00
Charles Lombardo
01cf8966ec android: Expose custom RTC setting 2023-06-01 17:58:37 -07:00
Charles Lombardo
232a016419 android: Reset setting on long press 2023-06-01 17:58:36 -07:00
Charles Lombardo
69aa5ef3f6 android: Fix issues with ea/main icons and version codes
Now all yuzu icon variants are taken care of and now we have a build variant that uses the versioning we need for the play store.
2023-06-01 17:58:36 -07:00
Charles Lombardo
e9497355fc android: Move theme options out of advanced settings 2023-06-01 17:58:36 -07:00
Charles Lombardo
633d3227fa android: Check if cached games are valid
Fixes bug when you close yuzu, delete games, and reopen to an instant crash.
2023-06-01 17:58:36 -07:00
german77
def80c473f android: Invert rotation to match phone orientation 2023-06-01 17:58:36 -07:00
bunnei
c7827226ee android: vulkan_device: Skip BGR565 emulation on S8gen2. 2023-06-01 17:58:36 -07:00
bunnei
021f4d3a54 android: config: Use default anisotropic filtering. 2023-06-01 17:58:36 -07:00
Charles Lombardo
2ec5a6cd72 android: Remove top padding from in game menu items 2023-06-01 17:58:36 -07:00
Charles Lombardo
4d0046da56 android: Use different icons for mainline/ea 2023-06-01 17:58:36 -07:00
Charles Lombardo
495e763462 android: Add early access upgrade fragment
We now have a second build flavor that will determine whether the "Get Early Access" button appears.
2023-06-01 17:58:35 -07:00
bunnei
23f0221d83 android: vulkan_device: Only compile OverrideBcnFormats when used. 2023-06-01 17:58:35 -07:00
Liam
65797fed2c android: remove spurious warnings about BCn formats when patched with adrenotools 2023-06-01 17:58:35 -07:00
bunnei
de4af2295c android: video_core: Disable some problematic things on GPU Normal. 2023-06-01 17:58:35 -07:00
bunnei
3567c2370f android: settings: Use mailbox vsync by default. 2023-06-01 17:58:35 -07:00
bunnei
24fe58bb47 android: video_core: Disable problematic compute shaders.
- Fixes #104.
2023-06-01 17:58:35 -07:00
Charles Lombardo
218ae8c83a android: Update progard to fix settings crash
R8 full mode was removing important classes from Wini that would cause a crash on saving settings. This keeps the relevant classes and suppresses warnings about irrelevant ones.
2023-06-01 17:58:35 -07:00
bunnei
d7d8f29962 android: vulkan: Recreate surface after suspension & adapt to async. presentation. 2023-06-01 17:58:35 -07:00
Charles Lombardo
a77e3bcf89 android: Game data cache 2023-06-01 17:58:35 -07:00
Charles Lombardo
72804bb642 android: Update to Kotlin 1.8.21 2023-06-01 17:58:34 -07:00
Charles Lombardo
34bc8b8477 android: Disable jetifier
We no longer depend on any legacy libraries that required this flag
2023-06-01 17:58:34 -07:00
Charles Lombardo
fdc3379daa android: Update dependencies 2023-06-01 17:58:34 -07:00
Charles Lombardo
ab36601c9c android: Migrate to AGP 8.0.1 2023-06-01 17:58:34 -07:00
Charles Lombardo
1d9df1681c android: Enable non-transitive R classes
New default going forward for new android projects. Best to follow the new standard.
2023-06-01 17:58:34 -07:00
bunnei
325908295b android: config: Enable asynchronous presentation by default on Android. 2023-06-01 17:58:34 -07:00
bunnei
f528444524 video_core: Enable support_descriptor_aliasing on Turnip, disable storage atomic otherwise. 2023-06-01 17:58:34 -07:00
german77
6437096395 android: fix deadzone calculation 2023-06-01 17:58:34 -07:00
Charles Lombardo
c3b76d6157 android: Fix background color when starting emulation 2023-06-01 17:58:34 -07:00
Charles Lombardo
d4acbb6c16 android: Persistent scrollbars on home settings fragment 2023-06-01 17:58:33 -07:00
Charles Lombardo
34c236d7b2 android: Use short build hash 2023-06-01 17:58:33 -07:00
Charles Lombardo
8c8ce08777 android: Use navigation bar shade view 2023-06-01 17:58:33 -07:00
Charles Lombardo
8fe7cd8bec android: About fragment 2023-06-01 17:58:33 -07:00
Charles Lombardo
41cb318df0 android: Use x-axis animation for navigation rail 2023-06-01 17:58:33 -07:00
Charles Lombardo
9a68017b33 android: Sort games alphabetically by default 2023-06-01 17:58:33 -07:00
Charles Lombardo
a0bc590c93 android: New icons for navigation bar 2023-06-01 17:58:33 -07:00
Charles Lombardo
014408bc92 android: New icons for home settings fragment 2023-06-01 17:58:33 -07:00
Charles Lombardo
2a5a3310db android: Add navigation rail 2023-06-01 17:58:33 -07:00
Charles Lombardo
c22aaf977a android: Search Fragment 2023-06-01 17:58:32 -07:00
Charles Lombardo
115497bb9c android: Fix potential zip traversal exploit 2023-06-01 17:58:32 -07:00
german77
9550112096 android: Add dedicated show overlay checkbox 2023-06-01 17:58:32 -07:00
Charles Lombardo
7612bde2f4 android: Add user directory shortcut 2023-06-01 17:58:32 -07:00
german77
8e26ccd483 android: Fix inline keyboard input 2023-06-01 17:58:32 -07:00
Charles Lombardo
6b5b579e8a android: Fix grammatical mistake in video core error message 2023-06-01 17:58:32 -07:00
Charles Lombardo
0f305b5a52 android: Adjust wording on GPU driver install button 2023-06-01 17:58:32 -07:00
Narr the Reg
a5e44b2a7f android: Add deadzone to stick input 2023-06-01 17:58:32 -07:00
german77
098c263ee9 android: Move motion listener to emulation activity 2023-06-01 17:58:32 -07:00
Narr the Reg
c4723bd05c core: hid: Finish linking motion from virtual controllers 2023-06-01 17:58:32 -07:00
Charles Lombardo
54b6d65531 android: Change wording for "Add Games" button (#100)
Co-authored-by: bunnei <bunneidev@gmail.com>
2023-06-01 17:58:32 -07:00
Charles Lombardo
2b315a0f86 android: Scroll shortcut for games list
If you reselect the "Games" menu item in the bottom navigation menu, the list smoothly scrolls to the top.
2023-06-01 17:58:31 -07:00
Charles Lombardo
d7f3555174 android: Setup screen hotfix
Added help button link for add games warning and a check for whether a task was completed on a given screen.
2023-06-01 17:58:31 -07:00
Charles Lombardo
3c2490ede6 android: Swap Default and Install buttons for GPU driver installation dialog 2023-06-01 17:58:31 -07:00
Charles Lombardo
547ce3d30e android: Add warnings to setup screens 2023-06-01 17:58:31 -07:00
Charles Lombardo
c2e341625f android: Allow search bar to scroll offscreen 2023-06-01 17:58:31 -07:00
Charles Lombardo
cb29a4c0d9 android: Update app icon
Small icon updates from Flam
2023-06-01 17:58:31 -07:00
Charles Lombardo
9ac813500c android: Change organization of the settings tab in the home screen 2023-06-01 17:58:31 -07:00
Charles Lombardo
a3d79aca3b android: Properly pop setup fragment from the back stack 2023-06-01 17:58:31 -07:00
Charles Lombardo
fa66691d5d android: Vertically scalable setup pages
Previously the setup pages would remain at a fixed height but now the icon and two text boxes will give up space as a device gets shorter. This eliminates the need for a scrolling view further problems with padding.
2023-06-01 17:58:31 -07:00
Charles Lombardo
aa9fe156da android: Fix setup rotation bug
If you rotated the device at the "Add Games" screen the buttons would disappear until you trigged them from the beginning page swap. Now button state is saved across recreation.
2023-06-01 17:58:31 -07:00
Charles Lombardo
b950e76368 android: Temporarily switch for a fixed version code for testing 2023-06-01 17:58:31 -07:00
Charles Lombardo
ea50ecc0d8 android: Fix alignment of SwipeRefreshLayout 2023-06-01 17:58:30 -07:00
Charles Lombardo
2aac235993 android: Shape/spacing adjustments to game card
Ripple effect now reaches into rounded corners, icon size changed, company text removed, title font adjusted, and spacing around the card was adjusted as well. Text also doesn't get cut off anymore and instead scrolls indefinitely on one line.
2023-06-01 17:58:30 -07:00
Charles Lombardo
d1518b8f19 android: Manual tweaks for dialog colors
Small fix for Flam
2023-06-01 17:58:30 -07:00
Charles Lombardo
704d1a0f23 android: Fix black backgrounds bug
Start using a specific night mode check because black backgrounds could apply incorrectly when using the light app mode, dark system mode, and black backgrounds. Launching the settings activity will show light mode colors/navigation bars but with black backgrounds.
2023-06-01 17:58:30 -07:00
Charles Lombardo
fa73b7f48a android: Use navigation bar shade view for settings activity 2023-06-01 17:58:30 -07:00
Charles Lombardo
395f9c2bab android: Disable editing themes during emulation 2023-06-01 17:58:30 -07:00
Charles Lombardo
b3611cbf0c android: Prevent situation where binding is called on a null view 2023-06-01 17:58:30 -07:00
Charles Lombardo
41c1ede953 android: Add black backgrounds toggle 2023-06-01 17:58:30 -07:00
Charles Lombardo
66be140e21 android: Add theme mode picker 2023-06-01 17:58:30 -07:00
Charles Lombardo
7f9e0b7da0 android: Add theme picker 2023-06-01 17:58:30 -07:00
Charles Lombardo
9abeba37ab android: Prevent potential abstract settings crash 2023-06-01 17:58:29 -07:00
Charles Lombardo
1b25be830a android: Fix cast for abstract settings 2023-06-01 17:58:29 -07:00
Charles Lombardo
2c09f303bf android: Create xml for Material You theme 2023-06-01 17:58:29 -07:00
Charles Lombardo
d616f8f3d9 android: Remove check for API 29 in themes 2023-06-01 17:58:29 -07:00
Charles Lombardo
85c558081d android: Adjustments to home option card
Several spacing/color adjustments provided by Flam
2023-06-01 17:58:29 -07:00
Charles Lombardo
e9a9016a91 android: Use different colors for logo in options menu
Reverting to the official logo colors
2023-06-01 17:58:29 -07:00
Charles Lombardo
df4fa1315d android: New default theme colors 2023-06-01 17:58:29 -07:00
Charles Lombardo
7e3134dcbb android: Use libnx default icon
Credit to jaames for the original icon
2023-06-01 17:58:29 -07:00
Liam
7666b2f944 android: enable LTO 2023-06-01 17:58:29 -07:00
Charles Lombardo
5dbb49ba1c android: Show error if invalid keys file is selected
There aren't MIME types specific enough for filtering out files that aren't amiibo or production keys. So here we just check for the extensions "bin" or "keys" where appropriate and stop the process if incorrect. Previously you could select any document and it could cause the app to hang.
2023-06-01 17:58:29 -07:00
Charles Lombardo
a391c1bb8f android: Fix first time setup scrolling bug
If you quickly scrolled from the second page to the first and then back, the next/back buttons would disappear.
2023-06-01 17:58:28 -07:00
Charles Lombardo
b283d8e625 android: Fix A button preference key 2023-06-01 17:58:28 -07:00
Charles Lombardo
362bf8b670 android: First time setup screen 2023-06-01 17:58:28 -07:00
Charles Lombardo
d9337f00e5 android: Prevent editing unsafe settings at runtime
There currently isn't a visual "disabled" cue for any of the view holders that aren't the switch setting. This will be improved in the future.
2023-06-01 17:58:28 -07:00
Charles Lombardo
5585845af5 android: Abstract settings
Previously we could only add settings that would change our ini file. Now we can create abstract settings in our presenter to alter things like shared preferences for theme support!
2023-06-01 17:58:28 -07:00
german77
2b0df09966 android: Implement gamepad input 2023-06-01 17:58:28 -07:00
Charles Lombardo
6f98a03dd2 android: Bump minimum version to Android 11 2023-06-01 17:58:28 -07:00
Charles Lombardo
2728262bb4 android: Decouple status bar shade from navigation bar visibility 2023-06-01 17:58:28 -07:00
Charles Lombardo
31d677e9a8 android: Enable code minification 2023-06-01 17:58:28 -07:00
Charles Lombardo
df1320356f android: Switch from a colored status bar to a custom view
Allows for smoother transitions with the search bar
2023-06-01 17:58:27 -07:00
Charles Lombardo
25d3ff266d android: Adjustments to card_game
Removed a currently unused text view and moved to material text views.
2023-06-01 17:58:27 -07:00
Charles Lombardo
62eb7fcd1a android: MainActivity overhaul
This moves several parts of the main activity into fragments that manage themselves to react to changes. UI changes like the appearance of a new search view or when the games list changes now gets updated via multiple view models. This also starts a conversion to the androidx navigation component which furthers the goals mentioned previously with more fragment responsibility. This will eventually allow us to use one activity with interchanging fragments and multiple view models that are stored within that central activity.

fdas
2023-06-01 17:58:27 -07:00
Charles Lombardo
fd32a675b7 android: Enforce Vulkan 1.1 support as minimum 2023-06-01 17:58:27 -07:00
Charles Lombardo
81df58f3e5 android: Update gradle version to 8.1 2023-06-01 17:58:27 -07:00
Charles Lombardo
085f717deb android: Update app dependencies 2023-06-01 17:58:27 -07:00
Charles Lombardo
5c0fa2126d android: Convert gradle scripts to Kotlin DSL 2023-06-01 17:58:27 -07:00
bunnei
6fa875f3e5 android: vulkan: Disable vertex_input_dynamic_state on Qualcomm. 2023-06-01 17:58:27 -07:00
bunnei
b969a14671 android: settings: Add scaling filter & anti-aliasing options. (#66) 2023-06-01 17:58:27 -07:00
bunnei
0601658ead android: video_core: Add support for disk shader cache. (#64) 2023-06-01 17:58:27 -07:00
bunnei
b12233f595 android: vulkan_debug_callback: Ignore many innocuous errors. 2023-06-01 17:58:27 -07:00
bunnei
7bf3830726 android: config: Change docked mode and GPU accuracy to favor performance on Android. 2023-06-01 17:58:27 -07:00
german77
4be68269a5 service: account: Save user profile folder on first user creation 2023-06-01 17:58:26 -07:00
german77
489846d9ca android: Initialize account manager 2023-06-01 17:58:26 -07:00
german77
07c93ebb92 android: Remove unsafe null check 2023-06-01 17:58:26 -07:00
Charles Lombardo
313bc7dff2 android: Scale input overlay independently of system display scale 2023-06-01 17:58:26 -07:00
Charles Lombardo
a96d835286 android: Use apply instead of commit for shared preferences
Previously we were operating on the assumption that apply'd settings wouldn't be visible immediately. This isn't true and settings will be accessible via memory before being stored to disk. This reduces any potential stutters caused by saving to shared preferences.
2023-06-01 17:58:26 -07:00
Charles Lombardo
b178a3788b android: Add DPad slide toggle 2023-06-01 17:58:26 -07:00
Charles Lombardo
aaf0de6edf android: Add relative stick center toggle 2023-06-01 17:58:26 -07:00
Charles Lombardo
9375df2221 android: Make hash and branch accessible from BuildConfig 2023-06-01 17:58:26 -07:00
Charles Lombardo
fe5082a833 android: Backup shared preferences where applicable 2023-06-01 17:58:26 -07:00
Charles Lombardo
9b28043226 android: Enable retaining app data after uninstall 2023-06-01 17:58:26 -07:00
Charles Lombardo
88d7134aec android: Remove unused doFrame function 2023-06-01 17:58:26 -07:00
Charles Lombardo
dc55e49f27 android: Convert NativeLibrary to Kotlin 2023-06-01 17:58:26 -07:00
Charles Lombardo
ccb6bf840c android: Remove LocalBroadcastManager
This causes a couple of minor changes to directory initialization. We don't have a lengthy initialization step so we could spend less time creating state receivers and just run initialization on the main thread. We also don't have a situation where external storage will be a concern so checks are removed in favor of a binary check to see if initialization is ready.

This additionally removes the unused DoFrame callback.
2023-06-01 17:58:25 -07:00
Charles Lombardo
4904c0d8da android: Remove game database
The content provider + database solution was excessive and is now replaced with the simple file checks from before but turned into an array list held within a viewmodel.
2023-06-01 17:58:25 -07:00
Charles Lombardo
d5170f374b android: Adjust game icon loading 2023-06-01 17:58:25 -07:00
Charles Lombardo
c977990e82 android: Remove unused dimensions files 2023-06-01 17:58:25 -07:00
Charles Lombardo
433d388728 android: Slightly reduce game card size 2023-06-01 17:58:25 -07:00
Charles Lombardo
5bbd9f88e8 android: Only show company text view if it has content 2023-06-01 17:58:25 -07:00
Charles Lombardo
971d603e98 android: Fix check for ok text in software keyboard 2023-06-01 17:58:25 -07:00
Narr the Reg
82950279aa android: Implement amiibo reading from nfc tag 2023-06-01 17:58:25 -07:00
bunnei
13533d4142 android: vulkan_device: Disable VK_EXT_custom_border_color on Adreno.
- Causes crashes on sampler creation with Super Mario Odyssey.
2023-06-01 17:58:25 -07:00
Charles Lombardo
135c2f1b56 android: Add toggle controls option to input overlay 2023-06-01 17:58:25 -07:00
Charles Lombardo
81a5e4c5bc android: Do not update FPS text on null view 2023-06-01 17:58:24 -07:00
Charles Lombardo
bdee00f9f5 android: Convert keyboard applet to kotlin and refactor 2023-06-01 17:58:24 -07:00
bunnei
398550f390 android: Implement basic software keyboard applet. 2023-06-01 17:58:24 -07:00
bunnei
bf1b32db95 android: config: Disable shader cache by default on Android. 2023-06-01 17:58:24 -07:00
german77
c8a7594d3e android: Fix fps counter not showing up 2023-06-01 17:58:24 -07:00
Charles Lombardo
8a9bef77e3 android: Prevent showing games on an invalid view 2023-06-01 17:58:24 -07:00
Charles Lombardo
00c2ce78a0 android: Re-implement overlay editing 2023-06-01 17:58:24 -07:00
Charles Lombardo
0f22ceaae7 android: Fix popup menu going out of bounds 2023-06-01 17:58:24 -07:00
Charles Lombardo
a31d2a90b8 android: Use autofit grid for games fragment 2023-06-01 17:58:24 -07:00
Charles Lombardo
a0b81102bc android: Prevent updating empty game list text on invalid view 2023-06-01 17:58:24 -07:00
Charles Lombardo
4b02c8c924 android: Persist settings across configuration changes
Mostly things get refactored here to remove previous assumptions made about how the activity/fragment lifecycles would operate. The important change for persistence is removing the assumption that the user will be at the first settings fragment on recreation when deciding whether or not to reload settings. Now we check a flag in Settings to know if we loaded the settings within this lifecycle.
2023-06-01 17:58:24 -07:00
Charles Lombardo
4e86e1e4d8 android: Store settings object in viewmodel 2023-06-01 17:58:24 -07:00
Charles Lombardo
e7fe2a380a android: Remove configChanges exceptions 2023-06-01 17:58:24 -07:00
Charles Lombardo
6a19ff24ca Android: Enable resizeable activities 2023-06-01 17:58:23 -07:00
Charles Lombardo
7f7a668c85 android: Fix emulation fragment comments 2023-06-01 17:58:23 -07:00
Charles Lombardo
8f6d4717ca android: Use modal navigation drawer as in game menu 2023-06-01 17:58:23 -07:00
Charles Lombardo
e717ff2dde android: Make Game class parcelable 2023-06-01 17:58:23 -07:00
Charles Lombardo
c54b7b68ec android: Add kotlin parcelize plugin 2023-06-01 17:58:23 -07:00
Charles Lombardo
95d4ae95d7 android: Remove deprecated use of onActivityResult 2023-06-01 17:58:23 -07:00
Charles Lombardo
eed9eb8a65 android: Fix RTL layouts 2023-06-01 17:58:23 -07:00
Charles Lombardo
e46509c1ce android: Use ellipsis character 2023-06-01 17:58:23 -07:00
Charles Lombardo
e4b17c674f android: Move all array strings to main strings file 2023-06-01 17:58:23 -07:00
Charles Lombardo
88fb750dcc android: Remove unused strings 2023-06-01 17:58:23 -07:00
Charles Lombardo
7608b7feb3 android: Remove unused colors 2023-06-01 17:58:22 -07:00
Charles Lombardo
398e5591cb android: Remove citra date time picker 2023-06-01 17:58:22 -07:00
Charles Lombardo
75154ba0d2 android: Remove unused premium header layout 2023-06-01 17:58:22 -07:00
Charles Lombardo
dda32cb400 android: Remove unused fragment animations 2023-06-01 17:58:22 -07:00
Charles Lombardo
64b90c982d android: Remove unused string arrays 2023-06-01 17:58:22 -07:00
Charles Lombardo
ba77d08dd6 android: Remove unused integer xmls 2023-06-01 17:58:22 -07:00
Charles Lombardo
4946035983 android: Refactor ic_launcher.xml to drawables 2023-06-01 17:58:22 -07:00
Charles Lombardo
630f5ab7a1 android: Suppress lint in InsetsHelper 2023-06-01 17:58:22 -07:00
Charles Lombardo
903d306f80 android: Add data extraction rules 2023-06-01 17:58:22 -07:00
Charles Lombardo
dea5ffe6f7 android: Remove requestLegacyExternalStorage attribute 2023-06-01 17:58:22 -07:00
Charles Lombardo
e80f6b2738 android: Remove unused permissions 2023-06-01 17:58:22 -07:00
Charles Lombardo
962b4a799d android: Inset input overlay based on system cutouts 2023-06-01 17:58:22 -07:00
Narr the Reg
1f48c5f5e3 Use yuzu as category instead of citra 2023-06-01 17:58:22 -07:00
Charles Lombardo
ada74893a9 android: Stop updating fps counter when emulation stops 2023-06-01 17:58:22 -07:00
Charles Lombardo
b7a0a09321 android: Move driver installation off of main thread
Additionally creates an indeterminate loading dialog during installation
2023-06-01 17:58:22 -07:00
Charles Lombardo
8658625ec1 android: Fix crash when decodeGameIcon creates a null Bitmap 2023-06-01 17:58:22 -07:00
Charles Lombardo
96cbdb653e android: Use view binding 2023-06-01 17:58:22 -07:00
Charles Lombardo
6fac89f5a6 android: Enable view binding 2023-06-01 17:58:21 -07:00
Charles Lombardo
9eb4b7eb23 android: Refactor CheckBoxSetting to SwitchSetting 2023-06-01 17:58:21 -07:00
bunnei
8c1ec7e2d5 android: EmulationActivity: Fix variable shadowing in fragment creation. 2023-06-01 17:58:21 -07:00
bunnei
51c774846e android: res: fragment_emulation: Ensure FPS counter is shown. 2023-06-01 17:58:21 -07:00
Liam
0ce94f8f78 common: link libandroid on android 2023-06-01 17:58:21 -07:00
Liam
6b96e333a7 cmake: download architecture-specific ffmpeg for android 2023-06-01 17:58:21 -07:00
Liam
505402b490 build: only enable adrenotools on arm64 2023-06-01 17:58:21 -07:00
Charles Lombardo
89f1dee6db android: Use Skyline's document provider 2023-06-01 17:58:21 -07:00
Charles Lombardo
6874eb0740 android: Use androidx splash screen 2023-06-01 17:58:21 -07:00
Charles Lombardo
a390247965 android: Replace Picasso with Coil 2023-06-01 17:58:21 -07:00
Charles Lombardo
3ef9ff437c android: New swipe to refresh color scheme 2023-06-01 17:58:21 -07:00
Charles Lombardo
d87d7b0c0e android: New settings fragment animations 2023-06-01 17:58:21 -07:00
Charles Lombardo
1863356fb9 android: Use edge to edge 2023-06-01 17:58:21 -07:00
Charles Lombardo
c90f136120 android: Use Material 3 components 2023-06-01 17:58:21 -07:00
Charles Lombardo
7d5e9b1744 android: Modernize theme system 2023-06-01 17:58:20 -07:00
Charles Lombardo
5b37523dc6 android: Use vector icons 2023-06-01 17:58:20 -07:00
Charles Lombardo
6b87ca2f10 android: Use adaptive icon 2023-06-01 17:58:20 -07:00
bunnei
5236d169bc android: settings: Dynamically evaluate valueAsString
Co-Authored-By: bunnei <bunneidev@gmail.com>
2023-06-01 17:58:20 -07:00
Charles Lombardo
e7ae312c46 android: Add license identifier 2023-06-01 17:58:20 -07:00
Charles Lombardo
a491d8d598 android: Convert YuzuApplication to Kotlin 2023-06-01 17:58:20 -07:00
Charles Lombardo
ec412e4a96 android: Convert Action1 to Kotlin 2023-06-01 17:58:20 -07:00
Charles Lombardo
86c46302a0 android: Convert GameViewHolder to Kotlin 2023-06-01 17:58:20 -07:00
Charles Lombardo
90cfaebe2f android: Remove ThemeUtil 2023-06-01 17:58:20 -07:00
Charles Lombardo
27969a6804 android: Convert StartupHandler to Kotlin 2023-06-01 17:58:20 -07:00
Charles Lombardo
8a0033b13c android: Convert Log to Kotlin 2023-06-01 17:58:20 -07:00
Charles Lombardo
5073788e4e android: Convert GpuDriverMetadata to Kotlin 2023-06-01 17:58:20 -07:00
Charles Lombardo
a8a7428c49 android: Convert GpuDriverHelper to Kotlin 2023-06-01 17:58:19 -07:00
Charles Lombardo
fca47e6397 android: Convert GameIconRequestHandler to Kotlin 2023-06-01 17:58:19 -07:00
Charles Lombardo
e45854be7a android: Convert ForegroundService to Kotlin 2023-06-01 17:58:19 -07:00
Charles Lombardo
98beeb5158 android: Convert FileUtil to Kotlin 2023-06-01 17:58:19 -07:00
Charles Lombardo
46644696a5 android: Convert FileBrowserHelper to Kotlin 2023-06-01 17:58:19 -07:00
Charles Lombardo
0fd310930d android: Convert EmulationMenuSettings to Kotlin 2023-06-01 17:58:19 -07:00
Charles Lombardo
c6b623ad1f android: Convert DocumentsTree to Kotlin 2023-06-01 17:58:19 -07:00
Charles Lombardo
5f092660da android: Convert DirectoryStateReceiver to Kotlin 2023-06-01 17:58:19 -07:00
Charles Lombardo
1be221b4be android: Convert DirectoryInitialization to Kotlin 2023-06-01 17:58:19 -07:00
Charles Lombardo
af0d9ff8c6 android: Convert ControllerMappingHelper to Kotlin 2023-06-01 17:58:19 -07:00
Charles Lombardo
50a708561e android: Convert BiMap to Kotlin 2023-06-01 17:58:19 -07:00
Charles Lombardo
c065750c59 android: Convert AddDirectoryHelper to Kotlin 2023-06-01 17:58:19 -07:00
Charles Lombardo
caceb4934d android: Convert PlatformGamesView to Kotlin 2023-06-01 17:58:19 -07:00
Charles Lombardo
caf71e98a6 android: Convert PlatformGamesPresenter to Kotlin 2023-06-01 17:58:19 -07:00
Charles Lombardo
bc6670244b android: Convert PlatformGamesFragment to Kotlin 2023-06-01 17:58:19 -07:00
Charles Lombardo
075f5ebea2 android: Convert MainView to Kotlin 2023-06-01 17:58:19 -07:00
Charles Lombardo
16089d14b0 android: Convert MainPresenter to Kotlin 2023-06-01 17:58:18 -07:00
Charles Lombardo
efc89ec23a android: Convert InputOverlayDrawableJoystick to Kotlin 2023-06-01 17:58:18 -07:00
Charles Lombardo
3e2faae14d android: Convert MainActivity to Kotlin 2023-06-01 17:58:18 -07:00
Charles Lombardo
73c24aba39 android: Remove ExampleInstrumentedTest 2023-06-01 17:58:18 -07:00
Charles Lombardo
a20883b316 android: Remove TwoPaneOnBackPressedCallback
Leftover UI code for dolphin's cheat system. Removing for now.
2023-06-01 17:58:18 -07:00
Charles Lombardo
99eac30e4b android: Convert InputOverlayDrawableDpad to Kotlin 2023-06-01 17:58:18 -07:00
Charles Lombardo
491ce5b68a android: Convert InputOverlayDrawableButton to Kotlin 2023-06-01 17:58:18 -07:00
Charles Lombardo
f7ec760623 android: Convert InputOverlay to Kotlin 2023-06-01 17:58:18 -07:00
Charles Lombardo
38139db186 android: Remove DividerItemDecoration
Removed in favor of material components version
2023-06-01 17:58:18 -07:00
Charles Lombardo
0996f9f728 android: Inherit from Material 3 themes
Partially breaks the UI for now but is necessary to use new material components.
2023-06-01 17:58:18 -07:00
Charles Lombardo
d3b5b59d9b android: Convert MinimalDocumentFile to Kotlin 2023-06-01 17:58:18 -07:00
Charles Lombardo
9224369a99 android: Convert GameProvider to Kotlin 2023-06-01 17:58:18 -07:00
Charles Lombardo
21ac92b473 android: Convert GameDatabase to Kotlin 2023-06-01 17:58:18 -07:00
Charles Lombardo
4696aa175f android: Convert Game to Kotlin 2023-06-01 17:58:18 -07:00
Charles Lombardo
b8956f3817 android: Convert EmulationFragment to Kotlin 2023-06-01 17:58:18 -07:00
Charles Lombardo
63bd15bb44 android: Convert SettingsFile to Kotlin 2023-06-01 17:58:18 -07:00
Charles Lombardo
fea1c3ce0d android: Convert SettingsFrameLayout to Kotlin 2023-06-01 17:58:17 -07:00
Charles Lombardo
8047083339 android: Convert SettingsFragmentView to Kotlin 2023-06-01 17:58:17 -07:00
Charles Lombardo
db5f415f30 android: Convert SettingsFragmentPresenter to Kotlin 2023-06-01 17:58:17 -07:00
Charles Lombardo
a860a6894b android: Convert SettingsFragment to Kotlin 2023-06-01 17:58:17 -07:00
Charles Lombardo
6a2591c026 android: Convert SettingsActivityView to Kotlin 2023-06-01 17:58:17 -07:00
Charles Lombardo
5fd38fd849 android: Convert SettingsActivityPresenter to Kotlin 2023-06-01 17:58:17 -07:00
Charles Lombardo
c8e0e011da android: Convert SettingsActivity to Kotlin 2023-06-01 17:58:17 -07:00
Charles Lombardo
99380ae3e0 android: Convert SubmenuViewHolder to Kotlin 2023-06-01 17:58:17 -07:00
Charles Lombardo
d6d63c408d android: Convert SliderViewHolder to Kotlin 2023-06-01 17:58:17 -07:00
Charles Lombardo
c6f90e8f2d android: Convert SingleChoiceViewHolder to Kotlin 2023-06-01 17:58:17 -07:00
Charles Lombardo
0bb627c6d8 android: Convert SettingViewHolder to Kotlin 2023-06-01 17:58:16 -07:00
Charles Lombardo
5f1638aa27 android: Convert HeaderViewHolder to Kotlin 2023-06-01 17:58:16 -07:00
Charles Lombardo
a658424994 android: Convert DateTimeViewHolder to Kotlin 2023-06-01 17:58:16 -07:00
Charles Lombardo
6766112edc android: Convert CheckBoxSettingViewHolder to Kotlin 2023-06-01 17:58:16 -07:00
Charles Lombardo
416501fa81 android: Convert StringSetting to Kotlin 2023-06-01 17:58:16 -07:00
Charles Lombardo
b6695fb31d android: Convert SettingSection to Kotlin 2023-06-01 17:58:16 -07:00
Charles Lombardo
826d0cc93f android: Convert Setting to Kotlin 2023-06-01 17:58:16 -07:00
Charles Lombardo
d0d55deec9 android: Convert IntSetting to Kotlin 2023-06-01 17:58:16 -07:00
Charles Lombardo
1abfa81cae android: Convert FloatSetting to Kotlin 2023-06-01 17:58:16 -07:00
Charles Lombardo
83476782ed android: Convert BooleanSetting to Kotlin 2023-06-01 17:58:16 -07:00
Charles Lombardo
aa2a95e9df android: Convert SubmenuSetting to Kotlin 2023-06-01 17:58:16 -07:00
Charles Lombardo
908ca145d2 android: Convert StringSingleChoiceSetting to Kotlin 2023-06-01 17:58:16 -07:00
Charles Lombardo
bfa1d51641 android: Convert SliderSetting to Kotlin 2023-06-01 17:58:16 -07:00
Charles Lombardo
de2433f889 android: Convert SingleChoiceSetting to Kotlin 2023-06-01 17:58:16 -07:00
Charles Lombardo
8983c1b568 android: Convert SettingsItem to Kotlin 2023-06-01 17:58:16 -07:00
Charles Lombardo
3774ad03a0 android: Convert HeaderSetting to Kotlin 2023-06-01 17:58:16 -07:00
Charles Lombardo
c6a30fa5f4 android: Convert DateTimeSetting to Kotlin 2023-06-01 17:58:16 -07:00
Charles Lombardo
61d3cc85d9 android: Convert CheckBoxSetting to Kotlin 2023-06-01 17:58:16 -07:00
Charles Lombardo
e0294387fd android: Convert GameAdapter to Kotlin 2023-06-01 17:58:16 -07:00
Charles Lombardo
a4f0606b49 android: Convert SettingsAdapter to Kotlin
Update SettingsAdapter.kt
2023-06-01 17:58:16 -07:00
Charles Lombardo
8e50be498c android: Convert EmulationActivity to Kotlin 2023-06-01 17:58:15 -07:00
Charles Lombardo
db61cbddb8 android: Use material slider in settings dialog 2023-06-01 17:58:15 -07:00
Charles Lombardo
d98d0934bf android: Convert Settings to Kotlin 2023-06-01 17:58:15 -07:00
Charles Lombardo
78ce062056 android: Use androidx preferences 2023-06-01 17:58:15 -07:00
bunnei
fe52eae6aa android: frontend: Add unique error strings for Vulkan initialization errors. 2023-06-01 17:58:15 -07:00
german77
26fcdfa866 android: Use the center of the object and reduce draw calls 2023-06-01 17:58:15 -07:00
german77
ca4dcc534c android: Replace old buttons with vectors 2023-06-01 17:58:15 -07:00
Charles Lombardo
79ca81d083 android: Enable Kotlin support 2023-06-01 17:58:15 -07:00
Charles Lombardo
05ac2ee236 android: Upgrade java version to 11 2023-06-01 17:58:15 -07:00
Charles Lombardo
64c7a0f362 android: Upgrade dependencies 2023-06-01 17:58:15 -07:00
Charles Lombardo
2612a650de android: Upgrade to AGP 7.4.2 2023-06-01 17:58:15 -07:00
Charles Lombardo
b96b73de7a android: Replace lintOptions with lint 2023-06-01 17:58:15 -07:00
Charles Lombardo
c602840394 android: Move namespace to app module build.gradle 2023-06-01 17:58:15 -07:00
Charles Lombardo
5db24dc615 android: bump compile/target sdk to 33 2023-06-01 17:58:15 -07:00
Charles Lombardo
999b2b5c31 android: Upgrade gradle to 8.0.1 2023-06-01 17:58:15 -07:00
liushuyu
7762a95a62 video_core: fix clang-format errors 2023-06-01 17:58:15 -07:00
liushuyu
3eb3728774 CMake: fix pkg-config behavior when building for Android 2023-06-01 17:58:15 -07:00
liushuyu
f0147a2971 CI: add Android build systems 2023-06-01 17:58:14 -07:00
bunnei
7e6363965d android: build.gradle: Cleanup build types. 2023-06-01 17:58:14 -07:00
bunnei
066608f25c android: frontend: settings: Add graphics debugging. 2023-06-01 17:58:14 -07:00
bunnei
c291d2c641 android: jni: Ensure system is only initialized once.
- Fixes likelihood that fastmem allocation succeeds.
2023-06-01 17:58:14 -07:00
bunnei
132c0c5245 video_core: vulkan_device: Correct error message for unsuitable driver. 2023-06-01 17:58:14 -07:00
bunnei
9df5c4ee2a android: frontend: Cleanup framerate counter. 2023-06-01 17:58:14 -07:00
bunnei
2e31a5fb6d android: vulkan: Implement adrenotools turbo mode. 2023-06-01 17:58:14 -07:00
bunnei
2fabcac53d android: vulkan_device: Disable VK_EXT_extended_dynamic_state2 on Qualcomm.
- Newer drivers report this as supported, but it is broken.
2023-06-01 17:58:14 -07:00
bunnei
d5e9afa0ff android: frontend: Add support for GPU driver selection. 2023-06-01 17:58:14 -07:00
bunnei
331eff1501 android: native: Add support for custom Vulkan driver loading. 2023-06-01 17:58:14 -07:00
bunnei
1ca44a3f0c core: frontend: Refactor GraphicsContext to its own module. 2023-06-01 17:58:14 -07:00
bunnei
6ed874cf76 common: dynamic_library: Add ctor for existing handle. 2023-06-01 17:58:14 -07:00
bunnei
dc2e756fc3 android: EmulationFragment: Always reset overlay.
- Ensures correct placement until we have better overlay configuration.
2023-06-01 17:58:14 -07:00
Billy Laws
68fe698120 Avoid using VectorExtractDynamic for subgroup mask on Adreno GPUs
This crashes their shader compiler for some reason.
2023-06-01 17:58:14 -07:00
Billy Laws
c1f5f1d581 Implement scaled vertex buffer format emulation
These formats are unsupported by mobile GPUs so they need to be emulated in shaders instead.
2023-06-01 17:58:14 -07:00
Billy Laws
1e2371057e Disable push descriptors on adreno drivers
Regular descriptors are around 1.5x faster to update.
2023-06-01 17:58:14 -07:00
Billy Laws
6ea54d1b13 Disable VK_EXT_extended_dynamic_state on mali 2023-06-01 17:58:14 -07:00
Billy Laws
d2cbe4252c Disable multithreaded pipeline compilation on Qualcomm drivers
This causes crashes during compilation on several 6xx and 5xx driver versions.
2023-06-01 17:58:13 -07:00
Narr the Reg
8a0495a56c android: Add motion sensor 2023-06-01 17:58:13 -07:00
Narr the Reg
830ca4627e android: Hook jni input properly 2023-06-01 17:58:13 -07:00
Narr the Reg
85b4c4e409 android: cleanup touch update loop 2023-06-01 17:58:13 -07:00
Narr the Reg
e20125ca2e android: Clean joystick overlay 2023-06-01 17:58:13 -07:00
Narr the Reg
edf29db8ee android: Clean dpad overlay 2023-06-01 17:58:13 -07:00
Narr the Reg
cfee9c5988 android: Clean button overlay 2023-06-01 17:58:13 -07:00
Narr the Reg
37529f023e android: Add all buttons to screen controller 2023-06-01 17:58:13 -07:00
Narr the Reg
8af8f6fc27 android: Apply clang format 2023-06-01 17:58:13 -07:00
bunnei
87dbc7c0a4 android: frontend: Implement game grid view. (#9) 2023-06-01 17:58:13 -07:00
german77
5a54309cc0 android: Replace notification icon with yuzu 2023-06-01 17:58:13 -07:00
bunnei
b8c3a2faa7 android: strings: Refresh key dumping URL. 2023-06-01 17:58:13 -07:00
bunnei
71328d6348 android: frontend: Modify ROM load messaging for invalid keys. 2023-06-01 17:58:13 -07:00
bunnei
fe3c6a564f android: frontend: Integrate key installation for SAF. 2023-06-01 17:58:13 -07:00
bunnei
2f385569ac android: jni: Add function to reload keys. 2023-06-01 17:58:13 -07:00
bunnei
cce03d72c6 core: crypto: key_manager: Add methods to reload & validate keys. 2023-06-01 17:58:13 -07:00
bunnei
628f932ded android: EmulationActivity: Temporarily disable running notification. 2023-06-01 17:58:13 -07:00
bunnei
99592aa808 android: Implement SAF support & migrate to SDK 31. (#4) 2023-06-01 17:58:13 -07:00
bunnei
af37869237 android: Harden emulation shutdown when loader fails. 2023-06-01 17:58:12 -07:00
bunnei
8c4638b3e3 android: SettingsFragmentPresenter: Fix default renderer backend. 2023-06-01 17:58:12 -07:00
bunnei
06e3fe4cb2 android: jni: native: Add lock around HaltEmulation, tighten run loop. 2023-06-01 17:58:12 -07:00
bunnei
55e457224e android: jni: native: Refactor locking for is_running. 2023-06-01 17:58:12 -07:00
bunnei
67095489d5 android: jni: native: Remove unnecessary atomic for is_running. 2023-06-01 17:58:12 -07:00
bunnei
042415e786 android: jni: native: Tighten up emulation start/stop signaling. 2023-06-01 17:58:12 -07:00
bunnei
3fed4d5a6a android: jni: native: Consolidate emulation state into EmulationSession singleton.
- Fixes state management issues across multiple boots.
- Fixes crashes related to unsafe access of perf stats.
2023-06-01 17:58:12 -07:00
bunnei
4cb7063d36 android: Frontend: Fix rendering aspect ratio & add a setting for it. 2023-06-01 17:58:12 -07:00
bunnei
52eef7963e android: Integrate settings frontend with yuzu & remove unused code. 2023-06-01 17:58:12 -07:00
Liam
670188d5bc externals: add adrenotools for bcenabler 2023-06-01 17:58:12 -07:00
Liam
dcc57c9a5a device_memory: Use smaller virtual reservation size for compatibility with 39-bit paging 2023-06-01 17:58:12 -07:00
bunnei
46310b8949 video_core: vulkan_device: Device initialization for Adreno. 2023-06-01 17:58:12 -07:00
bunnei
7ad682a69f video_core: vk_pipeline_cache: Disable support_descriptor_aliasing on Android. 2023-06-01 17:58:12 -07:00
bunnei
d691a76712 video_core: vk_swapchain: Fix image format for Android. 2023-06-01 17:58:12 -07:00
bunnei
594e322aa6 android: Minimize frontend & convert to yuzu. 2023-06-01 17:58:12 -07:00
bunnei
de42ff4549 video_core: vk_blit_screen: Rotate viewport for Android landscape. 2023-06-01 17:58:11 -07:00
bunnei
abd8b33f82 common: error: Fix for Android. 2023-06-01 17:58:11 -07:00
bunnei
4a9cac4d1d common: fs: Implement for Android. 2023-06-01 17:58:11 -07:00
bunnei
ddbb4b2e9a common: logging: Implement Android logcat backend. 2023-06-01 17:58:10 -07:00
bunnei
4a0ae1e0e2 common: host_memory: Implement for Android. 2023-06-01 17:58:10 -07:00
bunnei
d585a4c8aa android: Minimal JNI for yuzu. 2023-06-01 17:58:10 -07:00
bunnei
36b5c109e8 android: Add Citra frontend. 2023-06-01 17:58:10 -07:00
bunnei
6605545ed6 cmake: Integrate bundled FFmpeg for Android. 2023-06-01 17:58:10 -07:00
bunnei
89662cf18a cmake: Integrate submoduled LLVM & fixes for Android. 2023-06-01 17:58:10 -07:00
96 changed files with 590 additions and 2289 deletions

View File

@@ -43,7 +43,7 @@ body:
id: log
attributes:
label: Log File
description: A log file will help our developers to better diagnose and fix the issue. Instructions can be found [here](https://yuzu-emu.org/help/reference/log-files).
description: A log file will help our developers to better diagnose and fix the issue.
validations:
required: true
- type: textarea

View File

@@ -129,11 +129,6 @@ jobs:
- uses: actions/checkout@v3
with:
submodules: recursive
- name: set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'adopt'
- name: Set up cache
uses: actions/cache@v3
with:
@@ -165,3 +160,24 @@ jobs:
with:
name: android
path: artifacts/
release:
runs-on: ubuntu-latest
needs: [ android ]
if: ${{ startsWith(github.ref, 'refs/tags/') }}
steps:
- uses: actions/download-artifact@v3
- name: Create release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref_name }}
release_name: ${{ github.ref_name }}
draft: false
prerelease: false
- name: Upload artifacts
uses: alexellis/upload-assets@0.4.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
asset_paths: '["./**/*.tar.*","./**/*.AppImage","./**/*.7z","./**/*.zip","./**/*.apk","./**/*.aab"]'

2
.gitmodules vendored
View File

@@ -49,6 +49,6 @@
[submodule "cpp-jwt"]
path = externals/cpp-jwt
url = https://github.com/arun11299/cpp-jwt.git
[submodule "libadrenotools"]
[submodule "externals/libadrenotools"]
path = externals/libadrenotools
url = https://github.com/bylaws/libadrenotools

View File

@@ -20,7 +20,7 @@ CMAKE_DEPENDENT_OPTION(YUZU_USE_BUNDLED_SDL2 "Download bundled SDL2 binaries" ON
# On Linux system SDL2 is likely to be lacking HIDAPI support which have drawbacks but is needed for SDL motion
CMAKE_DEPENDENT_OPTION(YUZU_USE_EXTERNAL_SDL2 "Compile external SDL2" ON "ENABLE_SDL2;NOT MSVC" OFF)
cmake_dependent_option(ENABLE_LIBUSB "Enable the use of LibUSB" ON "NOT ANDROID" OFF)
option(ENABLE_LIBUSB "Enable the use of LibUSB" "NOT ${ANDROID}")
option(ENABLE_OPENGL "Enable OpenGL" ON)
mark_as_advanced(FORCE ENABLE_OPENGL)
@@ -49,7 +49,7 @@ option(YUZU_TESTS "Compile tests" "${BUILD_TESTING}")
option(YUZU_USE_PRECOMPILED_HEADERS "Use precompiled headers" ON)
cmake_dependent_option(YUZU_ROOM "Compile LDN room server" ON "NOT ANDROID" OFF)
option(YUZU_ROOM "Compile LDN room server" "NOT ${ANDROID}")
CMAKE_DEPENDENT_OPTION(YUZU_CRASH_DUMPS "Compile Windows crash dump (Minidump) support" OFF "WIN32" OFF)
@@ -255,7 +255,7 @@ endif()
# boost asio's concept usage doesn't play nicely with some compilers yet.
add_definitions(-DBOOST_ASIO_DISABLE_CONCEPTS)
if (MSVC)
add_compile_options($<$<COMPILE_LANGUAGE:CXX>:/std:c++20>)
add_compile_options($<$<COMPILE_LANGUAGE:CXX>:/std:c++latest>)
# boost still makes use of deprecated result_of.
add_definitions(-D_HAS_DEPRECATED_RESULT_OF)
@@ -279,7 +279,6 @@ find_package(LLVM MODULE COMPONENTS Demangle)
find_package(lz4 REQUIRED)
find_package(nlohmann_json 3.8 REQUIRED)
find_package(Opus 1.3 MODULE)
find_package(range-v3 REQUIRED)
find_package(ZLIB 1.2 REQUIRED)
find_package(zstd 1.5 REQUIRED)

View File

@@ -13,7 +13,7 @@ SPDX-License-Identifier: GPL-2.0-or-later
<h4 align="center"><b>yuzu</b> is the world's most popular, open-source, Nintendo Switch emulator — started by the creators of <a href="https://citra-emu.org" target="_blank">Citra</a>.
<br>
It is written in C++ with portability in mind, and we actively maintain builds for Windows, Linux and Android.
It is written in C++ with portability in mind, and we actively maintain builds for Windows and Linux.
</h4>
<p align="center">

View File

@@ -43,7 +43,7 @@ if (MSVC)
/Zo
/permissive-
/EHsc
/std:c++20
/std:c++latest
/utf-8
/volatile:iso
/Zc:externConstexpr
@@ -51,10 +51,8 @@ if (MSVC)
/Zc:throwingNew
/GT
# Modules
/experimental:module- # Disable module support explicitly due to conflicts with precompiled headers
# External headers diagnostics
/experimental:external # Enables the external headers options. This option isn't required in Visual Studio 2019 version 16.10 and later
/external:anglebrackets # Treats all headers included by #include <header>, where the header file is enclosed in angle brackets (< >), as external headers
/external:W0 # Sets the default warning level to 0 for external headers, effectively turning off warnings for external headers

View File

@@ -1,8 +1,6 @@
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
import android.annotation.SuppressLint
plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
@@ -37,7 +35,7 @@ android {
jvmTarget = "17"
}
packaging {
packagingOptions {
// This is necessary for libadrenotools custom driver loading
jniLibs.useLegacyPackaging = true
}
@@ -57,11 +55,9 @@ android {
applicationId = "org.yuzu.yuzu_emu"
minSdk = 30
targetSdk = 33
versionCode = 1
versionName = getGitVersion()
ndk {
@SuppressLint("ChromeOsAbiSupport")
abiFilters += listOf("arm64-v8a")
}

View File

@@ -6,10 +6,17 @@ SPDX-License-Identifier: GPL-3.0-or-later
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-feature android:name="android.hardware.touchscreen" android:required="false" />
<uses-feature android:name="android.hardware.gamepad" android:required="false" />
<uses-feature android:name="android.software.leanback" android:required="false" />
<uses-feature android:name="android.hardware.vulkan.version" android:version="0x401000" android:required="true" />
<uses-feature
android:name="android.hardware.touchscreen"
android:required="false"/>
<uses-feature
android:name="android.hardware.gamepad"
android:required="false"/>
<uses-feature
android:name="android.hardware.vulkan.version"
android:version="0x401000"
android:required="true" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
@@ -24,7 +31,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
android:hasFragileUserData="true"
android:supportsRtl="true"
android:isGame="true"
android:banner="@drawable/tv_banner"
android:banner="@drawable/ic_launcher"
android:extractNativeLibs="true"
android:fullBackupContent="@xml/data_extraction_rules"
android:dataExtractionRules="@xml/data_extraction_rules_api_31"
@@ -37,10 +44,9 @@ SPDX-License-Identifier: GPL-3.0-or-later
<!-- This intentfilter marks this Activity as the one that gets launched from Home screen. -->
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER" />
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>

View File

@@ -5,6 +5,7 @@ package org.yuzu.yuzu_emu.activities
import android.app.Activity
import android.content.Context
import android.content.DialogInterface
import android.content.Intent
import android.content.res.Configuration
import android.graphics.Rect
@@ -12,30 +13,22 @@ import android.hardware.Sensor
import android.hardware.SensorEvent
import android.hardware.SensorEventListener
import android.hardware.SensorManager
import android.hardware.display.DisplayManager
import android.os.Bundle
import android.view.Display
import android.view.InputDevice
import android.view.KeyEvent
import android.view.MotionEvent
import android.view.Surface
import android.view.View
import android.view.WindowManager
import android.view.inputmethod.InputMethodManager
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.getSystemService
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.WindowInsetsControllerCompat
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.window.layout.WindowInfoTracker
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import androidx.preference.PreferenceManager
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.slider.Slider.OnChangeListener
import org.yuzu.yuzu_emu.NativeLibrary
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.features.settings.model.SettingsViewModel
import org.yuzu.yuzu_emu.databinding.DialogSliderBinding
import org.yuzu.yuzu_emu.features.settings.model.Settings
import org.yuzu.yuzu_emu.fragments.EmulationFragment
import org.yuzu.yuzu_emu.model.Game
import org.yuzu.yuzu_emu.utils.ControllerMappingHelper
@@ -51,6 +44,7 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
private var controllerMappingHelper: ControllerMappingHelper? = null
var isActivityRecreated = false
private var menuVisible = false
private var emulationFragment: EmulationFragment? = null
private lateinit var nfcReader: NfcReader
private lateinit var inputHandler: InputHandler
@@ -62,8 +56,6 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
private lateinit var game: Game
private val settingsViewModel: SettingsViewModel by viewModels()
override fun onDestroy() {
stopForegroundService(this)
super.onDestroy()
@@ -72,8 +64,6 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
override fun onCreate(savedInstanceState: Bundle?) {
ThemeHelper.setTheme(this)
settingsViewModel.settings.loadSettings()
super.onCreate(savedInstanceState)
if (savedInstanceState == null) {
// Get params we were passed
@@ -108,14 +98,6 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
inputHandler = InputHandler()
inputHandler.initialize()
lifecycleScope.launch(Dispatchers.Main) {
lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
WindowInfoTracker.getOrCreate(this@EmulationActivity)
.windowLayoutInfo(this@EmulationActivity)
.collect { emulationFragment?.updateCurrentLayout(this@EmulationActivity, it) }
}
}
// Start a foreground service to prevent the app from getting killed in the background
val startIntent = Intent(this, ForegroundService::class.java)
startForegroundService(startIntent)
@@ -259,21 +241,20 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
override fun onAccuracyChanged(sensor: Sensor, i: Int) {}
private fun getAdjustedRotation():Int {
val rotation = getSystemService<DisplayManager>()!!.getDisplay(Display.DEFAULT_DISPLAY).rotation
val rotation = windowManager.defaultDisplay.rotation;
val config: Configuration = resources.configuration
if ((config.screenLayout and Configuration.SCREENLAYOUT_LONG_YES) != 0 ||
(config.screenLayout and Configuration.SCREENLAYOUT_LONG_NO) == 0 ||
(config.screenLayout and Configuration.SCREENLAYOUT_SIZE_SMALL) != 0) {
return rotation
(config.screenLayout and Configuration.SCREENLAYOUT_LONG_NO) == 0) {
return rotation;
}
when (rotation) {
Surface.ROTATION_0 -> return Surface.ROTATION_90
Surface.ROTATION_90 -> return Surface.ROTATION_0
Surface.ROTATION_180 -> return Surface.ROTATION_270
Surface.ROTATION_270 -> return Surface.ROTATION_180
Surface.ROTATION_0 -> return Surface.ROTATION_90;
Surface.ROTATION_90 -> return Surface.ROTATION_0;
Surface.ROTATION_180 -> return Surface.ROTATION_270;
Surface.ROTATION_270 -> return Surface.ROTATION_180;
}
return rotation
return rotation;
}
private fun restoreState(savedInstanceState: Bundle) {
@@ -281,13 +262,18 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
}
private fun enableFullscreenImmersive() {
WindowCompat.setDecorFitsSystemWindows(window, false)
window.attributes.layoutInDisplayCutoutMode =
WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
WindowInsetsControllerCompat(window, window.decorView).let { controller ->
controller.hide(WindowInsetsCompat.Type.systemBars())
controller.systemBarsBehavior =
WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
}
window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN)
// It would be nice to use IMMERSIVE_STICKY, but that doesn't show the toolbar.
window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or
View.SYSTEM_UI_FLAG_FULLSCREEN or
View.SYSTEM_UI_FLAG_IMMERSIVE
}
private fun startMotionSensorListener() {

View File

@@ -1,54 +0,0 @@
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
package org.yuzu.yuzu_emu.adapters
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.ViewHolder
import org.yuzu.yuzu_emu.YuzuApplication
import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding
import org.yuzu.yuzu_emu.fragments.LicenseBottomSheetDialogFragment
import org.yuzu.yuzu_emu.model.License
class LicenseAdapter(private val activity: AppCompatActivity, var licenses: List<License>) :
RecyclerView.Adapter<LicenseAdapter.LicenseViewHolder>(),
View.OnClickListener {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): LicenseViewHolder {
val binding =
ListItemSettingBinding.inflate(LayoutInflater.from(parent.context), parent, false)
binding.root.setOnClickListener(this)
return LicenseViewHolder(binding)
}
override fun getItemCount(): Int = licenses.size
override fun onBindViewHolder(holder: LicenseViewHolder, position: Int) {
holder.bind(licenses[position])
}
override fun onClick(view: View) {
val license = (view.tag as LicenseViewHolder).license
LicenseBottomSheetDialogFragment.newInstance(license)
.show(activity.supportFragmentManager, LicenseBottomSheetDialogFragment.TAG)
}
inner class LicenseViewHolder(val binding: ListItemSettingBinding) : ViewHolder(binding.root) {
lateinit var license: License
init {
itemView.tag = this
}
fun bind(license: License) {
this.license = license
val context = YuzuApplication.appContext
binding.textSettingName.text = context.getString(license.titleId)
binding.textSettingDescription.text = context.getString(license.descriptionId)
}
}
}

View File

@@ -63,7 +63,7 @@ class KeyboardDialogFragment : DialogFragment() {
val headerText =
config.header_text!!.ifEmpty { resources.getString(R.string.software_keyboard) }
val okText =
config.ok_text!!.ifEmpty { resources.getString(R.string.submit) }
config.ok_text!!.ifEmpty { resources.getString(android.R.string.ok) }
return MaterialAlertDialogBuilder(requireContext())
.setTitle(headerText)

View File

@@ -39,7 +39,7 @@ class Settings {
val isEmpty: Boolean
get() = sections.isEmpty()
fun loadSettings(view: SettingsActivityView? = null) {
fun loadSettings(view: SettingsActivityView) {
sections = SettingsSectionMap()
loadYuzuSettings(view)
if (!TextUtils.isEmpty(gameId)) {
@@ -48,13 +48,13 @@ class Settings {
isLoaded = true
}
private fun loadYuzuSettings(view: SettingsActivityView?) {
private fun loadYuzuSettings(view: SettingsActivityView) {
for ((fileName) in configFileSectionsMap) {
sections.putAll(SettingsFile.readFile(fileName, view))
}
}
private fun loadCustomGameSettings(gameId: String, view: SettingsActivityView?) {
private fun loadCustomGameSettings(gameId: String, view: SettingsActivityView) {
// Custom game settings
mergeSections(SettingsFile.readCustomGameSettings(gameId, view))
}
@@ -108,7 +108,6 @@ class Settings {
const val SECTION_AUDIO = "Audio"
const val SECTION_CPU = "Cpu"
const val SECTION_THEME = "Theme"
const val SECTION_DEBUG = "Debug"
const val PREF_OVERLAY_INIT = "OverlayInit"
const val PREF_CONTROL_SCALE = "controlScale"

View File

@@ -6,9 +6,10 @@ package org.yuzu.yuzu_emu.features.settings.model.view
import org.yuzu.yuzu_emu.features.settings.model.AbstractSetting
class SubmenuSetting(
setting: AbstractSetting?,
titleId: Int,
descriptionId: Int,
val menuKey: String
) : SettingsItem(null, titleId, descriptionId) {
) : SettingsItem(setting, titleId, descriptionId) {
override val type = TYPE_SUBMENU
}

View File

@@ -68,7 +68,6 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
Settings.SECTION_RENDERER -> addGraphicsSettings(sl)
Settings.SECTION_AUDIO -> addAudioSettings(sl)
Settings.SECTION_THEME -> addThemeSettings(sl)
Settings.SECTION_DEBUG -> addDebugSettings(sl)
else -> {
fragmentView.showToastMessage("Unimplemented menu", false)
return
@@ -79,10 +78,11 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
}
private fun addConfigSettings(sl: ArrayList<SettingsItem>) {
settingsActivity.setToolbarTitle(settingsActivity.getString(R.string.advanced_settings))
settingsActivity.setToolbarTitle(settingsActivity.getString(R.string.preferences_advanced_settings))
sl.apply {
add(
SubmenuSetting(
null,
R.string.preferences_general,
0,
Settings.SECTION_GENERAL
@@ -90,6 +90,7 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
)
add(
SubmenuSetting(
null,
R.string.preferences_system,
0,
Settings.SECTION_SYSTEM
@@ -97,6 +98,7 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
)
add(
SubmenuSetting(
null,
R.string.preferences_graphics,
0,
Settings.SECTION_RENDERER
@@ -104,18 +106,12 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
)
add(
SubmenuSetting(
null,
R.string.preferences_audio,
0,
Settings.SECTION_AUDIO
)
)
add(
SubmenuSetting(
R.string.preferences_debug,
0,
Settings.SECTION_DEBUG
)
)
add(
RunnableSetting(
R.string.reset_to_default,
@@ -227,7 +223,17 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
private fun addGraphicsSettings(sl: ArrayList<SettingsItem>) {
settingsActivity.setToolbarTitle(settingsActivity.getString(R.string.preferences_graphics))
sl.apply {
add(
SingleChoiceSetting(
IntSetting.RENDERER_BACKEND,
R.string.renderer_api,
0,
R.array.rendererApiNames,
R.array.rendererApiValues,
IntSetting.RENDERER_BACKEND.key,
IntSetting.RENDERER_BACKEND.defaultValue
)
)
add(
SingleChoiceSetting(
IntSetting.RENDERER_ACCURACY,
@@ -321,6 +327,15 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
IntSetting.RENDERER_ASYNCHRONOUS_SHADERS.defaultValue
)
)
add(
SwitchSetting(
IntSetting.RENDERER_DEBUG,
R.string.renderer_debug,
R.string.renderer_debug_description,
IntSetting.RENDERER_DEBUG.key,
IntSetting.RENDERER_DEBUG.defaultValue
)
)
}
}
@@ -436,30 +451,4 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
)
}
}
private fun addDebugSettings(sl: ArrayList<SettingsItem>) {
settingsActivity.setToolbarTitle(settingsActivity.getString(R.string.preferences_debug))
sl.apply {
add(
SingleChoiceSetting(
IntSetting.RENDERER_BACKEND,
R.string.renderer_api,
0,
R.array.rendererApiNames,
R.array.rendererApiValues,
IntSetting.RENDERER_BACKEND.key,
IntSetting.RENDERER_BACKEND.defaultValue
)
)
add(
SwitchSetting(
IntSetting.RENDERER_DEBUG,
R.string.renderer_debug,
R.string.renderer_debug_description,
IntSetting.RENDERER_DEBUG.key,
IntSetting.RENDERER_DEBUG.defaultValue
)
)
}
}
}

View File

@@ -37,7 +37,7 @@ object SettingsFile {
private fun readFile(
ini: File?,
isCustomGame: Boolean,
view: SettingsActivityView? = null
view: SettingsActivityView?
): HashMap<String, SettingSection?> {
val sections: HashMap<String, SettingSection?> = SettingsSectionMap()
var reader: BufferedReader? = null
@@ -74,13 +74,10 @@ object SettingsFile {
return sections
}
fun readFile(fileName: String, view: SettingsActivityView?): HashMap<String, SettingSection?> {
fun readFile(fileName: String, view: SettingsActivityView): HashMap<String, SettingSection?> {
return readFile(getSettingsFile(fileName), false, view)
}
fun readFile(fileName: String): HashMap<String, SettingSection?> =
readFile(getSettingsFile(fileName), false)
/**
* Reads a given .ini file from disk and returns it as a HashMap of SettingSections, themselves
* effectively a HashMap of key/value settings. If unsuccessful, outputs an error telling why it
@@ -91,7 +88,7 @@ object SettingsFile {
*/
fun readCustomGameSettings(
gameId: String,
view: SettingsActivityView?
view: SettingsActivityView
): HashMap<String, SettingSection?> {
return readFile(getCustomGameSettingsFile(gameId), true, view)
}

View File

@@ -15,12 +15,13 @@ import android.view.View
import android.view.ViewGroup
import android.view.ViewGroup.MarginLayoutParams
import android.widget.Toast
import androidx.core.content.ContextCompat
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updatePadding
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.navigation.findNavController
import androidx.navigation.fragment.findNavController
import com.google.android.material.transition.MaterialSharedAxis
import org.yuzu.yuzu_emu.BuildConfig
import org.yuzu.yuzu_emu.R
@@ -37,7 +38,6 @@ class AboutFragment : Fragment() {
super.onCreate(savedInstanceState)
enterTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)
returnTransition = MaterialSharedAxis(MaterialSharedAxis.X, false)
reenterTransition = MaterialSharedAxis(MaterialSharedAxis.X, false)
}
override fun onCreateView(
@@ -54,7 +54,7 @@ class AboutFragment : Fragment() {
homeViewModel.setStatusBarShadeVisibility(visible = false)
binding.toolbarAbout.setNavigationOnClickListener {
binding.root.findNavController().popBackStack()
parentFragmentManager.primaryNavigationFragment?.findNavController()?.popBackStack()
}
binding.imageLogo.setOnLongClickListener {
@@ -67,10 +67,6 @@ class AboutFragment : Fragment() {
}
binding.buttonContributors.setOnClickListener { openLink(getString(R.string.contributors_link)) }
binding.buttonLicenses.setOnClickListener {
exitTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)
binding.root.findNavController().navigate(R.id.action_aboutFragment_to_licensesFragment)
}
binding.textBuildHash.text = BuildConfig.GIT_HASH
binding.buttonBuildHash.setOnClickListener {

View File

@@ -8,14 +8,10 @@ import android.app.AlertDialog
import android.content.Context
import android.content.DialogInterface
import android.content.SharedPreferences
import android.content.pm.ActivityInfo
import android.content.res.Resources
import android.graphics.Color
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.util.Rational
import android.util.TypedValue
import android.view.*
import android.widget.TextView
import androidx.activity.OnBackPressedCallback
@@ -24,11 +20,8 @@ import androidx.core.content.res.ResourcesCompat
import androidx.core.graphics.Insets
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updatePadding
import androidx.fragment.app.Fragment
import androidx.preference.PreferenceManager
import androidx.window.layout.FoldingFeature
import androidx.window.layout.WindowLayoutInfo
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.slider.Slider
import org.yuzu.yuzu_emu.NativeLibrary
@@ -37,7 +30,6 @@ import org.yuzu.yuzu_emu.YuzuApplication
import org.yuzu.yuzu_emu.activities.EmulationActivity
import org.yuzu.yuzu_emu.databinding.DialogOverlayAdjustBinding
import org.yuzu.yuzu_emu.databinding.FragmentEmulationBinding
import org.yuzu.yuzu_emu.features.settings.model.IntSetting
import org.yuzu.yuzu_emu.features.settings.model.Settings
import org.yuzu.yuzu_emu.features.settings.ui.SettingsActivity
import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile
@@ -160,18 +152,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
if (!DirectoryInitialization.areDirectoriesReady) {
DirectoryInitialization.start(requireContext())
}
binding.surfaceEmulation.setAspectRatio(
when (IntSetting.RENDERER_ASPECT_RATIO.int) {
0 -> Rational(16, 9)
1 -> Rational(4, 3)
2 -> Rational(21, 9)
3 -> Rational(16, 10)
4 -> null // Stretch
else -> Rational(16, 9)
}
)
emulationState.run(emulationActivity!!.isActivityRecreated)
}
@@ -231,33 +211,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
}
}
private val Number.toPx get() = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, this.toFloat(), Resources.getSystem().displayMetrics).toInt()
fun updateCurrentLayout(emulationActivity: EmulationActivity, newLayoutInfo: WindowLayoutInfo) {
val isFolding = (newLayoutInfo.displayFeatures.find { it is FoldingFeature } as? FoldingFeature)?.let {
if (it.isSeparating) {
emulationActivity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
if (it.orientation == FoldingFeature.Orientation.HORIZONTAL) {
binding.surfaceEmulation.layoutParams.height = it.bounds.top
binding.inGameMenu.layoutParams.height = it.bounds.bottom
binding.overlayContainer.layoutParams.height = it.bounds.bottom - 48.toPx
binding.overlayContainer.updatePadding(0, 0, 0, 24.toPx)
}
}
it.isSeparating
} ?: false
if (!isFolding) {
binding.surfaceEmulation.layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT
binding.inGameMenu.layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT
binding.overlayContainer.layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT
binding.overlayContainer.updatePadding(0, 0, 0, 0)
emulationActivity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
}
binding.surfaceInputOverlay.requestLayout()
binding.inGameMenu.requestLayout()
binding.overlayContainer.requestLayout()
}
override fun surfaceCreated(holder: SurfaceHolder) {
// We purposely don't do anything here.
// All work is done in surfaceChanged, which we are guaranteed to get even for surface creation.
@@ -328,7 +281,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
.setPositiveButton(android.R.string.ok) { _, _ ->
refreshInputOverlay()
}
.setNegativeButton(android.R.string.cancel, null)
.setNeutralButton(R.string.emulation_toggle_all) { _, _ -> }
.show()

View File

@@ -19,10 +19,10 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import androidx.core.content.ContextCompat
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updatePadding
import androidx.documentfile.provider.DocumentFile
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.navigation.fragment.findNavController
@@ -40,7 +40,6 @@ import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile
import org.yuzu.yuzu_emu.model.HomeSetting
import org.yuzu.yuzu_emu.model.HomeViewModel
import org.yuzu.yuzu_emu.ui.main.MainActivity
import org.yuzu.yuzu_emu.utils.FileUtil
import org.yuzu.yuzu_emu.utils.GpuDriverHelper
class HomeSettingsFragment : Fragment() {
@@ -109,16 +108,6 @@ class HomeSettingsFragment : Fragment() {
R.string.install_prod_keys_description,
R.drawable.ic_unlock
) { mainActivity.getProdKey.launch(arrayOf("*/*")) },
HomeSetting(
R.string.install_firmware,
R.string.install_firmware_description,
R.drawable.ic_firmware
) { mainActivity.getFirmware.launch(arrayOf("application/zip")) },
HomeSetting(
R.string.share_log,
R.string.share_log_description,
R.drawable.ic_log
) { shareLog() },
HomeSetting(
R.string.about,
R.string.about_description,
@@ -273,29 +262,6 @@ class HomeSettingsFragment : Fragment() {
.show()
}
private fun shareLog() {
val file = DocumentFile.fromSingleUri(
mainActivity,
DocumentsContract.buildDocumentUri(
DocumentProvider.AUTHORITY,
"${DocumentProvider.ROOT_ID}/log/yuzu_log.txt"
)
)!!
if (file.exists()) {
val intent = Intent(Intent.ACTION_SEND)
.setDataAndType(file.uri, FileUtil.TEXT_PLAIN)
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
.putExtra(Intent.EXTRA_STREAM, file.uri)
startActivity(Intent.createChooser(intent, getText(R.string.share_log)))
} else {
Toast.makeText(
requireContext(),
getText(R.string.share_log_missing),
Toast.LENGTH_SHORT
).show()
}
}
private fun setInsets() =
ViewCompat.setOnApplyWindowInsetsListener(binding.root) { view: View, windowInsets: WindowInsetsCompat ->
val barInsets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())

View File

@@ -11,7 +11,6 @@ import android.provider.DocumentsContract
import android.widget.Toast
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.documentfile.provider.DocumentFile
import androidx.fragment.app.DialogFragment
import com.google.android.material.dialog.MaterialAlertDialogBuilder
@@ -23,14 +22,17 @@ import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.YuzuApplication
import org.yuzu.yuzu_emu.features.DocumentProvider
import org.yuzu.yuzu_emu.getPublicFilesDir
import org.yuzu.yuzu_emu.utils.FileUtil
import java.io.BufferedInputStream
import java.io.BufferedOutputStream
import java.io.File
import java.io.FileOutputStream
import java.io.FilenameFilter
import java.io.IOException
import java.io.InputStream
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
import java.util.zip.ZipEntry
import java.util.zip.ZipInputStream
import java.util.zip.ZipOutputStream
class ImportExportSavesFragment : DialogFragment() {
@@ -47,7 +49,6 @@ class ImportExportSavesFragment : DialogFragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val activity = requireActivity() as AppCompatActivity
val activityResultRegistry = requireActivity().activityResultRegistry
startForResultExportSave = activityResultRegistry.register(
@@ -60,7 +61,7 @@ class ImportExportSavesFragment : DialogFragment() {
"documentPickerKey",
ActivityResultContracts.OpenDocument()
) {
it?.let { uri -> importSave(uri, activity) }
it?.let { uri -> importSave(uri) }
}
}
@@ -121,6 +122,33 @@ class ImportExportSavesFragment : DialogFragment() {
return true
}
/**
* Extracts the save files located in the given zip file and copies them to the saves folder.
* @exception IOException if the file was being created outside of the target directory
*/
private fun unzip(zipStream: InputStream, destDir: File): Boolean {
val zis = ZipInputStream(BufferedInputStream(zipStream))
var entry: ZipEntry? = zis.nextEntry
while (entry != null) {
val entryName = entry.name
val entryFile = File(destDir, entryName)
if (!entryFile.canonicalPath.startsWith(destDir.canonicalPath + File.separator)) {
zis.close()
throw IOException("Entry is outside of the target dir: " + entryFile.name)
}
if (entry.isDirectory) {
entryFile.mkdirs()
} else {
entryFile.parentFile?.mkdirs()
entryFile.createNewFile()
entryFile.outputStream().use { fos -> zis.copyTo(fos) }
}
entry = zis.nextEntry
}
zis.close()
return true
}
/**
* Exports the save file located in the given folder path by creating a zip file and sharing it via intent.
*/
@@ -155,7 +183,7 @@ class ImportExportSavesFragment : DialogFragment() {
* Imports the save files contained in the zip file, and replaces any existing ones with the new save file.
* @param zipUri The Uri of the zip file containing the save file(s) to import.
*/
private fun importSave(zipUri: Uri, activity: AppCompatActivity) {
private fun importSave(zipUri: Uri) {
val inputZip = context.contentResolver.openInputStream(zipUri)
// A zip needs to have at least one subfolder named after a TitleId in order to be considered valid.
var validZip = false
@@ -174,7 +202,7 @@ class ImportExportSavesFragment : DialogFragment() {
try {
CoroutineScope(Dispatchers.IO).launch {
FileUtil.unzip(inputZip, cacheSaveDir)
unzip(inputZip, cacheSaveDir)
cacheSaveDir.list(filterTitleId)?.forEach { savePath ->
File(savesFolder, savePath).deleteRecursively()
File(cacheSaveDir, savePath).copyRecursively(File(savesFolder, savePath), true)
@@ -186,7 +214,7 @@ class ImportExportSavesFragment : DialogFragment() {
MessageDialogFragment.newInstance(
R.string.save_file_invalid_zip_structure,
R.string.save_file_invalid_zip_structure_description
).show(activity.supportFragmentManager, MessageDialogFragment.TAG)
).show(childFragmentManager, MessageDialogFragment.TAG)
return@withContext
}
Toast.makeText(

View File

@@ -1,70 +0,0 @@
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
package org.yuzu.yuzu_emu.fragments
import android.app.Dialog
import android.os.Bundle
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.ViewModelProvider
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import org.yuzu.yuzu_emu.databinding.DialogProgressBarBinding
import org.yuzu.yuzu_emu.model.TaskViewModel
class IndeterminateProgressDialogFragment : DialogFragment() {
private val taskViewModel: TaskViewModel by activityViewModels()
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val titleId = requireArguments().getInt(TITLE)
val progressBinding = DialogProgressBarBinding.inflate(layoutInflater)
progressBinding.progressBar.isIndeterminate = true
val dialog = MaterialAlertDialogBuilder(requireContext())
.setTitle(titleId)
.setView(progressBinding.root)
.create()
dialog.setCanceledOnTouchOutside(false)
taskViewModel.isComplete.observe(this) { complete ->
if (complete) {
dialog.dismiss()
when (val result = taskViewModel.result.value) {
is String -> Toast.makeText(requireContext(), result, Toast.LENGTH_LONG).show()
is MessageDialogFragment -> result.show(
parentFragmentManager,
MessageDialogFragment.TAG
)
}
taskViewModel.clear()
}
}
if (taskViewModel.isRunning.value == false) {
taskViewModel.runTask()
}
return dialog
}
companion object {
const val TAG = "IndeterminateProgressDialogFragment"
private const val TITLE = "Title"
fun newInstance(
activity: AppCompatActivity,
titleId: Int,
task: () -> Any
): IndeterminateProgressDialogFragment {
val dialog = IndeterminateProgressDialogFragment()
val args = Bundle()
ViewModelProvider(activity)[TaskViewModel::class.java].task = task
args.putInt(TITLE, titleId)
dialog.arguments = args
return dialog
}
}
}

View File

@@ -1,59 +0,0 @@
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
package org.yuzu.yuzu_emu.fragments
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import org.yuzu.yuzu_emu.databinding.DialogLicenseBinding
import org.yuzu.yuzu_emu.model.License
import org.yuzu.yuzu_emu.utils.SerializableHelper.parcelable
class LicenseBottomSheetDialogFragment : BottomSheetDialogFragment() {
private var _binding: DialogLicenseBinding? = null
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = DialogLicenseBinding.inflate(layoutInflater)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
BottomSheetBehavior.from<View>(view.parent as View).state =
BottomSheetBehavior.STATE_HALF_EXPANDED
val license = requireArguments().parcelable<License>(LICENSE)!!
binding.apply {
textTitle.setText(license.titleId)
textLink.setText(license.linkId)
textCopyright.setText(license.copyrightId)
textLicense.setText(license.licenseId)
}
}
companion object {
const val TAG = "LicenseBottomSheetDialogFragment"
const val LICENSE = "License"
fun newInstance(
license: License
): LicenseBottomSheetDialogFragment {
val dialog = LicenseBottomSheetDialogFragment()
val bundle = Bundle()
bundle.putParcelable(LICENSE, license)
dialog.arguments = bundle
return dialog
}
}
}

View File

@@ -1,137 +0,0 @@
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
package org.yuzu.yuzu_emu.fragments
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.ViewGroup.MarginLayoutParams
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updatePadding
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.navigation.findNavController
import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.material.transition.MaterialSharedAxis
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.adapters.LicenseAdapter
import org.yuzu.yuzu_emu.databinding.FragmentLicensesBinding
import org.yuzu.yuzu_emu.model.HomeViewModel
import org.yuzu.yuzu_emu.model.License
class LicensesFragment : Fragment() {
private var _binding: FragmentLicensesBinding? = null
private val binding get() = _binding!!
private val homeViewModel: HomeViewModel by activityViewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enterTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)
returnTransition = MaterialSharedAxis(MaterialSharedAxis.X, false)
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentLicensesBinding.inflate(layoutInflater)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
homeViewModel.setNavigationVisibility(visible = false, animated = true)
homeViewModel.setStatusBarShadeVisibility(visible = false)
binding.toolbarLicenses.setNavigationOnClickListener {
binding.root.findNavController().popBackStack()
}
val licenses = listOf(
License(
R.string.license_fidelityfx_fsr,
R.string.license_fidelityfx_fsr_description,
R.string.license_fidelityfx_fsr_link,
R.string.license_fidelityfx_fsr_copyright,
R.string.license_fidelityfx_fsr_text
),
License(
R.string.license_cubeb,
R.string.license_cubeb_description,
R.string.license_cubeb_link,
R.string.license_cubeb_copyright,
R.string.license_cubeb_text
),
License(
R.string.license_dynarmic,
R.string.license_dynarmic_description,
R.string.license_dynarmic_link,
R.string.license_dynarmic_copyright,
R.string.license_dynarmic_text
),
License(
R.string.license_ffmpeg,
R.string.license_ffmpeg_description,
R.string.license_ffmpeg_link,
R.string.license_ffmpeg_copyright,
R.string.license_ffmpeg_text
),
License(
R.string.license_opus,
R.string.license_opus_description,
R.string.license_opus_link,
R.string.license_opus_copyright,
R.string.license_opus_text
),
License(
R.string.license_sirit,
R.string.license_sirit_description,
R.string.license_sirit_link,
R.string.license_sirit_copyright,
R.string.license_sirit_text
),
License(
R.string.license_adreno_tools,
R.string.license_adreno_tools_description,
R.string.license_adreno_tools_link,
R.string.license_adreno_tools_copyright,
R.string.license_adreno_tools_text
)
)
binding.listLicenses.apply {
layoutManager = LinearLayoutManager(requireContext())
adapter = LicenseAdapter(requireActivity() as AppCompatActivity, licenses)
}
setInsets()
}
private fun setInsets() =
ViewCompat.setOnApplyWindowInsetsListener(binding.root) { _: View, windowInsets: WindowInsetsCompat ->
val barInsets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
val cutoutInsets = windowInsets.getInsets(WindowInsetsCompat.Type.displayCutout())
val leftInsets = barInsets.left + cutoutInsets.left
val rightInsets = barInsets.right + cutoutInsets.right
val mlpAppBar = binding.appbarLicenses.layoutParams as MarginLayoutParams
mlpAppBar.leftMargin = leftInsets
mlpAppBar.rightMargin = rightInsets
binding.appbarLicenses.layoutParams = mlpAppBar
val mlpScrollAbout = binding.listLicenses.layoutParams as MarginLayoutParams
mlpScrollAbout.leftMargin = leftInsets
mlpScrollAbout.rightMargin = rightInsets
binding.listLicenses.layoutParams = mlpScrollAbout
binding.listLicenses.updatePadding(bottom = barInsets.bottom)
windowInsets
}
}

View File

@@ -1,16 +0,0 @@
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
package org.yuzu.yuzu_emu.model
import android.os.Parcelable
import kotlinx.parcelize.Parcelize
@Parcelize
data class License(
val titleId: Int,
val descriptionId: Int,
val linkId: Int,
val copyrightId: Int,
val licenseId: Int
) : Parcelable

View File

@@ -1,47 +0,0 @@
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
package org.yuzu.yuzu_emu.model
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
class TaskViewModel : ViewModel() {
private val _result = MutableLiveData<Any>()
val result: LiveData<Any> = _result
private val _isComplete = MutableLiveData<Boolean>()
val isComplete: LiveData<Boolean> = _isComplete
private val _isRunning = MutableLiveData<Boolean>()
val isRunning: LiveData<Boolean> = _isRunning
lateinit var task: () -> Any
init {
clear()
}
fun clear() {
_result.value = Any()
_isComplete.value = false
_isRunning.value = false
}
fun runTask() {
if (_isRunning.value == true) {
return
}
_isRunning.value = true
viewModelScope.launch(Dispatchers.IO) {
val res = task()
_result.postValue(res)
_isComplete.postValue(true)
}
}
}

View File

@@ -35,16 +35,12 @@ import org.yuzu.yuzu_emu.activities.EmulationActivity
import org.yuzu.yuzu_emu.databinding.ActivityMainBinding
import org.yuzu.yuzu_emu.databinding.DialogProgressBarBinding
import org.yuzu.yuzu_emu.features.settings.model.Settings
import org.yuzu.yuzu_emu.features.settings.model.SettingsViewModel
import org.yuzu.yuzu_emu.features.settings.ui.SettingsActivity
import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile
import org.yuzu.yuzu_emu.fragments.IndeterminateProgressDialogFragment
import org.yuzu.yuzu_emu.fragments.MessageDialogFragment
import org.yuzu.yuzu_emu.model.GamesViewModel
import org.yuzu.yuzu_emu.model.HomeViewModel
import org.yuzu.yuzu_emu.utils.*
import java.io.File
import java.io.FilenameFilter
import java.io.IOException
class MainActivity : AppCompatActivity(), ThemeProvider {
@@ -52,7 +48,6 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
private val homeViewModel: HomeViewModel by viewModels()
private val gamesViewModel: GamesViewModel by viewModels()
private val settingsViewModel: SettingsViewModel by viewModels()
override var themeId: Int = 0
@@ -60,8 +55,6 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
val splashScreen = installSplashScreen()
splashScreen.setKeepOnScreenCondition { !DirectoryInitialization.areDirectoriesReady }
settingsViewModel.settings.loadSettings()
ThemeHelper.setTheme(this)
super.onCreate(savedInstanceState)
@@ -322,58 +315,6 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
}
}
val getFirmware =
registerForActivityResult(ActivityResultContracts.OpenDocument()) { result ->
if (result == null)
return@registerForActivityResult
val inputZip = contentResolver.openInputStream(result)
if (inputZip == null) {
Toast.makeText(
applicationContext,
getString(R.string.fatal_error),
Toast.LENGTH_LONG
).show()
return@registerForActivityResult
}
val filterNCA = FilenameFilter { _, dirName -> dirName.endsWith(".nca") }
val firmwarePath =
File(DirectoryInitialization.userDirectory + "/nand/system/Contents/registered/")
val cacheFirmwareDir = File("${cacheDir.path}/registered/")
val task: () -> Any = {
var messageToShow: Any
try {
FileUtil.unzip(inputZip, cacheFirmwareDir)
val unfilteredNumOfFiles = cacheFirmwareDir.list()?.size ?: -1
val filteredNumOfFiles = cacheFirmwareDir.list(filterNCA)?.size ?: -2
messageToShow = if (unfilteredNumOfFiles != filteredNumOfFiles) {
MessageDialogFragment.newInstance(
R.string.firmware_installed_failure,
R.string.firmware_installed_failure_description
)
} else {
firmwarePath.deleteRecursively()
cacheFirmwareDir.copyRecursively(firmwarePath, true)
getString(R.string.save_file_imported_success)
}
} catch (e: Exception) {
messageToShow = getString(R.string.fatal_error)
} finally {
cacheFirmwareDir.deleteRecursively()
}
messageToShow
}
IndeterminateProgressDialogFragment.newInstance(
this,
R.string.firmware_installing,
task
).show(supportFragmentManager, IndeterminateProgressDialogFragment.TAG)
}
val getAmiiboKey =
registerForActivityResult(ActivityResultContracts.OpenDocument()) { result ->
if (result == null)

View File

@@ -9,14 +9,10 @@ import android.net.Uri
import android.provider.DocumentsContract
import androidx.documentfile.provider.DocumentFile
import org.yuzu.yuzu_emu.model.MinimalDocumentFile
import java.io.BufferedInputStream
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import java.io.InputStream
import java.net.URLDecoder
import java.util.zip.ZipEntry
import java.util.zip.ZipInputStream
object FileUtil {
const val PATH_TREE = "tree"
@@ -280,34 +276,6 @@ object FileUtil {
return false
}
/**
* Extracts the given zip file into the given directory.
* @exception IOException if the file was being created outside of the target directory
*/
@Throws(SecurityException::class)
fun unzip(zipStream: InputStream, destDir: File): Boolean {
ZipInputStream(BufferedInputStream(zipStream)).use { zis ->
var entry: ZipEntry? = zis.nextEntry
while (entry != null) {
val entryName = entry.name
val entryFile = File(destDir, entryName)
if (!entryFile.canonicalPath.startsWith(destDir.canonicalPath + File.separator)) {
throw SecurityException("Entry is outside of the target dir: " + entryFile.name)
}
if (entry.isDirectory) {
entryFile.mkdirs()
} else {
entryFile.parentFile?.mkdirs()
entryFile.createNewFile()
entryFile.outputStream().use { fos -> zis.copyTo(fos) }
}
entry = zis.nextEntry
}
}
return true
}
fun isRootTreeUri(uri: Uri): Boolean {
val paths = uri.pathSegments
return paths.size == 2 && PATH_TREE == paths[0]

View File

@@ -1,46 +0,0 @@
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
package org.yuzu.yuzu_emu.views
import android.content.Context
import android.util.AttributeSet
import android.util.Rational
import android.view.SurfaceView
import kotlin.math.roundToInt
class FixedRatioSurfaceView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : SurfaceView(context, attrs, defStyleAttr) {
private var aspectRatio: Float = 0f // (width / height), 0f is a special value for stretch
/**
* Sets the desired aspect ratio for this view
* @param ratio the ratio to force the view to, or null to stretch to fit
*/
fun setAspectRatio(ratio: Rational?) {
aspectRatio = ratio?.toFloat() ?: 0f
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
val width = MeasureSpec.getSize(widthMeasureSpec)
val height = MeasureSpec.getSize(heightMeasureSpec)
if (aspectRatio != 0f) {
val newWidth: Int
val newHeight: Int
if (height * aspectRatio < width) {
newWidth = (height * aspectRatio).roundToInt()
newHeight = height
} else {
newWidth = width
newHeight = (width / aspectRatio).roundToInt()
}
setMeasuredDimension(newWidth, newHeight)
} else {
setMeasuredDimension(width, height)
}
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

View File

@@ -1,10 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M160,840Q127,840 103.5,816.5Q80,793 80,760L80,200Q80,167 103.5,143.5Q127,120 160,120L720,120Q753,120 776.5,143.5Q800,167 800,200L800,280L840,280Q857,280 868.5,291.5Q880,303 880,320Q880,337 868.5,348.5Q857,360 840,360L800,360L800,440L840,440Q857,440 868.5,451.5Q880,463 880,480Q880,497 868.5,508.5Q857,520 840,520L800,520L800,600L840,600Q857,600 868.5,611.5Q880,623 880,640Q880,657 868.5,668.5Q857,680 840,680L800,680L800,760Q800,793 776.5,816.5Q753,840 720,840L160,840ZM160,760L720,760Q720,760 720,760Q720,760 720,760L720,200Q720,200 720,200Q720,200 720,200L160,200Q160,200 160,200Q160,200 160,200L160,760Q160,760 160,760Q160,760 160,760ZM280,680L400,680Q417,680 428.5,668.5Q440,657 440,640L440,560Q440,543 428.5,531.5Q417,520 400,520L280,520Q263,520 251.5,531.5Q240,543 240,560L240,640Q240,657 251.5,668.5Q263,680 280,680ZM520,400L600,400Q617,400 628.5,388.5Q640,377 640,360L640,320Q640,303 628.5,291.5Q617,280 600,280L520,280Q503,280 491.5,291.5Q480,303 480,320L480,360Q480,377 491.5,388.5Q503,400 520,400ZM280,480L400,480Q417,480 428.5,468.5Q440,457 440,440L440,320Q440,303 428.5,291.5Q417,280 400,280L280,280Q263,280 251.5,291.5Q240,303 240,320L240,440Q240,457 251.5,468.5Q263,480 280,480ZM520,680L600,680Q617,680 628.5,668.5Q640,657 640,640L640,480Q640,463 628.5,451.5Q617,440 600,440L520,440Q503,440 491.5,451.5Q480,463 480,480L480,640Q480,657 491.5,668.5Q503,680 520,680ZM160,200L160,200Q160,200 160,200Q160,200 160,200L160,760Q160,760 160,760Q160,760 160,760L160,760Q160,760 160,760Q160,760 160,760L160,200Q160,200 160,200Q160,200 160,200Z"/>
</vector>

View File

@@ -1,10 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M360,720L600,720Q617,720 628.5,708.5Q640,697 640,680Q640,663 628.5,651.5Q617,640 600,640L360,640Q343,640 331.5,651.5Q320,663 320,680Q320,697 331.5,708.5Q343,720 360,720ZM360,560L600,560Q617,560 628.5,548.5Q640,537 640,520Q640,503 628.5,491.5Q617,480 600,480L360,480Q343,480 331.5,491.5Q320,503 320,520Q320,537 331.5,548.5Q343,560 360,560ZM240,880Q207,880 183.5,856.5Q160,833 160,800L160,160Q160,127 183.5,103.5Q207,80 240,80L527,80Q543,80 557.5,86Q572,92 583,103L777,297Q788,308 794,322.5Q800,337 800,353L800,800Q800,833 776.5,856.5Q753,880 720,880L240,880ZM520,320L520,160L240,160Q240,160 240,160Q240,160 240,160L240,800Q240,800 240,800Q240,800 240,800L720,800Q720,800 720,800Q720,800 720,800L720,360L560,360Q543,360 531.5,348.5Q520,337 520,320ZM240,160L240,160L240,320Q240,337 240,348.5Q240,360 240,360L240,360L240,160L240,320Q240,337 240,348.5Q240,360 240,360L240,360L240,800Q240,800 240,800Q240,800 240,800L240,800Q240,800 240,800Q240,800 240,800L240,160Q240,160 240,160Q240,160 240,160Z"/>
</vector>

View File

@@ -1,64 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:tools="http://schemas.android.com/tools">
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginHorizontal="16dp">
<com.google.android.material.bottomsheet.BottomSheetDragHandleView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"/>
<com.google.android.material.textview.MaterialTextView
style="@style/TextAppearance.Material3.HeadlineLarge"
android:id="@+id/text_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
tools:text="@string/license_adreno_tools" />
<com.google.android.material.textview.MaterialTextView
style="@style/TextAppearance.Material3.BodyLarge"
android:id="@+id/text_link"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:layout_marginTop="16dp"
android:autoLink="all"
tools:text="@string/license_adreno_tools_link" />
<com.google.android.material.textview.MaterialTextView
style="@style/TextAppearance.Material3.BodyLarge"
android:id="@+id/text_copyright"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:layout_marginTop="16dp"
android:textStyle="bold"
tools:text="@string/license_adreno_tools_copyright" />
<com.google.android.material.textview.MaterialTextView
style="@style/TextAppearance.Material3.BodyMedium"
android:id="@+id/text_license"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginVertical="16dp"
android:autoLink="all"
tools:text="@string/license_adreno_tools_text" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@@ -109,39 +109,6 @@
</LinearLayout>
<com.google.android.material.divider.MaterialDivider
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="20dp" />
<LinearLayout
android:id="@+id/button_licenses"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingVertical="16dp"
android:paddingHorizontal="16dp"
android:background="?attr/selectableItemBackground"
android:orientation="vertical">
<com.google.android.material.textview.MaterialTextView
style="@style/TextAppearance.Material3.TitleMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp"
android:textAlignment="viewStart"
android:text="@string/licenses" />
<com.google.android.material.textview.MaterialTextView
style="@style/TextAppearance.Material3.BodyMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="6dp"
android:textAlignment="viewStart"
android:text="@string/licenses_description" />
</LinearLayout>
<com.google.android.material.divider.MaterialDivider
android:layout_width="match_parent"
android:layout_height="wrap_content"

View File

@@ -13,20 +13,13 @@
android:layout_height="match_parent">
<!-- This is what everything is rendered to during emulation -->
<org.yuzu.yuzu_emu.views.FixedRatioSurfaceView
<SurfaceView
android:id="@+id/surface_emulation"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:focusable="false"
android:focusableInTouchMode="false" />
<FrameLayout
android:id="@+id/overlay_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="bottom">
<!-- This is the onscreen input overlay -->
<org.yuzu.yuzu_emu.overlay.InputOverlay
android:id="@+id/surface_input_overlay"
@@ -55,7 +48,6 @@
android:layout_gravity="center"
android:text="@string/emulation_done"
android:visibility="gone" />
</FrameLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
@@ -63,7 +55,7 @@
android:id="@+id/in_game_menu"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start|bottom"
android:layout_gravity="start"
app:headerLayout="@layout/header_in_game"
app:menu="@menu/menu_in_game" />

View File

@@ -1,30 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/coordinator_licenses"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/colorSurface">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar_licenses"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar_licenses"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:title="@string/licenses"
app:navigationIcon="@drawable/ic_back" />
</com.google.android.material.appbar.AppBarLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/list_licenses"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@@ -40,20 +40,11 @@
<fragment
android:id="@+id/aboutFragment"
android:name="org.yuzu.yuzu_emu.fragments.AboutFragment"
android:label="AboutFragment" >
<action
android:id="@+id/action_aboutFragment_to_licensesFragment"
app:destination="@id/licensesFragment" />
</fragment>
android:label="AboutFragment" />
<fragment
android:id="@+id/earlyAccessFragment"
android:name="org.yuzu.yuzu_emu.fragments.EarlyAccessFragment"
android:label="EarlyAccessFragment" />
<fragment
android:id="@+id/licensesFragment"
android:name="org.yuzu.yuzu_emu.fragments.LicensesFragment"
android:label="LicensesFragment" />
</navigation>

View File

@@ -2,67 +2,67 @@
<resources>
<string-array name="regionNames">
<item>@string/auto</item>
<item>@string/region_auto</item>
<item>@string/region_japan</item>
<item>@string/region_usa</item>
<item>@string/region_europe</item>
<item>@string/region_australia</item>
<item>@string/region_china</item>
<item>@string/region_europe</item>
<item>@string/region_japan</item>
<item>@string/region_korea</item>
<item>@string/region_taiwan</item>
<item>@string/region_usa</item>
</string-array>
<integer-array name="regionValues">
<item>-1</item>
<item>0</item>
<item>1</item>
<item>2</item>
<item>3</item>
<item>4</item>
<item>2</item>
<item>0</item>
<item>5</item>
<item>6</item>
<item>1</item>
</integer-array>
<string-array name="languageNames">
<item>@string/language_brazilian_portuguese</item>
<item>@string/language_british_english</item>
<item>@string/language_canadian_french</item>
<item>@string/language_chinese</item>
<item>@string/language_dutch</item>
<item>@string/language_japanese</item>
<item>@string/language_english</item>
<item>@string/language_french</item>
<item>@string/langauge_german</item>
<item>@string/language_italian</item>
<item>@string/language_japanese</item>
<item>@string/language_spanish</item>
<item>@string/language_chinese</item>
<item>@string/language_korean</item>
<item>@string/language_latin_american_spanish</item>
<item>@string/language_dutch</item>
<item>@string/language_portuguese</item>
<item>@string/language_russian</item>
<item>@string/language_simplified_chinese</item>
<item>@string/language_spanish</item>
<item>@string/language_taiwanese</item>
<item>@string/language_british_english</item>
<item>@string/language_canadian_french</item>
<item>@string/language_latin_american_spanish</item>
<item>@string/language_simplified_chinese</item>
<item>@string/language_traditional_chinese</item>
<item>@string/language_brazilian_portuguese</item>
</string-array>
<integer-array name="languageValues">
<item>17</item>
<item>12</item>
<item>13</item>
<item>6</item>
<item>8</item>
<item>0</item>
<item>1</item>
<item>2</item>
<item>3</item>
<item>4</item>
<item>0</item>
<item>5</item>
<item>6</item>
<item>7</item>
<item>14</item>
<item>8</item>
<item>9</item>
<item>10</item>
<item>15</item>
<item>5</item>
<item>11</item>
<item>12</item>
<item>13</item>
<item>14</item>
<item>15</item>
<item>16</item>
<item>17</item>
</integer-array>
<string-array name="rendererApiNames">
@@ -166,7 +166,7 @@
</integer-array>
<string-array name="cpuAccuracyNames">
<item>@string/auto</item>
<item>@string/cpu_accuracy_auto</item>
<item>@string/cpu_accuracy_accurate</item>
<item>@string/cpu_accuracy_unsafe</item>
<item>@string/cpu_accuracy_paranoid</item>

View File

@@ -41,7 +41,7 @@
<string name="add_games_warning">Skip selecting games folder?</string>
<string name="add_games_warning_description">Games won\'t be displayed in the Games list if a folder isn\'t selected.</string>
<string name="add_games_warning_help">https://yuzu-emu.org/help/quickstart/#dumping-games</string>
<string name="home_search_games">Search games</string>
<string name="home_search_games">Search Games</string>
<string name="games_dir_selected">Games directory selected</string>
<string name="install_prod_keys">Install prod.keys</string>
<string name="install_prod_keys_description">Required to decrypt retail games</string>
@@ -77,8 +77,8 @@
<string name="install_gpu_driver_description">Install alternative drivers for potentially better performance or accuracy</string>
<string name="advanced_settings">Advanced settings</string>
<string name="settings_description">Configure emulator settings</string>
<string name="search_recently_played">Recently played</string>
<string name="search_recently_added">Recently added</string>
<string name="search_recently_played">Recently Played</string>
<string name="search_recently_added">Recently Added</string>
<string name="search_retail">Retail</string>
<string name="search_homebrew">Homebrew</string>
<string name="open_user_folder">Open yuzu folder</string>
@@ -96,15 +96,6 @@
<string name="save_file_invalid_zip_structure_description">The first subfolder name must be the title ID of the game.</string>
<string name="import_saves">Import</string>
<string name="export_saves">Export</string>
<string name="install_firmware">Install firmware</string>
<string name="install_firmware_description">Firmware must be in a ZIP archive and is needed to boot some games</string>
<string name="firmware_installing">Installing firmware</string>
<string name="firmware_installed_success">Firmware installed successfully</string>
<string name="firmware_installed_failure">Firmware installation failed</string>
<string name="firmware_installed_failure_description">Verify that the ZIP contains valid firmware and try again.</string>
<string name="share_log">Share debug logs</string>
<string name="share_log_description">Share yuzu\'s log file to debug issues</string>
<string name="share_log_missing">No log file found</string>
<!-- About screen strings -->
<string name="gaia_is_not_real">Gaia isn\'t real</string>
@@ -113,7 +104,6 @@
<string name="contributors">Contributors</string>
<string name="contributors_description">Made with \u2764 from the yuzu team</string>
<string name="contributors_link">https://github.com/yuzu-emu/yuzu/graphs/contributors</string>
<string name="licenses_description">Projects that make yuzu for Android possible</string>
<string name="build">Build</string>
<string name="support_link">https://discord.gg/u77vRWY</string>
<string name="website_link">https://yuzu-emu.org/</string>
@@ -134,39 +124,39 @@
<string name="are_you_interested">Are you interested?</string>
<!-- General settings strings -->
<string name="frame_limit_enable">Limit speed</string>
<string name="frame_limit_enable_description">Limits emulation speed to a specified percentage of normal speed.</string>
<string name="frame_limit_enable">Enable limit speed</string>
<string name="frame_limit_enable_description">When enabled, emulation speed will be limited to a specified percentage of normal speed.</string>
<string name="frame_limit_slider">Limit speed percent</string>
<string name="frame_limit_slider_description">Specifies the percentage to limit emulation speed. 100% is the normal speed. Values higher or lower will increase or decrease the speed limit.</string>
<string name="frame_limit_slider_description">Specifies the percentage to limit emulation speed. With the default of 100% emulation will be limited to normal speed. Values higher or lower will increase or decrease the speed limit.</string>
<string name="cpu_accuracy">CPU accuracy</string>
<!-- System settings strings -->
<string name="use_docked_mode">Docked Mode</string>
<string name="use_docked_mode_description">Increases resolution, decreasing performance. Handheld Mode is used when disabled, lowering resolution and increasing performance.</string>
<string name="use_docked_mode">Docked mode</string>
<string name="use_docked_mode_description">Emulates in docked mode, which increases the resolution at the expense of performance.</string>
<string name="emulated_region">Emulated region</string>
<string name="emulated_language">Emulated language</string>
<string name="select_rtc_date">Select RTC date</string>
<string name="select_rtc_time">Select RTC time</string>
<string name="use_custom_rtc">Custom RTC</string>
<string name="use_custom_rtc_description">Allows you to set a custom real-time clock separate from your current system time.</string>
<string name="set_custom_rtc">Set custom RTC</string>
<string name="select_rtc_date">Select RTC Date</string>
<string name="select_rtc_time">Select RTC Time</string>
<string name="use_custom_rtc">Enable Custom RTC</string>
<string name="use_custom_rtc_description">This setting allows you to set a custom real time clock separate from your current system time</string>
<string name="set_custom_rtc">Set Custom RTC</string>
<!-- Graphics settings strings -->
<string name="renderer_api">API</string>
<string name="renderer_accuracy">Accuracy level</string>
<string name="renderer_resolution">Resolution (Handheld/Docked)</string>
<string name="renderer_resolution">Resolution</string>
<string name="renderer_vsync">VSync mode</string>
<string name="renderer_aspect_ratio">Aspect ratio</string>
<string name="renderer_scaling_filter">Window adapting filter</string>
<string name="renderer_anti_aliasing">Anti-aliasing method</string>
<string name="renderer_aspect_ratio">Aspect Ratio</string>
<string name="renderer_scaling_filter">Window Adapting Filter</string>
<string name="renderer_anti_aliasing">Anti-Aliasing Method</string>
<string name="renderer_force_max_clock">Force maximum clocks (Adreno only)</string>
<string name="renderer_force_max_clock_description">Forces the GPU to run at the maximum possible clocks (thermal constraints will still be applied).</string>
<string name="renderer_asynchronous_shaders">Use asynchronous shaders</string>
<string name="renderer_asynchronous_shaders_description">Compiles shaders asynchronously, reducing stutter but may introduce glitches.</string>
<string name="renderer_debug">Graphics debugging</string>
<string name="renderer_debug_description">Sets the graphics API to a slow debugging mode.</string>
<string name="use_disk_shader_cache">Disk shader cache</string>
<string name="use_disk_shader_cache_description">Reduces stuttering by locally storing and loading generated shaders.</string>
<string name="renderer_asynchronous_shaders_description">Compiles shaders asynchronously, which will reduce stutter but may introduce glitches.</string>
<string name="renderer_debug">Enable graphics debugging</string>
<string name="renderer_debug_description">When checked, the graphics API enters a slower debugging mode.</string>
<string name="use_disk_shader_cache">Use disk shader cache</string>
<string name="use_disk_shader_cache_description">Reduce stuttering by storing and loading generated shaders to disk.</string>
<!-- Audio settings strings -->
<string name="audio_volume">Volume</string>
@@ -181,12 +171,10 @@
<string name="reset_setting_confirmation">Do you want to reset this setting back to its default value?</string>
<string name="reset_to_default">Reset to default</string>
<string name="reset_all_settings">Reset all settings?</string>
<string name="reset_all_settings_description">All advanced settings will be reset to their default configuration. This can not be undone.</string>
<string name="reset_all_settings_description">All Advanced Settings will be reset to their default configuration. This can not be undone.</string>
<string name="settings_reset">Settings reset</string>
<string name="close">Close</string>
<string name="learn_more">Learn more</string>
<string name="auto">Auto</string>
<string name="submit">Submit</string>
<string name="learn_more">Learn More</string>
<!-- GPU driver installation -->
<string name="select_gpu_driver">Select GPU driver</string>
@@ -200,13 +188,13 @@
<string name="installing_driver">Installing driver…</string>
<!-- Preferences Screen -->
<string name="preferences_advanced_settings">Advanced Settings</string>
<string name="preferences_settings">Settings</string>
<string name="preferences_general">General</string>
<string name="preferences_system">System</string>
<string name="preferences_graphics">Graphics</string>
<string name="preferences_audio">Audio</string>
<string name="preferences_theme">Theme and color</string>
<string name="preferences_debug">Debug</string>
<!-- ROM loading errors -->
<string name="loader_error_encrypted">Your ROM is encrypted</string>
@@ -218,29 +206,29 @@
<string name="loader_error_file_not_found">ROM file does not exist</string>
<!-- Emulation Menu -->
<string name="emulation_exit">Exit emulation</string>
<string name="emulation_exit">Exit Emulation</string>
<string name="emulation_done">Done</string>
<string name="emulation_fps_counter">FPS counter</string>
<string name="emulation_toggle_controls">Toggle controls</string>
<string name="emulation_rel_stick_center">Relative stick center</string>
<string name="emulation_dpad_slide">D-pad slide</string>
<string name="emulation_haptics">Touch haptics</string>
<string name="emulation_show_overlay">Show overlay</string>
<string name="emulation_toggle_all">Toggle all</string>
<string name="emulation_control_adjust">Adjust overlay</string>
<string name="emulation_fps_counter">FPS Counter</string>
<string name="emulation_toggle_controls">Toggle Controls</string>
<string name="emulation_rel_stick_center">Relative Stick Center</string>
<string name="emulation_dpad_slide">DPad Slide</string>
<string name="emulation_haptics">Haptics</string>
<string name="emulation_show_overlay">Show Overlay</string>
<string name="emulation_toggle_all">Toggle All</string>
<string name="emulation_control_adjust">Adjust Overlay</string>
<string name="emulation_control_scale">Scale</string>
<string name="emulation_control_opacity">Opacity</string>
<string name="emulation_touch_overlay_reset">Reset overlay</string>
<string name="emulation_touch_overlay_edit">Edit overlay</string>
<string name="emulation_pause">Pause emulation</string>
<string name="emulation_unpause">Unpause emulation</string>
<string name="emulation_input_overlay">Overlay options</string>
<string name="emulation_touch_overlay_reset">Reset Overlay</string>
<string name="emulation_touch_overlay_edit">Edit Overlay</string>
<string name="emulation_pause">Pause Emulation</string>
<string name="emulation_unpause">Unpause Emulation</string>
<string name="emulation_input_overlay">Overlay Options</string>
<string name="emulation_game_loading">Game loading…</string>
<string name="load_settings">Loading settings…</string>
<string name="load_settings">Loading Settings…</string>
<!-- Software keyboard -->
<string name="software_keyboard">Software keyboard</string>
<string name="software_keyboard">Software Keyboard</string>
<!-- Errors and warnings -->
<string name="abort_button">Abort</string>
@@ -254,6 +242,7 @@
<string name="performance_warning">Turning off this setting will significantly reduce emulation performance! For the best experience, it is recommended that you leave this setting enabled.</string>
<!-- Region Names -->
<string name="region_auto">Auto-select</string>
<string name="region_japan">Japan</string>
<string name="region_usa">USA</string>
<string name="region_europe">Europe</string>
@@ -323,17 +312,18 @@
<string name="ratio_force_four_three">Force 4:3</string>
<string name="ratio_force_twenty_one_nine">Force 21:9</string>
<string name="ratio_force_sixteen_ten">Force 16:10</string>
<string name="ratio_stretch">Stretch to window</string>
<string name="ratio_stretch">Stretch to Window</string>
<!-- CPU Accuracy -->
<string name="cpu_accuracy_auto">Auto</string>
<string name="cpu_accuracy_accurate">Accurate</string>
<string name="cpu_accuracy_unsafe">Unsafe</string>
<string name="cpu_accuracy_paranoid">Paranoid (Slow)</string>
<!-- Gamepad Buttons -->
<string name="gamepad_d_pad">D-pad</string>
<string name="gamepad_left_stick">Left stick</string>
<string name="gamepad_right_stick">Right stick</string>
<string name="gamepad_d_pad">D-Pad</string>
<string name="gamepad_left_stick">Left Stick</string>
<string name="gamepad_right_stick">Right Stick</string>
<string name="gamepad_home">Home</string>
<string name="gamepad_screenshot">Screenshot</string>
@@ -342,525 +332,18 @@
<string name="building_shaders">Building shaders</string>
<!-- Theme options -->
<string name="change_app_theme">Change app theme</string>
<string name="change_app_theme">Change App Theme</string>
<string name="theme_default">Default</string>
<string name="theme_material_you">Material You</string>
<!-- Theme Modes -->
<string name="change_theme_mode">Change theme mode</string>
<string name="change_theme_mode">Change Theme Mode</string>
<string name="theme_mode_follow_system">Follow System</string>
<string name="theme_mode_light">Light</string>
<string name="theme_mode_dark">Dark</string>
<!-- Black backgrounds theme -->
<string name="use_black_backgrounds">Black backgrounds</string>
<string name="use_black_backgrounds">Use Black Backgrounds</string>
<string name="use_black_backgrounds_description">When using the dark theme, apply black backgrounds.</string>
<!-- Licenses screen strings -->
<string name="licenses">Licenses</string>
<string name="license_fidelityfx_fsr" translatable="false">FidelityFX-FSR</string>
<string name="license_fidelityfx_fsr_description">High-quality upscaling from AMD</string>
<string name="license_fidelityfx_fsr_link" translatable="false">https://github.com/GPUOpen-Effects/FidelityFX-FSR</string>
<string name="license_fidelityfx_fsr_copyright" translatable="false">Copyright © 2021 Advanced Micro Devices, Inc.</string>
<string name="license_fidelityfx_fsr_text" translatable="false">
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the \"Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:\n\n
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.\n\n
THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
</string>
<string name="license_cubeb" translatable="false">cubeb</string>
<string name="license_cubeb_description" translatable="false">Cross platform audio library</string>
<string name="license_cubeb_link" translatable="false">https://github.com/mozilla/cubeb</string>
<string name="license_cubeb_copyright" translatable="false">Copyright © 2011 Mozilla Foundation</string>
<string name="license_cubeb_text" translatable="false">
Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.\n\n
THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
</string>
<string name="license_dynarmic" translatable="false">Dynarmic</string>
<string name="license_dynarmic_description" translatable="false">An ARM dynamic recompiler</string>
<string name="license_dynarmic_link" translatable="false">https://github.com/merryhime/dynarmic</string>
<string name="license_dynarmic_copyright" translatable="false">Copyright © 2017 merryhime</string>
<string name="license_dynarmic_text" translatable="false">
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted.\n\n
THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
</string>
<string name="license_ffmpeg" translatable="false">FFmpeg</string>
<string name="license_ffmpeg_description" translatable="false">FFmpeg is a collection of libraries and tools to process multimedia content such as audio, video, subtitles and related metadata.</string>
<string name="license_ffmpeg_link" translatable="false">https://github.com/FFmpeg/FFmpeg</string>
<string name="license_ffmpeg_copyright" translatable="false">Copyright © 1991, 1999 Free Software Foundation, Inc.</string>
<string name="license_ffmpeg_text" translatable="false">
GNU LESSER GENERAL PUBLIC LICENSE\n
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n\n
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called \"this License\").
Each licensee is addressed as \"you\".\n\n
A \"library\" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.\n\n
The \"Library\", below, refers to any such software library or work
which has been distributed under these terms. A \"work based on the
Library\" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term \"modification\".)\n\n
\"Source code\" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.\n\n
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.\n\n
1. You may copy and distribute verbatim copies of the Library\'s
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.\n\n
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.\n\n
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:\n\n
a) The modified work must itself be a software library.\n\n
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.\n\n
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.\n\n
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.\n\n
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)\n\n
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.\n\n
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.\n\n
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.\n\n
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.\n\n
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.\n\n
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.\n\n
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.\n\n
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.\n\n
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a \"work that uses the Library\". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.\n\n
However, linking a \"work that uses the Library\" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a \"work that uses the
library\". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.\n\n
When a \"work that uses the Library\" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.\n\n
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)\n\n
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.\n\n
6. As an exception to the Sections above, you may also combine or
link a \"work that uses the Library\" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer\'s own use and reverse
engineering for debugging such modifications.\n\n
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:\n\n
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable \"work that
uses the Library\", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)\n\n
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user\'s computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.\n\n
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.\n\n
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.\n\n
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.\n\n
For an executable, the required form of the \"work that uses the
Library\" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.\n\n
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.\n\n
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:\n\n
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.\n\n
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.\n\n
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.\n\n
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.\n\n
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients\' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.\n\n
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.\n\n
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.\n\n
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.\n\n
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.\n\n
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.\n\n
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.\n\n
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version\", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.\n\n
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.\n\n
NO WARRANTY\n\n
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY \"AS IS\" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
</string>
<string name="license_opus" translatable="false">Opus</string>
<string name="license_opus_description" translatable="false">Modern audio compression for the internet</string>
<string name="license_opus_link" translatable="false">https://github.com/xiph/opus</string>
<string name="license_opus_copyright" translatable="false">Copyright 20012011 Xiph.Org, Skype Limited, Octasic, Jean-Marc Valin, Timothy B. Terriberry, CSIRO, Gregory Maxwell, Mark Borgerding, Erik de Castro Lopo</string>
<string name="license_opus_text" translatable="false">
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:\n\n
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.\n\n
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.\n\n
- Neither the name of Internet Society, IETF or IETF Trust, nor the
names of specific contributors, may be used to endorse or promote
products derived from this software without specific prior written
permission.\n\n
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS\'\' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n
Opus is subject to the royalty-free patent licenses which are
specified at:\n\n
Xiph.Org Foundation:
https://datatracker.ietf.org/ipr/1524/ \n\n
Microsoft Corporation:
https://datatracker.ietf.org/ipr/1914/ \n\n
Broadcom Corporation:
https://datatracker.ietf.org/ipr/1526/
</string>
<string name="license_sirit" translatable="false">Sirit</string>
<string name="license_sirit_description" translatable="false">A runtime SPIR-V assembler</string>
<string name="license_sirit_link" translatable="false">https://github.com/ReinUsesLisp/sirit</string>
<string name="license_sirit_copyright" translatable="false">Copyright © 2019, sirit All rights reserved.</string>
<string name="license_sirit_text" translatable="false">
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:\n
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.\n
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.\n
* Neither the name of the organization nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.\n\n
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
</string>
<string name="license_adreno_tools" translatable="false">Adreno Tools</string>
<string name="license_adreno_tools_description" translatable="false">A library for applying rootless Adreno GPU driver modifications/replacements</string>
<string name="license_adreno_tools_link" translatable="false">https://github.com/bylaws/libadrenotools</string>
<string name="license_adreno_tools_copyright" translatable="false">Copyright © 2021, Billy Laws</string>
<string name="license_adreno_tools_text" translatable="false">
BSD 2-Clause License\n\n
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:\n\n
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.\n\n
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.\n\n
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
</string>
</resources>

View File

@@ -9,9 +9,8 @@
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xms512m -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
android.useAndroidX=true
# Kotlin code style for this project: "official" or "obsolete":
kotlin.code.style=official
kotlin.parallel.tasks.in.project=true
android.defaults.buildfeatures.buildconfig=true

View File

@@ -47,4 +47,12 @@ AudioRenderer::ADSP::ADSP& AudioCore::GetADSP() {
return *adsp;
}
void AudioCore::SetNVDECActive(bool active) {
nvdec_active = active;
}
bool AudioCore::IsNVDECActive() const {
return nvdec_active;
}
} // namespace AudioCore

View File

@@ -57,6 +57,18 @@ public:
*/
AudioRenderer::ADSP::ADSP& GetADSP();
/**
* Toggle NVDEC state, used to avoid stall in playback.
*
* @param active - Set true if nvdec is active, otherwise false.
*/
void SetNVDECActive(bool active);
/**
* Get NVDEC state.
*/
bool IsNVDECActive() const;
private:
/**
* Create the sinks on startup.
@@ -71,6 +83,8 @@ private:
std::unique_ptr<Sink::Sink> input_sink;
/// The ADSP in the sysmodule
std::unique_ptr<AudioRenderer::ADSP::ADSP> adsp;
/// Is NVDec currently active?
bool nvdec_active{false};
};
} // namespace AudioCore

View File

@@ -105,7 +105,7 @@ void AudioRenderer::Start(AudioRenderer_Mailbox* mailbox_) {
}
mailbox = mailbox_;
thread = std::jthread([this](std::stop_token stop_token) { ThreadFunc(stop_token); });
thread = std::thread(&AudioRenderer::ThreadFunc, this);
running = true;
}
@@ -131,7 +131,7 @@ void AudioRenderer::CreateSinkStreams() {
}
}
void AudioRenderer::ThreadFunc(std::stop_token stop_token) {
void AudioRenderer::ThreadFunc() {
static constexpr char name[]{"AudioRenderer"};
MicroProfileOnThreadCreate(name);
Common::SetCurrentThreadName(name);
@@ -146,7 +146,7 @@ void AudioRenderer::ThreadFunc(std::stop_token stop_token) {
constexpr u64 max_process_time{2'304'000ULL};
while (!stop_token.stop_requested()) {
while (true) {
auto message{mailbox->ADSPWaitMessage()};
switch (message) {
case RenderMessage::AudioRenderer_Shutdown:
@@ -194,7 +194,7 @@ void AudioRenderer::ThreadFunc(std::stop_token stop_token) {
max_time = std::min(command_buffer.time_limit, max_time);
command_list_processor.SetProcessTimeMax(max_time);
streams[index]->WaitFreeSpace(stop_token);
streams[index]->WaitFreeSpace();
// Process the command list
{

View File

@@ -177,7 +177,7 @@ private:
/**
* Main AudioRenderer thread, responsible for processing the command lists.
*/
void ThreadFunc(std::stop_token stop_token);
void ThreadFunc();
/**
* Creates the streams which will receive the processed samples.
@@ -187,7 +187,7 @@ private:
/// Core system
Core::System& system;
/// Main thread
std::jthread thread{};
std::thread thread{};
/// The current state
std::atomic<bool> running{};
/// The active mailbox

View File

@@ -269,14 +269,16 @@ u64 SinkStream::GetExpectedPlayedSampleCount() {
return std::min<u64>(exp_played_sample_count, max_played_sample_count) + TargetSampleCount * 3;
}
void SinkStream::WaitFreeSpace(std::stop_token stop_token) {
void SinkStream::WaitFreeSpace() {
std::unique_lock lk{release_mutex};
release_cv.wait_for(lk, std::chrono::milliseconds(5),
[this]() { return queued_buffers < max_queue_size; });
#ifndef ANDROID
// This wait can cause a problematic shutdown hang on Android.
if (queued_buffers > max_queue_size + 3) {
Common::CondvarWait(release_cv, lk, stop_token,
[this] { return queued_buffers < max_queue_size; });
release_cv.wait(lk, [this]() { return queued_buffers < max_queue_size; });
}
#endif
}
} // namespace AudioCore::Sink

View File

@@ -13,7 +13,6 @@
#include "audio_core/common/common.h"
#include "common/common_types.h"
#include "common/polyfill_thread.h"
#include "common/reader_writer_queue.h"
#include "common/ring_buffer.h"
#include "common/thread.h"
@@ -211,7 +210,7 @@ public:
/**
* Waits for free space in the sample ring buffer
*/
void WaitFreeSpace(std::stop_token stop_token);
void WaitFreeSpace();
protected:
/// Core system
@@ -253,7 +252,7 @@ private:
/// Set via IAudioDevice service calls
f32 device_volume{1.0f};
/// Signalled when ring buffer entries are consumed
std::condition_variable_any release_cv;
std::condition_variable release_cv;
std::mutex release_mutex;
};

View File

@@ -10,7 +10,6 @@
// Sub-directories contained within a yuzu data directory
#define AMIIBO_DIR "amiibo"
#define CACHE_DIR "cache"
#define CONFIG_DIR "config"
#define DUMP_DIR "dump"

View File

@@ -114,7 +114,6 @@ public:
#endif
GenerateYuzuPath(YuzuPath::YuzuDir, yuzu_path);
GenerateYuzuPath(YuzuPath::AmiiboDir, yuzu_path / AMIIBO_DIR);
GenerateYuzuPath(YuzuPath::CacheDir, yuzu_path_cache);
GenerateYuzuPath(YuzuPath::ConfigDir, yuzu_path_config);
GenerateYuzuPath(YuzuPath::DumpDir, yuzu_path / DUMP_DIR);
@@ -350,11 +349,17 @@ std::string_view RemoveTrailingSlash(std::string_view path) {
}
std::vector<std::string> SplitPathComponents(std::string_view filename) {
std::vector<std::string> copied_components;
for (std::string_view component : filename | split_path_components_view) {
copied_components.emplace_back(component);
std::string copy(filename);
std::replace(copy.begin(), copy.end(), '\\', '/');
std::vector<std::string> out;
std::stringstream stream(copy);
std::string item;
while (std::getline(stream, item, '/')) {
out.push_back(std::move(item));
}
return copied_components;
return out;
}
std::string SanitizePath(std::string_view path_, DirectorySeparator directory_separator) {

View File

@@ -6,17 +6,12 @@
#include <filesystem>
#include <vector>
#include <range/v3/view/remove_if.hpp>
#include <range/v3/view/split_when.hpp>
#include <range/v3/view/transform.hpp>
#include "common/fs/fs_util.h"
namespace Common::FS {
enum class YuzuPath {
YuzuDir, // Where yuzu stores its data.
AmiiboDir, // Where Amiibo backups are stored.
CacheDir, // Where cached filesystem data is stored.
ConfigDir, // Where config files are stored.
DumpDir, // Where dumped data is stored.
@@ -288,23 +283,6 @@ enum class DirectorySeparator {
PlatformDefault,
};
// A range adaptor closure which splits the path on '/' or '\'
// i.e. "C:\Users\Yuzu\Documents\save.bin" becomes {"C:", "Users", "Yuzu", "Documents", "save.bin" }
constexpr auto split_path_components_view =
// Somehow split_when never made it into the standard
ranges::views::split_when([](auto cur, auto end) {
const char c = *cur;
bool do_split = c == '\\' || c == '/';
return std::make_pair(do_split, cur + (do_split ? 1 : 0));
}) |
// Convert from opaque range to std::string_view
ranges::views::transform([](auto&& chunk) {
return std::string_view{&*ranges::begin(chunk),
static_cast<std::size_t>(ranges::distance(chunk))};
}) |
// Skip any empty segments like at the beginning and end of "/root/directory/"
ranges::views::remove_if(&std::string_view::empty);
// Splits the path on '/' or '\' and put the components into a vector
// i.e. "C:\Users\Yuzu\Documents\save.bin" becomes {"C:", "Users", "Yuzu", "Documents", "save.bin" }
[[nodiscard]] std::vector<std::string> SplitPathComponents(std::string_view filename);

View File

@@ -18,7 +18,6 @@
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <boost/icl/interval_set.hpp>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
@@ -424,7 +423,6 @@ public:
madvise(virtual_base, virtual_size, MADV_HUGEPAGE);
#endif
placeholders.add({0, virtual_size});
good = true;
}
@@ -433,10 +431,6 @@ public:
}
void Map(size_t virtual_offset, size_t host_offset, size_t length) {
{
std::scoped_lock lock{placeholder_mutex};
placeholders.subtract({virtual_offset, virtual_offset + length});
}
void* ret = mmap(virtual_base + virtual_offset, length, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_FIXED, fd, host_offset);
@@ -447,19 +441,6 @@ public:
// The method name is wrong. We're still talking about the virtual range.
// We don't want to unmap, we want to reserve this memory.
{
std::scoped_lock lock{placeholder_mutex};
auto it = placeholders.find({virtual_offset - 1, virtual_offset + length + 1});
if (it != placeholders.end()) {
size_t prev_upper = virtual_offset + length;
virtual_offset = std::min(virtual_offset, it->lower());
length = std::max(it->upper(), prev_upper) - virtual_offset;
}
placeholders.add({virtual_offset, virtual_offset + length});
}
void* ret = mmap(virtual_base + virtual_offset, length, PROT_NONE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
ASSERT_MSG(ret != MAP_FAILED, "mmap failed: {}", strerror(errno));
@@ -503,9 +484,6 @@ private:
}
int fd{-1}; // memfd file descriptor, -1 is the error value of memfd_create
boost::icl::interval_set<size_t> placeholders; ///< Mapped placeholders
std::mutex placeholder_mutex; ///< Mutex for placeholders
};
#else // ^^^ Linux ^^^ vvv Generic vvv

View File

@@ -235,7 +235,6 @@ void RestoreGlobalState(bool is_powered_on) {
values.bg_green.SetGlobal(true);
values.bg_blue.SetGlobal(true);
values.enable_compute_pipelines.SetGlobal(true);
values.use_video_framerate.SetGlobal(true);
// System
values.language_index.SetGlobal(true);

View File

@@ -482,7 +482,6 @@ struct Values {
SwitchableSetting<AstcRecompression, true> astc_recompression{
AstcRecompression::Uncompressed, AstcRecompression::Uncompressed, AstcRecompression::Bc3,
"astc_recompression"};
SwitchableSetting<bool> use_video_framerate{false, "use_video_framerate"};
SwitchableSetting<u8> bg_red{0, "bg_red"};
SwitchableSetting<u8> bg_green{0, "bg_green"};

View File

@@ -48,7 +48,7 @@ std::array<u8, 0x10> ConstructFromRawString(std::string_view raw_string) {
}
std::array<u8, 0x10> ConstructFromFormattedString(std::string_view formatted_string) {
std::array<u8, 0x10> uuid{};
std::array<u8, 0x10> uuid;
size_t i = 0;

View File

@@ -106,8 +106,6 @@ add_library(core STATIC
file_sys/system_archive/time_zone_binary.h
file_sys/vfs.cpp
file_sys/vfs.h
file_sys/vfs_cached.cpp
file_sys/vfs_cached.h
file_sys/vfs_concat.cpp
file_sys/vfs_concat.h
file_sys/vfs_layered.cpp
@@ -837,7 +835,7 @@ endif()
create_target_directory_groups(core)
target_link_libraries(core PUBLIC common PRIVATE audio_core network video_core)
target_link_libraries(core PUBLIC Boost::headers PRIVATE fmt::fmt nlohmann_json::nlohmann_json mbedtls Opus::opus range-v3)
target_link_libraries(core PUBLIC Boost::headers PRIVATE fmt::fmt nlohmann_json::nlohmann_json mbedtls Opus::opus)
if (MINGW)
target_link_libraries(core PRIVATE ${MSWSOCK_LIBRARY})
endif()

View File

@@ -216,14 +216,6 @@ struct System::Impl {
}
}
void SetNVDECActive(bool is_nvdec_active) {
nvdec_active = is_nvdec_active;
}
bool GetNVDECActive() {
return nvdec_active;
}
void InitializeDebugger(System& system, u16 port) {
debugger = std::make_unique<Debugger>(system, port);
}
@@ -493,8 +485,6 @@ struct System::Impl {
std::atomic_bool is_powered_on{};
bool exit_lock = false;
bool nvdec_active{};
Reporter reporter;
std::unique_ptr<Memory::CheatEngine> cheat_engine;
std::unique_ptr<Tools::Freezer> memory_freezer;
@@ -604,14 +594,6 @@ void System::UnstallApplication() {
impl->UnstallApplication();
}
void System::SetNVDECActive(bool is_nvdec_active) {
impl->SetNVDECActive(is_nvdec_active);
}
bool System::GetNVDECActive() {
return impl->GetNVDECActive();
}
void System::InitializeDebugger() {
impl->InitializeDebugger(*this, Settings::values.gdbstub_port.GetValue());
}

View File

@@ -189,9 +189,6 @@ public:
std::unique_lock<std::mutex> StallApplication();
void UnstallApplication();
void SetNVDECActive(bool is_nvdec_active);
[[nodiscard]] bool GetNVDECActive();
/**
* Initialize the debugger.
*/

View File

@@ -23,8 +23,8 @@ const std::array<const char*, 16> LANGUAGE_NAMES{{
"Portuguese",
"Russian",
"Korean",
"TraditionalChinese",
"SimplifiedChinese",
"Taiwanese",
"Chinese",
"BrazilianPortuguese",
}};
@@ -45,17 +45,17 @@ constexpr std::array<Language, 18> language_to_codes = {{
Language::German,
Language::Italian,
Language::Spanish,
Language::SimplifiedChinese,
Language::Chinese,
Language::Korean,
Language::Dutch,
Language::Portuguese,
Language::Russian,
Language::TraditionalChinese,
Language::Taiwanese,
Language::BritishEnglish,
Language::CanadianFrench,
Language::LatinAmericanSpanish,
Language::SimplifiedChinese,
Language::TraditionalChinese,
Language::Chinese,
Language::Taiwanese,
Language::BrazilianPortuguese,
}};

View File

@@ -84,8 +84,8 @@ enum class Language : u8 {
Portuguese = 10,
Russian = 11,
Korean = 12,
TraditionalChinese = 13,
SimplifiedChinese = 14,
Taiwanese = 13,
Chinese = 14,
BrazilianPortuguese = 15,
Default = 255,

View File

@@ -21,12 +21,9 @@
#include "core/file_sys/patch_manager.h"
#include "core/file_sys/registered_cache.h"
#include "core/file_sys/romfs.h"
#include "core/file_sys/vfs_cached.h"
#include "core/file_sys/vfs_layered.h"
#include "core/file_sys/vfs_vector.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/hle/service/ns/language.h"
#include "core/hle/service/set/set.h"
#include "core/loader/loader.h"
#include "core/loader/nso.h"
#include "core/memory/cheat_engine.h"
@@ -383,11 +380,11 @@ static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, ContentRecordType t
auto romfs_dir = FindSubdirectoryCaseless(subdir, "romfs");
if (romfs_dir != nullptr)
layers.push_back(std::make_shared<CachedVfsDirectory>(romfs_dir));
layers.push_back(std::move(romfs_dir));
auto ext_dir = FindSubdirectoryCaseless(subdir, "romfs_ext");
if (ext_dir != nullptr)
layers_ext.push_back(std::make_shared<CachedVfsDirectory>(ext_dir));
layers_ext.push_back(std::move(ext_dir));
}
// When there are no layers to apply, return early as there is no need to rebuild the RomFS
@@ -626,37 +623,8 @@ PatchManager::Metadata PatchManager::ParseControlNCA(const NCA& nca) const {
auto nacp = nacp_file == nullptr ? nullptr : std::make_unique<NACP>(nacp_file);
// Get language code from settings
const auto language_code =
Service::Set::GetLanguageCodeFromIndex(Settings::values.language_index.GetValue());
// Convert to application language and get priority list
const auto application_language =
Service::NS::ConvertToApplicationLanguage(language_code)
.value_or(Service::NS::ApplicationLanguage::AmericanEnglish);
const auto language_priority_list =
Service::NS::GetApplicationLanguagePriorityList(application_language);
// Convert to language names
auto priority_language_names = FileSys::LANGUAGE_NAMES; // Copy
if (language_priority_list) {
for (size_t i = 0; i < priority_language_names.size(); ++i) {
// Relies on FileSys::LANGUAGE_NAMES being in the same order as
// Service::NS::ApplicationLanguage
const auto language_index = static_cast<u8>(language_priority_list->at(i));
if (language_index < FileSys::LANGUAGE_NAMES.size()) {
priority_language_names[i] = FileSys::LANGUAGE_NAMES[language_index];
} else {
// Not a catastrophe, unlikely to happen
LOG_WARNING(Loader, "Invalid language index {}", language_index);
}
}
}
// Get first matching icon
VirtualFile icon_file;
for (const auto& language : priority_language_names) {
for (const auto& language : FileSys::LANGUAGE_NAMES) {
icon_file = extracted->GetFile(std::string("icon_").append(language).append(".dat"));
if (icon_file != nullptr) {
break;

View File

@@ -9,7 +9,6 @@
#include "core/file_sys/fsmitm_romfsbuild.h"
#include "core/file_sys/romfs.h"
#include "core/file_sys/vfs.h"
#include "core/file_sys/vfs_cached.h"
#include "core/file_sys/vfs_concat.h"
#include "core/file_sys/vfs_offset.h"
#include "core/file_sys/vfs_vector.h"
@@ -133,7 +132,7 @@ VirtualDir ExtractRomFS(VirtualFile file, RomFSExtractionType type) {
out = out->GetSubdirectories().front();
}
return std::make_shared<CachedVfsDirectory>(out);
return out;
}
VirtualFile CreateRomFS(VirtualDir dir, VirtualDir ext) {

View File

@@ -200,32 +200,31 @@ std::string VfsFile::GetFullPath() const {
}
VirtualFile VfsDirectory::GetFileRelative(std::string_view path) const {
auto&& component_view = path | Common::FS::split_path_components_view;
auto next_component = component_view.begin();
if (next_component == component_view.end()) {
auto vec = Common::FS::SplitPathComponents(path);
vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }),
vec.end());
if (vec.empty()) {
return nullptr;
}
std::string_view component = *next_component;
if (++next_component == component_view.end()) {
return GetFile(component);
if (vec.size() == 1) {
return GetFile(vec[0]);
}
auto dir = GetSubdirectory(component);
if (dir == nullptr) {
return nullptr;
}
component = *next_component;
while (++next_component != component_view.end()) {
dir = dir->GetSubdirectory(component);
auto dir = GetSubdirectory(vec[0]);
for (std::size_t component = 1; component < vec.size() - 1; ++component) {
if (dir == nullptr) {
return nullptr;
}
component = *next_component;
dir = dir->GetSubdirectory(vec[component]);
}
return dir->GetFile(component);
if (dir == nullptr) {
return nullptr;
}
return dir->GetFile(vec.back());
}
VirtualFile VfsDirectory::GetFileAbsolute(std::string_view path) const {

View File

@@ -1,63 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/file_sys/vfs_cached.h"
#include "core/file_sys/vfs_types.h"
namespace FileSys {
CachedVfsDirectory::CachedVfsDirectory(VirtualDir& source_dir)
: name(source_dir->GetName()), parent(source_dir->GetParentDirectory()) {
for (auto& dir : source_dir->GetSubdirectories()) {
dirs.emplace(dir->GetName(), std::make_shared<CachedVfsDirectory>(dir));
}
for (auto& file : source_dir->GetFiles()) {
files.emplace(file->GetName(), file);
}
}
CachedVfsDirectory::~CachedVfsDirectory() = default;
VirtualFile CachedVfsDirectory::GetFile(std::string_view file_name) const {
auto it = files.find(file_name);
if (it != files.end()) {
return it->second;
}
return nullptr;
}
VirtualDir CachedVfsDirectory::GetSubdirectory(std::string_view dir_name) const {
auto it = dirs.find(dir_name);
if (it != dirs.end()) {
return it->second;
}
return nullptr;
}
std::vector<VirtualFile> CachedVfsDirectory::GetFiles() const {
std::vector<VirtualFile> out;
for (auto& [file_name, file] : files) {
out.push_back(file);
}
return out;
}
std::vector<VirtualDir> CachedVfsDirectory::GetSubdirectories() const {
std::vector<VirtualDir> out;
for (auto& [dir_name, dir] : dirs) {
out.push_back(dir);
}
return out;
}
std::string CachedVfsDirectory::GetName() const {
return name;
}
VirtualDir CachedVfsDirectory::GetParentDirectory() const {
return parent;
}
} // namespace FileSys

View File

@@ -1,31 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <string_view>
#include <vector>
#include "core/file_sys/vfs.h"
namespace FileSys {
class CachedVfsDirectory : public ReadOnlyVfsDirectory {
public:
CachedVfsDirectory(VirtualDir& source_directory);
~CachedVfsDirectory() override;
VirtualFile GetFile(std::string_view file_name) const override;
VirtualDir GetSubdirectory(std::string_view dir_name) const override;
std::vector<VirtualFile> GetFiles() const override;
std::vector<VirtualDir> GetSubdirectories() const override;
std::string GetName() const override;
VirtualDir GetParentDirectory() const override;
private:
std::string name;
VirtualDir parent;
std::map<std::string, VirtualDir, std::less<>> dirs;
std::map<std::string, VirtualFile, std::less<>> files;
};
} // namespace FileSys

View File

@@ -67,6 +67,23 @@ VectorVfsDirectory::VectorVfsDirectory(std::vector<VirtualFile> files_,
VectorVfsDirectory::~VectorVfsDirectory() = default;
VirtualFile VectorVfsDirectory::GetFile(std::string_view file_name) const {
if (!optimized_file_index_built) {
optimized_file_index.clear();
for (size_t i = 0; i < files.size(); i++) {
optimized_file_index.emplace(files[i]->GetName(), i);
}
optimized_file_index_built = true;
}
const auto it = optimized_file_index.find(file_name);
if (it != optimized_file_index.end()) {
return files[it->second];
}
return nullptr;
}
std::vector<VirtualFile> VectorVfsDirectory::GetFiles() const {
return files;
}
@@ -107,6 +124,7 @@ bool VectorVfsDirectory::DeleteSubdirectory(std::string_view subdir_name) {
}
bool VectorVfsDirectory::DeleteFile(std::string_view file_name) {
optimized_file_index_built = false;
return FindAndRemoveVectorElement(files, file_name);
}
@@ -124,6 +142,7 @@ VirtualFile VectorVfsDirectory::CreateFile(std::string_view file_name) {
}
void VectorVfsDirectory::AddFile(VirtualFile file) {
optimized_file_index_built = false;
files.push_back(std::move(file));
}

View File

@@ -105,6 +105,7 @@ public:
VirtualDir parent = nullptr);
~VectorVfsDirectory() override;
VirtualFile GetFile(std::string_view file_name) const override;
std::vector<VirtualFile> GetFiles() const override;
std::vector<VirtualDir> GetSubdirectories() const override;
bool IsWritable() const override;
@@ -126,6 +127,9 @@ private:
VirtualDir parent;
std::string name;
mutable std::map<std::string, size_t, std::less<>> optimized_file_index;
mutable bool optimized_file_index_built{};
};
} // namespace FileSys

View File

@@ -968,20 +968,16 @@ void FSP_SRV::ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute(HLERequ
void FSP_SRV::OpenDataStorageByCurrentProcess(HLERequestContext& ctx) {
LOG_DEBUG(Service_FS, "called");
if (!romfs) {
auto current_romfs = fsc.OpenRomFSCurrentProcess();
if (current_romfs.Failed()) {
// TODO (bunnei): Find the right error code to use here
LOG_CRITICAL(Service_FS, "no file system interface available!");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultUnknown);
return;
}
romfs = current_romfs.Unwrap();
auto current_romfs = fsc.OpenRomFSCurrentProcess();
if (current_romfs.Failed()) {
// TODO (bunnei): Find the right error code to use here
LOG_CRITICAL(Service_FS, "no file system interface available!");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultUnknown);
return;
}
auto storage = std::make_shared<IStorage>(system, romfs);
auto storage = std::make_shared<IStorage>(system, std::move(current_romfs.Unwrap()));
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);

View File

@@ -12,11 +12,6 @@
#pragma warning(pop)
#endif
#include <fmt/format.h>
#include "common/fs/file.h"
#include "common/fs/fs.h"
#include "common/fs/path_util.h"
#include "common/input.h"
#include "common/logging/log.h"
#include "common/string_util.h"
@@ -141,7 +136,7 @@ bool NfcDevice::LoadNfcTag(std::span<const u8> data) {
if (!NFP::AmiiboCrypto::IsKeyAvailable()) {
LOG_INFO(Service_NFC, "Loading amiibo without keys");
memcpy(&encrypted_tag_data, data.data(), sizeof(NFP::EncryptedNTAG215File));
BuildAmiiboWithoutKeys(tag_data, encrypted_tag_data);
BuildAmiiboWithoutKeys();
is_plain_amiibo = true;
is_write_protected = true;
return true;
@@ -371,25 +366,16 @@ Result NfcDevice::Mount(NFP::ModelType model_type, NFP::MountTarget mount_target
// The loaded amiibo is not encrypted
if (is_plain_amiibo) {
std::vector<u8> data(sizeof(NFP::NTAG215File));
memcpy(data.data(), &tag_data, sizeof(tag_data));
WriteBackupData(tag_data.uid, data);
device_state = DeviceState::TagMounted;
mount_target = mount_target_;
return ResultSuccess;
}
if (!NFP::AmiiboCrypto::DecodeAmiibo(encrypted_tag_data, tag_data)) {
bool has_backup = HasBackup(encrypted_tag_data.uuid.uid).IsSuccess();
LOG_ERROR(Service_NFP, "Can't decode amiibo, has_backup= {}", has_backup);
return has_backup ? ResultCorruptedDataWithBackup : ResultCorruptedData;
LOG_ERROR(Service_NFP, "Can't decode amiibo {}", device_state);
return ResultCorruptedData;
}
std::vector<u8> data(sizeof(NFP::EncryptedNTAG215File));
memcpy(data.data(), &encrypted_tag_data, sizeof(encrypted_tag_data));
WriteBackupData(encrypted_tag_data.uuid.uid, data);
device_state = DeviceState::TagMounted;
mount_target = mount_target_;
return ResultSuccess;
@@ -484,7 +470,6 @@ Result NfcDevice::FlushWithBreak(NFP::BreakType break_type) {
std::vector<u8> data(sizeof(NFP::EncryptedNTAG215File));
if (is_plain_amiibo) {
memcpy(data.data(), &tag_data, sizeof(tag_data));
WriteBackupData(tag_data.uid, data);
} else {
if (!NFP::AmiiboCrypto::EncodeAmiibo(tag_data, encrypted_tag_data)) {
LOG_ERROR(Service_NFP, "Failed to encode data");
@@ -492,7 +477,6 @@ Result NfcDevice::FlushWithBreak(NFP::BreakType break_type) {
}
memcpy(data.data(), &encrypted_tag_data, sizeof(encrypted_tag_data));
WriteBackupData(encrypted_tag_data.uuid.uid, data);
}
if (!npad_device->WriteNfc(data)) {
@@ -504,7 +488,7 @@ Result NfcDevice::FlushWithBreak(NFP::BreakType break_type) {
}
Result NfcDevice::Restore() {
if (device_state != DeviceState::TagFound) {
if (device_state != DeviceState::TagMounted) {
LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
if (device_state == DeviceState::TagRemoved) {
return ResultTagRemoved;
@@ -512,59 +496,13 @@ Result NfcDevice::Restore() {
return ResultWrongDeviceState;
}
NFC::TagInfo tag_info{};
std::array<u8, sizeof(NFP::EncryptedNTAG215File)> data{};
Result result = GetTagInfo(tag_info, false);
if (result.IsError()) {
return result;
if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
LOG_ERROR(Service_NFC, "Amiibo is read only", device_state);
return ResultWrongDeviceState;
}
result = ReadBackupData(tag_info.uuid, data);
if (result.IsError()) {
return result;
}
NFP::NTAG215File temporary_tag_data{};
NFP::EncryptedNTAG215File temporary_encrypted_tag_data{};
// Fallback for encrypted amiibos without keys
if (is_write_protected) {
return ResultWriteAmiiboFailed;
}
// Fallback for plain amiibos
if (is_plain_amiibo) {
LOG_INFO(Service_NFP, "Restoring backup of plain amiibo");
memcpy(&temporary_tag_data, data.data(), sizeof(NFP::EncryptedNTAG215File));
temporary_encrypted_tag_data = NFP::AmiiboCrypto::EncodedDataToNfcData(temporary_tag_data);
}
if (!is_plain_amiibo) {
LOG_INFO(Service_NFP, "Restoring backup of encrypted amiibo");
temporary_tag_data = {};
memcpy(&temporary_encrypted_tag_data, data.data(), sizeof(NFP::EncryptedNTAG215File));
}
if (!NFP::AmiiboCrypto::IsAmiiboValid(temporary_encrypted_tag_data)) {
return ResultNotAnAmiibo;
}
if (!is_plain_amiibo) {
if (!NFP::AmiiboCrypto::DecodeAmiibo(temporary_encrypted_tag_data, temporary_tag_data)) {
LOG_ERROR(Service_NFP, "Can't decode amiibo");
return ResultCorruptedData;
}
}
// Overwrite tag contents with backup and mount the tag
tag_data = temporary_tag_data;
encrypted_tag_data = temporary_encrypted_tag_data;
device_state = DeviceState::TagMounted;
mount_target = NFP::MountTarget::All;
is_data_moddified = true;
// TODO: Load amiibo from backup on system
LOG_ERROR(Service_NFP, "Not Implemented");
return ResultSuccess;
}
@@ -1194,69 +1132,13 @@ Result NfcDevice::BreakTag(NFP::BreakType break_type) {
return FlushWithBreak(break_type);
}
Result NfcDevice::HasBackup(const NFC::UniqueSerialNumber& uid) const {
constexpr auto backup_dir = "backup";
const auto yuzu_amiibo_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::AmiiboDir);
const auto file_name = fmt::format("{0:02x}.bin", fmt::join(uid, ""));
if (!Common::FS::Exists(yuzu_amiibo_dir / backup_dir / file_name)) {
return ResultUnableToAccessBackupFile;
}
Result NfcDevice::ReadBackupData(std::span<u8> data) const {
// Not implemented
return ResultSuccess;
}
Result NfcDevice::ReadBackupData(const NFC::UniqueSerialNumber& uid, std::span<u8> data) const {
constexpr auto backup_dir = "backup";
const auto yuzu_amiibo_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::AmiiboDir);
const auto file_name = fmt::format("{0:02x}.bin", fmt::join(uid, ""));
const Common::FS::IOFile keys_file{yuzu_amiibo_dir / backup_dir / file_name,
Common::FS::FileAccessMode::Read,
Common::FS::FileType::BinaryFile};
if (!keys_file.IsOpen()) {
LOG_ERROR(Service_NFP, "Failed to open amiibo backup");
return ResultUnableToAccessBackupFile;
}
if (keys_file.Read(data) != data.size()) {
LOG_ERROR(Service_NFP, "Failed to read amiibo backup");
return ResultUnableToAccessBackupFile;
}
return ResultSuccess;
}
Result NfcDevice::WriteBackupData(const NFC::UniqueSerialNumber& uid, std::span<const u8> data) {
constexpr auto backup_dir = "backup";
const auto yuzu_amiibo_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::AmiiboDir);
const auto file_name = fmt::format("{0:02x}.bin", fmt::join(uid, ""));
if (HasBackup(uid).IsError()) {
if (!Common::FS::CreateDir(yuzu_amiibo_dir / backup_dir)) {
return ResultBackupPathAlreadyExist;
}
if (!Common::FS::NewFile(yuzu_amiibo_dir / backup_dir / file_name)) {
return ResultBackupPathAlreadyExist;
}
}
const Common::FS::IOFile keys_file{yuzu_amiibo_dir / backup_dir / file_name,
Common::FS::FileAccessMode::ReadWrite,
Common::FS::FileType::BinaryFile};
if (!keys_file.IsOpen()) {
LOG_ERROR(Service_NFP, "Failed to open amiibo backup");
return ResultUnableToAccessBackupFile;
}
if (keys_file.Write(data) != data.size()) {
LOG_ERROR(Service_NFP, "Failed to write amiibo backup");
return ResultUnableToAccessBackupFile;
}
Result NfcDevice::WriteBackupData(std::span<const u8> data) {
// Not implemented
return ResultSuccess;
}
@@ -1295,8 +1177,7 @@ NFP::AmiiboName NfcDevice::GetAmiiboName(const NFP::AmiiboSettings& settings) co
return amiibo_name;
}
void NfcDevice::SetAmiiboName(NFP::AmiiboSettings& settings,
const NFP::AmiiboName& amiibo_name) const {
void NfcDevice::SetAmiiboName(NFP::AmiiboSettings& settings, const NFP::AmiiboName& amiibo_name) {
std::array<char16_t, NFP::amiibo_name_length> settings_amiibo_name{};
// Convert from utf8 to utf16
@@ -1377,23 +1258,22 @@ void NfcDevice::UpdateRegisterInfoCrc() {
tag_data.register_info_crc = crc.checksum();
}
void NfcDevice::BuildAmiiboWithoutKeys(NFP::NTAG215File& stubbed_tag_data,
const NFP::EncryptedNTAG215File& encrypted_file) const {
void NfcDevice::BuildAmiiboWithoutKeys() {
Service::Mii::MiiManager manager;
auto& settings = stubbed_tag_data.settings;
auto& settings = tag_data.settings;
stubbed_tag_data = NFP::AmiiboCrypto::NfcDataToEncodedData(encrypted_file);
tag_data = NFP::AmiiboCrypto::NfcDataToEncodedData(encrypted_tag_data);
// Common info
stubbed_tag_data.write_counter = 0;
stubbed_tag_data.amiibo_version = 0;
tag_data.write_counter = 0;
tag_data.amiibo_version = 0;
settings.write_date = GetAmiiboDate(GetCurrentPosixTime());
// Register info
SetAmiiboName(settings, {'y', 'u', 'z', 'u', 'A', 'm', 'i', 'i', 'b', 'o'});
settings.settings.font_region.Assign(0);
settings.init_date = GetAmiiboDate(GetCurrentPosixTime());
stubbed_tag_data.owner_mii = manager.BuildFromStoreData(manager.BuildDefault(0));
tag_data.owner_mii = manager.BuildFromStoreData(manager.BuildDefault(0));
// Admin info
settings.settings.amiibo_initialized.Assign(1);

View File

@@ -86,9 +86,8 @@ public:
Result GetAll(NFP::NfpData& data) const;
Result SetAll(const NFP::NfpData& data);
Result BreakTag(NFP::BreakType break_type);
Result HasBackup(const NFC::UniqueSerialNumber& uid) const;
Result ReadBackupData(const NFC::UniqueSerialNumber& uid, std::span<u8> data) const;
Result WriteBackupData(const NFC::UniqueSerialNumber& uid, std::span<const u8> data);
Result ReadBackupData(std::span<u8> data) const;
Result WriteBackupData(std::span<const u8> data);
Result WriteNtf(std::span<const u8> data);
u64 GetHandle() const;
@@ -104,15 +103,14 @@ private:
void CloseNfcTag();
NFP::AmiiboName GetAmiiboName(const NFP::AmiiboSettings& settings) const;
void SetAmiiboName(NFP::AmiiboSettings& settings, const NFP::AmiiboName& amiibo_name) const;
void SetAmiiboName(NFP::AmiiboSettings& settings, const NFP::AmiiboName& amiibo_name);
NFP::AmiiboDate GetAmiiboDate(s64 posix_time) const;
u64 GetCurrentPosixTime() const;
u64 RemoveVersionByte(u64 application_id) const;
void UpdateSettingsCrc();
void UpdateRegisterInfoCrc();
void BuildAmiiboWithoutKeys(NFP::NTAG215File& stubbed_tag_data,
const NFP::EncryptedNTAG215File& encrypted_file) const;
void BuildAmiiboWithoutKeys();
bool is_controller_set{};
int callback_key;

View File

@@ -543,14 +543,9 @@ Result DeviceManager::ReadBackupData(u64 device_handle, std::span<u8> data) cons
std::shared_ptr<NfcDevice> device = nullptr;
auto result = GetDeviceHandle(device_handle, device);
NFC::TagInfo tag_info{};
if (result.IsSuccess()) {
result = device->GetTagInfo(tag_info, false);
}
if (result.IsSuccess()) {
result = device->ReadBackupData(tag_info.uuid, data);
result = device->ReadBackupData(data);
result = VerifyDeviceResult(device, result);
}
@@ -562,14 +557,9 @@ Result DeviceManager::WriteBackupData(u64 device_handle, std::span<const u8> dat
std::shared_ptr<NfcDevice> device = nullptr;
auto result = GetDeviceHandle(device_handle, device);
NFC::TagInfo tag_info{};
if (result.IsSuccess()) {
result = device->GetTagInfo(tag_info, false);
}
if (result.IsSuccess()) {
result = device->WriteBackupData(tag_info.uuid, data);
result = device->WriteBackupData(data);
result = VerifyDeviceResult(device, result);
}

View File

@@ -302,7 +302,7 @@ Result NfcInterface::TranslateResultToServiceError(Result result) const {
return TranslateResultToNfp(result);
}
default:
if (result != ResultBackupPathAlreadyExist) {
if (result != ResultUnknown216) {
return result;
}
return ResultUnknown74;
@@ -343,9 +343,6 @@ Result NfcInterface::TranslateResultToNfp(Result result) const {
if (result == ResultApplicationAreaIsNotInitialized) {
return NFP::ResultApplicationAreaIsNotInitialized;
}
if (result == ResultCorruptedDataWithBackup) {
return NFP::ResultCorruptedDataWithBackup;
}
if (result == ResultCorruptedData) {
return NFP::ResultCorruptedData;
}
@@ -358,9 +355,6 @@ Result NfcInterface::TranslateResultToNfp(Result result) const {
if (result == ResultNotAnAmiibo) {
return NFP::ResultNotAnAmiibo;
}
if (result == ResultUnableToAccessBackupFile) {
return NFP::ResultUnableToAccessBackupFile;
}
LOG_WARNING(Service_NFC, "Result conversion not handled");
return result;
}

View File

@@ -9,22 +9,20 @@ namespace Service::NFC {
constexpr Result ResultDeviceNotFound(ErrorModule::NFC, 64);
constexpr Result ResultInvalidArgument(ErrorModule::NFC, 65);
constexpr Result ResultWrongApplicationAreaSize(ErrorModule::NFC, 68);
constexpr Result ResultWrongApplicationAreaSize(ErrorModule::NFP, 68);
constexpr Result ResultWrongDeviceState(ErrorModule::NFC, 73);
constexpr Result ResultUnknown74(ErrorModule::NFC, 74);
constexpr Result ResultUnknown76(ErrorModule::NFC, 76);
constexpr Result ResultNfcNotInitialized(ErrorModule::NFC, 77);
constexpr Result ResultNfcDisabled(ErrorModule::NFC, 80);
constexpr Result ResultWriteAmiiboFailed(ErrorModule::NFC, 88);
constexpr Result ResultWriteAmiiboFailed(ErrorModule::NFP, 88);
constexpr Result ResultTagRemoved(ErrorModule::NFC, 97);
constexpr Result ResultUnableToAccessBackupFile(ErrorModule::NFC, 113);
constexpr Result ResultRegistrationIsNotInitialized(ErrorModule::NFC, 120);
constexpr Result ResultApplicationAreaIsNotInitialized(ErrorModule::NFC, 128);
constexpr Result ResultCorruptedDataWithBackup(ErrorModule::NFC, 136);
constexpr Result ResultCorruptedData(ErrorModule::NFC, 144);
constexpr Result ResultWrongApplicationAreaId(ErrorModule::NFC, 152);
constexpr Result ResultApplicationAreaExist(ErrorModule::NFC, 168);
constexpr Result ResultNotAnAmiibo(ErrorModule::NFC, 178);
constexpr Result ResultBackupPathAlreadyExist(ErrorModule::NFC, 216);
constexpr Result ResultRegistrationIsNotInitialized(ErrorModule::NFP, 120);
constexpr Result ResultApplicationAreaIsNotInitialized(ErrorModule::NFP, 128);
constexpr Result ResultCorruptedData(ErrorModule::NFP, 144);
constexpr Result ResultWrongApplicationAreaId(ErrorModule::NFP, 152);
constexpr Result ResultApplicationAreaExist(ErrorModule::NFP, 168);
constexpr Result ResultNotAnAmiibo(ErrorModule::NFP, 178);
constexpr Result ResultUnknown216(ErrorModule::NFC, 216);
} // namespace Service::NFC

View File

@@ -126,7 +126,7 @@ void Interface::Flush(HLERequestContext& ctx) {
void Interface::Restore(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto device_handle{rp.Pop<u64>()};
LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
LOG_WARNING(Service_NFP, "(STUBBED) called, device_handle={}", device_handle);
auto result = GetManager()->Restore(device_handle);
result = TranslateResultToServiceError(result);
@@ -394,7 +394,7 @@ void Interface::BreakTag(HLERequestContext& ctx) {
void Interface::ReadBackupData(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto device_handle{rp.Pop<u64>()};
LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
LOG_WARNING(Service_NFP, "(STUBBED) called, device_handle={}", device_handle);
std::vector<u8> backup_data{};
auto result = GetManager()->ReadBackupData(device_handle, backup_data);
@@ -412,7 +412,7 @@ void Interface::WriteBackupData(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto device_handle{rp.Pop<u64>()};
const auto backup_data_buffer{ctx.ReadBuffer()};
LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
LOG_WARNING(Service_NFP, "(STUBBED) called, device_handle={}", device_handle);
auto result = GetManager()->WriteBackupData(device_handle, backup_data_buffer);
result = TranslateResultToServiceError(result);

View File

@@ -17,11 +17,9 @@ constexpr Result ResultWriteAmiiboFailed(ErrorModule::NFP, 88);
constexpr Result ResultTagRemoved(ErrorModule::NFP, 97);
constexpr Result ResultRegistrationIsNotInitialized(ErrorModule::NFP, 120);
constexpr Result ResultApplicationAreaIsNotInitialized(ErrorModule::NFP, 128);
constexpr Result ResultCorruptedDataWithBackup(ErrorModule::NFP, 136);
constexpr Result ResultCorruptedData(ErrorModule::NFP, 144);
constexpr Result ResultWrongApplicationAreaId(ErrorModule::NFP, 152);
constexpr Result ResultApplicationAreaExist(ErrorModule::NFP, 168);
constexpr Result ResultNotAnAmiibo(ErrorModule::NFP, 178);
constexpr Result ResultUnableToAccessBackupFile(ErrorModule::NFP, 200);
} // namespace Service::NFP

View File

@@ -69,7 +69,7 @@ NvResult nvhost_nvdec::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> in
void nvhost_nvdec::OnOpen(DeviceFD fd) {
LOG_INFO(Service_NVDRV, "NVDEC video stream started");
system.SetNVDECActive(true);
system.AudioCore().SetNVDECActive(true);
}
void nvhost_nvdec::OnClose(DeviceFD fd) {
@@ -79,7 +79,7 @@ void nvhost_nvdec::OnClose(DeviceFD fd) {
if (iter != host1x_file.fd_to_id.end()) {
system.GPU().ClearCdmaInstance(iter->second);
}
system.SetNVDECActive(false);
system.AudioCore().SetNVDECActive(false);
}
} // namespace Service::Nvidia::Devices

View File

@@ -324,10 +324,6 @@ s64 Nvnflinger::GetNextTicks() const {
speed_scale = 0.01f;
}
}
if (system.GetNVDECActive() && settings.use_video_framerate.GetValue()) {
// Run at intended presentation rate during video playback.
speed_scale = 1.f;
}
// As an extension, treat nonpositive swap interval as framerate multiplier.
const f32 effective_fps = swap_interval <= 0 ? 120.f * static_cast<f32>(1 - swap_interval)

View File

@@ -133,8 +133,8 @@ add_library(video_core STATIC
renderer_opengl/gl_shader_util.h
renderer_opengl/gl_state_tracker.cpp
renderer_opengl/gl_state_tracker.h
renderer_opengl/gl_staging_buffer_pool.cpp
renderer_opengl/gl_staging_buffer_pool.h
renderer_opengl/gl_stream_buffer.cpp
renderer_opengl/gl_stream_buffer.h
renderer_opengl/gl_texture_cache.cpp
renderer_opengl/gl_texture_cache.h
renderer_opengl/gl_texture_cache_base.cpp

View File

@@ -478,6 +478,7 @@ void BufferCache<P>::CommitAsyncFlushesHigh() {
if (committed_ranges.empty()) {
if constexpr (IMPLEMENTS_ASYNC_DOWNLOADS) {
async_buffers.emplace_back(std::optional<Async_Buffer>{});
}
return;
@@ -538,6 +539,7 @@ void BufferCache<P>::CommitAsyncFlushesHigh() {
committed_ranges.clear();
if (downloads.empty()) {
if constexpr (IMPLEMENTS_ASYNC_DOWNLOADS) {
async_buffers.emplace_back(std::optional<Async_Buffer>{});
}
return;
@@ -689,7 +691,7 @@ void BufferCache<P>::BindHostIndexBuffer() {
const u32 size = channel_state->index_buffer.size;
const auto& draw_state = maxwell3d->draw_manager->GetDrawState();
if (!draw_state.inline_index_draw_indexes.empty()) [[unlikely]] {
if constexpr (USE_MEMORY_MAPS_FOR_UPLOADS) {
if constexpr (USE_MEMORY_MAPS) {
auto upload_staging = runtime.UploadStagingBuffer(size);
std::array<BufferCopy, 1> copies{
{BufferCopy{.src_offset = upload_staging.offset, .dst_offset = 0, .size = size}}};
@@ -1460,7 +1462,7 @@ bool BufferCache<P>::SynchronizeBufferNoModified(Buffer& buffer, VAddr cpu_addr,
template <class P>
void BufferCache<P>::UploadMemory(Buffer& buffer, u64 total_size_bytes, u64 largest_copy,
std::span<BufferCopy> copies) {
if constexpr (USE_MEMORY_MAPS_FOR_UPLOADS) {
if constexpr (USE_MEMORY_MAPS) {
MappedUploadMemory(buffer, total_size_bytes, copies);
} else {
ImmediateUploadMemory(buffer, largest_copy, copies);
@@ -1471,7 +1473,7 @@ template <class P>
void BufferCache<P>::ImmediateUploadMemory([[maybe_unused]] Buffer& buffer,
[[maybe_unused]] u64 largest_copy,
[[maybe_unused]] std::span<const BufferCopy> copies) {
if constexpr (!USE_MEMORY_MAPS_FOR_UPLOADS) {
if constexpr (!USE_MEMORY_MAPS) {
std::span<u8> immediate_buffer;
for (const BufferCopy& copy : copies) {
std::span<const u8> upload_span;
@@ -1530,7 +1532,7 @@ bool BufferCache<P>::InlineMemory(VAddr dest_address, size_t copy_size,
auto& buffer = slot_buffers[buffer_id];
SynchronizeBuffer(buffer, dest_address, static_cast<u32>(copy_size));
if constexpr (USE_MEMORY_MAPS_FOR_UPLOADS) {
if constexpr (USE_MEMORY_MAPS) {
auto upload_staging = runtime.UploadStagingBuffer(copy_size);
std::array copies{BufferCopy{
.src_offset = upload_staging.offset,

View File

@@ -173,7 +173,6 @@ class BufferCache : public VideoCommon::ChannelSetupCaches<BufferCacheChannelInf
static constexpr bool USE_MEMORY_MAPS = P::USE_MEMORY_MAPS;
static constexpr bool SEPARATE_IMAGE_BUFFERS_BINDINGS = P::SEPARATE_IMAGE_BUFFER_BINDINGS;
static constexpr bool IMPLEMENTS_ASYNC_DOWNLOADS = P::IMPLEMENTS_ASYNC_DOWNLOADS;
static constexpr bool USE_MEMORY_MAPS_FOR_UPLOADS = P::USE_MEMORY_MAPS_FOR_UPLOADS;
static constexpr s64 DEFAULT_EXPECTED_MEMORY = 512_MiB;
static constexpr s64 DEFAULT_CRITICAL_MEMORY = 1_GiB;

View File

@@ -106,10 +106,8 @@ GLuint Buffer::View(u32 offset, u32 size, PixelFormat format) {
return views.back().texture.handle;
}
BufferCacheRuntime::BufferCacheRuntime(const Device& device_,
StagingBufferPool& staging_buffer_pool_)
: device{device_}, staging_buffer_pool{staging_buffer_pool_},
has_fast_buffer_sub_data{device.HasFastBufferSubData()},
BufferCacheRuntime::BufferCacheRuntime(const Device& device_)
: device{device_}, has_fast_buffer_sub_data{device.HasFastBufferSubData()},
use_assembly_shaders{device.UseAssemblyShaders()},
has_unified_vertex_buffers{device.HasVertexBufferUnifiedMemory()},
stream_buffer{has_fast_buffer_sub_data ? std::nullopt : std::make_optional<StreamBuffer>()} {
@@ -142,14 +140,6 @@ BufferCacheRuntime::BufferCacheRuntime(const Device& device_,
}();
}
StagingBufferMap BufferCacheRuntime::UploadStagingBuffer(size_t size) {
return staging_buffer_pool.RequestUploadBuffer(size);
}
StagingBufferMap BufferCacheRuntime::DownloadStagingBuffer(size_t size) {
return staging_buffer_pool.RequestDownloadBuffer(size);
}
u64 BufferCacheRuntime::GetDeviceMemoryUsage() const {
if (device.CanReportMemoryUsage()) {
return device_access_memory - device.GetCurrentDedicatedVideoMemory();
@@ -157,47 +147,13 @@ u64 BufferCacheRuntime::GetDeviceMemoryUsage() const {
return 2_GiB;
}
void BufferCacheRuntime::CopyBuffer(GLuint dst_buffer, GLuint src_buffer,
std::span<const VideoCommon::BufferCopy> copies, bool barrier) {
if (barrier) {
PreCopyBarrier();
}
for (const VideoCommon::BufferCopy& copy : copies) {
glCopyNamedBufferSubData(src_buffer, dst_buffer, static_cast<GLintptr>(copy.src_offset),
static_cast<GLintptr>(copy.dst_offset),
static_cast<GLsizeiptr>(copy.size));
}
if (barrier) {
PostCopyBarrier();
}
}
void BufferCacheRuntime::CopyBuffer(GLuint dst_buffer, Buffer& src_buffer,
std::span<const VideoCommon::BufferCopy> copies, bool barrier) {
CopyBuffer(dst_buffer, src_buffer.Handle(), copies, barrier);
}
void BufferCacheRuntime::CopyBuffer(Buffer& dst_buffer, GLuint src_buffer,
std::span<const VideoCommon::BufferCopy> copies, bool barrier) {
CopyBuffer(dst_buffer.Handle(), src_buffer, copies, barrier);
}
void BufferCacheRuntime::CopyBuffer(Buffer& dst_buffer, Buffer& src_buffer,
std::span<const VideoCommon::BufferCopy> copies) {
CopyBuffer(dst_buffer.Handle(), src_buffer.Handle(), copies);
}
void BufferCacheRuntime::PreCopyBarrier() {
// TODO: finer grained barrier?
glMemoryBarrier(GL_ALL_BARRIER_BITS);
}
void BufferCacheRuntime::PostCopyBarrier() {
glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT | GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT);
}
void BufferCacheRuntime::Finish() {
glFinish();
for (const VideoCommon::BufferCopy& copy : copies) {
glCopyNamedBufferSubData(
src_buffer.Handle(), dst_buffer.Handle(), static_cast<GLintptr>(copy.src_offset),
static_cast<GLintptr>(copy.dst_offset), static_cast<GLsizeiptr>(copy.size));
}
}
void BufferCacheRuntime::ClearBuffer(Buffer& dest_buffer, u32 offset, size_t size, u32 value) {

View File

@@ -12,7 +12,7 @@
#include "video_core/rasterizer_interface.h"
#include "video_core/renderer_opengl/gl_device.h"
#include "video_core/renderer_opengl/gl_resource_manager.h"
#include "video_core/renderer_opengl/gl_staging_buffer_pool.h"
#include "video_core/renderer_opengl/gl_stream_buffer.h"
namespace OpenGL {
@@ -60,28 +60,11 @@ class BufferCacheRuntime {
public:
static constexpr u8 INVALID_BINDING = std::numeric_limits<u8>::max();
explicit BufferCacheRuntime(const Device& device_, StagingBufferPool& staging_buffer_pool_);
[[nodiscard]] StagingBufferMap UploadStagingBuffer(size_t size);
[[nodiscard]] StagingBufferMap DownloadStagingBuffer(size_t size);
void CopyBuffer(GLuint dst_buffer, GLuint src_buffer,
std::span<const VideoCommon::BufferCopy> copies, bool barrier = true);
void CopyBuffer(GLuint dst_buffer, Buffer& src_buffer,
std::span<const VideoCommon::BufferCopy> copies, bool barrier = true);
void CopyBuffer(Buffer& dst_buffer, GLuint src_buffer,
std::span<const VideoCommon::BufferCopy> copies, bool barrier = true);
explicit BufferCacheRuntime(const Device& device_);
void CopyBuffer(Buffer& dst_buffer, Buffer& src_buffer,
std::span<const VideoCommon::BufferCopy> copies);
void PreCopyBarrier();
void PostCopyBarrier();
void Finish();
void ClearBuffer(Buffer& dest_buffer, u32 offset, size_t size, u32 value);
void BindIndexBuffer(Buffer& buffer, u32 offset, u32 size);
@@ -186,7 +169,6 @@ private:
};
const Device& device;
StagingBufferPool& staging_buffer_pool;
bool has_fast_buffer_sub_data = false;
bool use_assembly_shaders = false;
@@ -219,7 +201,7 @@ private:
struct BufferCacheParams {
using Runtime = OpenGL::BufferCacheRuntime;
using Buffer = OpenGL::Buffer;
using Async_Buffer = OpenGL::StagingBufferMap;
using Async_Buffer = u32;
using MemoryTracker = VideoCommon::MemoryTrackerBase<VideoCore::RasterizerInterface>;
static constexpr bool IS_OPENGL = true;
@@ -227,12 +209,9 @@ struct BufferCacheParams {
static constexpr bool HAS_FULL_INDEX_AND_PRIMITIVE_SUPPORT = true;
static constexpr bool NEEDS_BIND_UNIFORM_INDEX = true;
static constexpr bool NEEDS_BIND_STORAGE_INDEX = true;
static constexpr bool USE_MEMORY_MAPS = true;
static constexpr bool USE_MEMORY_MAPS = false;
static constexpr bool SEPARATE_IMAGE_BUFFER_BINDINGS = true;
static constexpr bool IMPLEMENTS_ASYNC_DOWNLOADS = false;
// TODO: Investigate why OpenGL seems to perform worse with persistently mapped buffer uploads
static constexpr bool USE_MEMORY_MAPS_FOR_UPLOADS = false;
};
using BufferCache = VideoCommon::BufferCache<BufferCacheParams>;

View File

@@ -24,7 +24,6 @@
#include "video_core/renderer_opengl/gl_query_cache.h"
#include "video_core/renderer_opengl/gl_rasterizer.h"
#include "video_core/renderer_opengl/gl_shader_cache.h"
#include "video_core/renderer_opengl/gl_staging_buffer_pool.h"
#include "video_core/renderer_opengl/gl_texture_cache.h"
#include "video_core/renderer_opengl/maxwell_to_gl.h"
#include "video_core/renderer_opengl/renderer_opengl.h"
@@ -59,9 +58,8 @@ RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& emu_window_, Tegra
StateTracker& state_tracker_)
: RasterizerAccelerated(cpu_memory_), gpu(gpu_), device(device_), screen_info(screen_info_),
program_manager(program_manager_), state_tracker(state_tracker_),
texture_cache_runtime(device, program_manager, state_tracker, staging_buffer_pool),
texture_cache(texture_cache_runtime, *this),
buffer_cache_runtime(device, staging_buffer_pool),
texture_cache_runtime(device, program_manager, state_tracker),
texture_cache(texture_cache_runtime, *this), buffer_cache_runtime(device),
buffer_cache(*this, cpu_memory_, buffer_cache_runtime),
shader_cache(*this, emu_window_, device, texture_cache, buffer_cache, program_manager,
state_tracker, gpu.ShaderNotify()),

View File

@@ -230,7 +230,6 @@ private:
ProgramManager& program_manager;
StateTracker& state_tracker;
StagingBufferPool staging_buffer_pool;
TextureCacheRuntime texture_cache_runtime;
TextureCache texture_cache;
BufferCacheRuntime buffer_cache_runtime;

View File

@@ -1,150 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <array>
#include <memory>
#include <span>
#include <glad/glad.h>
#include "common/alignment.h"
#include "common/assert.h"
#include "common/bit_util.h"
#include "common/microprofile.h"
#include "video_core/renderer_opengl/gl_staging_buffer_pool.h"
MICROPROFILE_DEFINE(OpenGL_BufferRequest, "OpenGL", "BufferRequest", MP_RGB(128, 128, 192));
namespace OpenGL {
StagingBufferMap::~StagingBufferMap() {
if (sync) {
sync->Create();
}
}
StagingBuffers::StagingBuffers(GLenum storage_flags_, GLenum map_flags_)
: storage_flags{storage_flags_}, map_flags{map_flags_} {}
StagingBuffers::~StagingBuffers() = default;
StagingBufferMap StagingBuffers::RequestMap(size_t requested_size, bool insert_fence) {
MICROPROFILE_SCOPE(OpenGL_BufferRequest);
const size_t index = RequestBuffer(requested_size);
OGLSync* const sync = insert_fence ? &syncs[index] : nullptr;
sync_indices[index] = insert_fence ? ++current_sync_index : 0;
return StagingBufferMap{
.mapped_span = std::span(maps[index], requested_size),
.sync = sync,
.buffer = buffers[index].handle,
};
}
size_t StagingBuffers::RequestBuffer(size_t requested_size) {
if (const std::optional<size_t> index = FindBuffer(requested_size); index) {
return *index;
}
OGLBuffer& buffer = buffers.emplace_back();
buffer.Create();
const auto next_pow2_size = Common::NextPow2(requested_size);
glNamedBufferStorage(buffer.handle, next_pow2_size, nullptr,
storage_flags | GL_MAP_PERSISTENT_BIT);
maps.push_back(static_cast<u8*>(glMapNamedBufferRange(buffer.handle, 0, next_pow2_size,
map_flags | GL_MAP_PERSISTENT_BIT)));
syncs.emplace_back();
sync_indices.emplace_back();
sizes.push_back(next_pow2_size);
ASSERT(syncs.size() == buffers.size() && buffers.size() == maps.size() &&
maps.size() == sizes.size());
return buffers.size() - 1;
}
std::optional<size_t> StagingBuffers::FindBuffer(size_t requested_size) {
size_t known_unsignaled_index = current_sync_index + 1;
size_t smallest_buffer = std::numeric_limits<size_t>::max();
std::optional<size_t> found;
const size_t num_buffers = sizes.size();
for (size_t index = 0; index < num_buffers; ++index) {
const size_t buffer_size = sizes[index];
if (buffer_size < requested_size || buffer_size >= smallest_buffer) {
continue;
}
if (syncs[index].handle != 0) {
if (sync_indices[index] >= known_unsignaled_index) {
// This fence is later than a fence that is known to not be signaled
continue;
}
if (!syncs[index].IsSignaled()) {
// Since this fence hasn't been signaled, it's safe to assume all later
// fences haven't been signaled either
known_unsignaled_index = std::min(known_unsignaled_index, sync_indices[index]);
continue;
}
syncs[index].Release();
}
smallest_buffer = buffer_size;
found = index;
}
return found;
}
StreamBuffer::StreamBuffer() {
static constexpr GLenum flags = GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT;
buffer.Create();
glObjectLabel(GL_BUFFER, buffer.handle, -1, "Stream Buffer");
glNamedBufferStorage(buffer.handle, STREAM_BUFFER_SIZE, nullptr, flags);
mapped_pointer =
static_cast<u8*>(glMapNamedBufferRange(buffer.handle, 0, STREAM_BUFFER_SIZE, flags));
for (OGLSync& sync : fences) {
sync.Create();
}
}
std::pair<std::span<u8>, size_t> StreamBuffer::Request(size_t size) noexcept {
ASSERT(size < REGION_SIZE);
for (size_t region = Region(used_iterator), region_end = Region(iterator); region < region_end;
++region) {
fences[region].Create();
}
used_iterator = iterator;
for (size_t region = Region(free_iterator) + 1,
region_end = std::min(Region(iterator + size) + 1, NUM_SYNCS);
region < region_end; ++region) {
glClientWaitSync(fences[region].handle, 0, GL_TIMEOUT_IGNORED);
fences[region].Release();
}
if (iterator + size >= free_iterator) {
free_iterator = iterator + size;
}
if (iterator + size > STREAM_BUFFER_SIZE) {
for (size_t region = Region(used_iterator); region < NUM_SYNCS; ++region) {
fences[region].Create();
}
used_iterator = 0;
iterator = 0;
free_iterator = size;
for (size_t region = 0, region_end = Region(size); region <= region_end; ++region) {
glClientWaitSync(fences[region].handle, 0, GL_TIMEOUT_IGNORED);
fences[region].Release();
}
}
const size_t offset = iterator;
iterator = Common::AlignUp(iterator + size, MAX_ALIGNMENT);
return {std::span(mapped_pointer + offset, size), offset};
}
StagingBufferMap StagingBufferPool::RequestUploadBuffer(size_t size) {
return upload_buffers.RequestMap(size, true);
}
StagingBufferMap StagingBufferPool::RequestDownloadBuffer(size_t size) {
return download_buffers.RequestMap(size, false);
}
} // namespace OpenGL

View File

@@ -0,0 +1,63 @@
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <array>
#include <memory>
#include <span>
#include <glad/glad.h>
#include "common/alignment.h"
#include "common/assert.h"
#include "video_core/renderer_opengl/gl_stream_buffer.h"
namespace OpenGL {
StreamBuffer::StreamBuffer() {
static constexpr GLenum flags = GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT;
buffer.Create();
glObjectLabel(GL_BUFFER, buffer.handle, -1, "Stream Buffer");
glNamedBufferStorage(buffer.handle, STREAM_BUFFER_SIZE, nullptr, flags);
mapped_pointer =
static_cast<u8*>(glMapNamedBufferRange(buffer.handle, 0, STREAM_BUFFER_SIZE, flags));
for (OGLSync& sync : fences) {
sync.Create();
}
}
std::pair<std::span<u8>, size_t> StreamBuffer::Request(size_t size) noexcept {
ASSERT(size < REGION_SIZE);
for (size_t region = Region(used_iterator), region_end = Region(iterator); region < region_end;
++region) {
fences[region].Create();
}
used_iterator = iterator;
for (size_t region = Region(free_iterator) + 1,
region_end = std::min(Region(iterator + size) + 1, NUM_SYNCS);
region < region_end; ++region) {
glClientWaitSync(fences[region].handle, 0, GL_TIMEOUT_IGNORED);
fences[region].Release();
}
if (iterator + size >= free_iterator) {
free_iterator = iterator + size;
}
if (iterator + size > STREAM_BUFFER_SIZE) {
for (size_t region = Region(used_iterator); region < NUM_SYNCS; ++region) {
fences[region].Create();
}
used_iterator = 0;
iterator = 0;
free_iterator = size;
for (size_t region = 0, region_end = Region(size); region <= region_end; ++region) {
glClientWaitSync(fences[region].handle, 0, GL_TIMEOUT_IGNORED);
fences[region].Release();
}
}
const size_t offset = iterator;
iterator = Common::AlignUp(iterator + size, MAX_ALIGNMENT);
return {std::span(mapped_pointer + offset, size), offset};
}
} // namespace OpenGL

View File

@@ -4,10 +4,8 @@
#pragma once
#include <array>
#include <optional>
#include <span>
#include <utility>
#include <vector>
#include <glad/glad.h>
@@ -19,35 +17,6 @@ namespace OpenGL {
using namespace Common::Literals;
struct StagingBufferMap {
~StagingBufferMap();
std::span<u8> mapped_span;
size_t offset = 0;
OGLSync* sync;
GLuint buffer;
};
struct StagingBuffers {
explicit StagingBuffers(GLenum storage_flags_, GLenum map_flags_);
~StagingBuffers();
StagingBufferMap RequestMap(size_t requested_size, bool insert_fence);
size_t RequestBuffer(size_t requested_size);
std::optional<size_t> FindBuffer(size_t requested_size);
std::vector<OGLSync> syncs;
std::vector<OGLBuffer> buffers;
std::vector<u8*> maps;
std::vector<size_t> sizes;
std::vector<size_t> sync_indices;
GLenum storage_flags;
GLenum map_flags;
size_t current_sync_index = 0;
};
class StreamBuffer {
static constexpr size_t STREAM_BUFFER_SIZE = 64_MiB;
static constexpr size_t NUM_SYNCS = 16;
@@ -79,17 +48,4 @@ private:
std::array<OGLSync, NUM_SYNCS> fences;
};
class StagingBufferPool {
public:
StagingBufferPool() = default;
~StagingBufferPool() = default;
StagingBufferMap RequestUploadBuffer(size_t size);
StagingBufferMap RequestDownloadBuffer(size_t size);
private:
StagingBuffers upload_buffers{GL_MAP_WRITE_BIT, GL_MAP_WRITE_BIT | GL_MAP_FLUSH_EXPLICIT_BIT};
StagingBuffers download_buffers{GL_MAP_READ_BIT | GL_CLIENT_STORAGE_BIT, GL_MAP_READ_BIT};
};
} // namespace OpenGL

View File

@@ -456,14 +456,19 @@ OGLTexture MakeImage(const VideoCommon::ImageInfo& info, GLenum gl_internal_form
return is_srgb ? GL_SRGB8_ALPHA8 : GL_RGBA8;
}
}
} // Anonymous namespace
ImageBufferMap::~ImageBufferMap() {
if (sync) {
sync->Create();
}
}
TextureCacheRuntime::TextureCacheRuntime(const Device& device_, ProgramManager& program_manager,
StateTracker& state_tracker_,
StagingBufferPool& staging_buffer_pool_)
: device{device_}, state_tracker{state_tracker_}, staging_buffer_pool{staging_buffer_pool_},
util_shaders(program_manager), format_conversion_pass{util_shaders},
resolution{Settings::values.resolution_info} {
StateTracker& state_tracker_)
: device{device_}, state_tracker{state_tracker_}, util_shaders(program_manager),
format_conversion_pass{util_shaders}, resolution{Settings::values.resolution_info} {
static constexpr std::array TARGETS{GL_TEXTURE_1D_ARRAY, GL_TEXTURE_2D_ARRAY, GL_TEXTURE_3D};
for (size_t i = 0; i < TARGETS.size(); ++i) {
const GLenum target = TARGETS[i];
@@ -553,12 +558,12 @@ void TextureCacheRuntime::Finish() {
glFinish();
}
StagingBufferMap TextureCacheRuntime::UploadStagingBuffer(size_t size) {
return staging_buffer_pool.RequestUploadBuffer(size);
ImageBufferMap TextureCacheRuntime::UploadStagingBuffer(size_t size) {
return upload_buffers.RequestMap(size, true);
}
StagingBufferMap TextureCacheRuntime::DownloadStagingBuffer(size_t size) {
return staging_buffer_pool.RequestDownloadBuffer(size);
ImageBufferMap TextureCacheRuntime::DownloadStagingBuffer(size_t size) {
return download_buffers.RequestMap(size, false);
}
u64 TextureCacheRuntime::GetDeviceMemoryUsage() const {
@@ -643,7 +648,7 @@ void TextureCacheRuntime::BlitFramebuffer(Framebuffer* dst, Framebuffer* src,
is_linear ? GL_LINEAR : GL_NEAREST);
}
void TextureCacheRuntime::AccelerateImageUpload(Image& image, const StagingBufferMap& map,
void TextureCacheRuntime::AccelerateImageUpload(Image& image, const ImageBufferMap& map,
std::span<const SwizzleParameters> swizzles) {
switch (image.info.type) {
case ImageType::e2D:
@@ -685,6 +690,64 @@ bool TextureCacheRuntime::HasNativeASTC() const noexcept {
return device.HasASTC();
}
TextureCacheRuntime::StagingBuffers::StagingBuffers(GLenum storage_flags_, GLenum map_flags_)
: storage_flags{storage_flags_}, map_flags{map_flags_} {}
TextureCacheRuntime::StagingBuffers::~StagingBuffers() = default;
ImageBufferMap TextureCacheRuntime::StagingBuffers::RequestMap(size_t requested_size,
bool insert_fence) {
const size_t index = RequestBuffer(requested_size);
OGLSync* const sync = insert_fence ? &syncs[index] : nullptr;
return ImageBufferMap{
.mapped_span = std::span(maps[index], requested_size),
.sync = sync,
.buffer = buffers[index].handle,
};
}
size_t TextureCacheRuntime::StagingBuffers::RequestBuffer(size_t requested_size) {
if (const std::optional<size_t> index = FindBuffer(requested_size); index) {
return *index;
}
OGLBuffer& buffer = buffers.emplace_back();
buffer.Create();
glNamedBufferStorage(buffer.handle, requested_size, nullptr,
storage_flags | GL_MAP_PERSISTENT_BIT);
maps.push_back(static_cast<u8*>(glMapNamedBufferRange(buffer.handle, 0, requested_size,
map_flags | GL_MAP_PERSISTENT_BIT)));
syncs.emplace_back();
sizes.push_back(requested_size);
ASSERT(syncs.size() == buffers.size() && buffers.size() == maps.size() &&
maps.size() == sizes.size());
return buffers.size() - 1;
}
std::optional<size_t> TextureCacheRuntime::StagingBuffers::FindBuffer(size_t requested_size) {
size_t smallest_buffer = std::numeric_limits<size_t>::max();
std::optional<size_t> found;
const size_t num_buffers = sizes.size();
for (size_t index = 0; index < num_buffers; ++index) {
const size_t buffer_size = sizes[index];
if (buffer_size < requested_size || buffer_size >= smallest_buffer) {
continue;
}
if (syncs[index].handle != 0) {
if (!syncs[index].IsSignaled()) {
continue;
}
syncs[index].Release();
}
smallest_buffer = buffer_size;
found = index;
}
return found;
}
Image::Image(TextureCacheRuntime& runtime_, const VideoCommon::ImageInfo& info_, GPUVAddr gpu_addr_,
VAddr cpu_addr_)
: VideoCommon::ImageBase(info_, gpu_addr_, cpu_addr_), runtime{&runtime_} {
@@ -760,7 +823,7 @@ void Image::UploadMemory(GLuint buffer_handle, size_t buffer_offset,
}
}
void Image::UploadMemory(const StagingBufferMap& map,
void Image::UploadMemory(const ImageBufferMap& map,
std::span<const VideoCommon::BufferImageCopy> copies) {
UploadMemory(map.buffer, map.offset, copies);
}
@@ -807,7 +870,7 @@ void Image::DownloadMemory(std::span<GLuint> buffer_handles, std::span<size_t> b
}
}
void Image::DownloadMemory(StagingBufferMap& map,
void Image::DownloadMemory(ImageBufferMap& map,
std::span<const VideoCommon::BufferImageCopy> copies) {
DownloadMemory(map.buffer, map.offset, copies);
}

View File

@@ -11,7 +11,6 @@
#include "shader_recompiler/shader_info.h"
#include "video_core/renderer_opengl/gl_device.h"
#include "video_core/renderer_opengl/gl_resource_manager.h"
#include "video_core/renderer_opengl/gl_staging_buffer_pool.h"
#include "video_core/renderer_opengl/util_shaders.h"
#include "video_core/texture_cache/image_view_base.h"
#include "video_core/texture_cache/texture_cache_base.h"
@@ -38,6 +37,15 @@ using VideoCommon::Region2D;
using VideoCommon::RenderTargets;
using VideoCommon::SlotVector;
struct ImageBufferMap {
~ImageBufferMap();
std::span<u8> mapped_span;
size_t offset = 0;
OGLSync* sync;
GLuint buffer;
};
struct FormatProperties {
GLenum compatibility_class;
bool compatibility_by_size;
@@ -66,15 +74,14 @@ class TextureCacheRuntime {
public:
explicit TextureCacheRuntime(const Device& device, ProgramManager& program_manager,
StateTracker& state_tracker,
StagingBufferPool& staging_buffer_pool);
StateTracker& state_tracker);
~TextureCacheRuntime();
void Finish();
StagingBufferMap UploadStagingBuffer(size_t size);
ImageBufferMap UploadStagingBuffer(size_t size);
StagingBufferMap DownloadStagingBuffer(size_t size);
ImageBufferMap DownloadStagingBuffer(size_t size);
u64 GetDeviceLocalMemory() const {
return device_access_memory;
@@ -113,7 +120,7 @@ public:
const Region2D& src_region, Tegra::Engines::Fermi2D::Filter filter,
Tegra::Engines::Fermi2D::Operation operation);
void AccelerateImageUpload(Image& image, const StagingBufferMap& map,
void AccelerateImageUpload(Image& image, const ImageBufferMap& map,
std::span<const VideoCommon::SwizzleParameters> swizzles);
void InsertUploadMemoryBarrier();
@@ -142,16 +149,35 @@ public:
}
private:
struct StagingBuffers {
explicit StagingBuffers(GLenum storage_flags_, GLenum map_flags_);
~StagingBuffers();
ImageBufferMap RequestMap(size_t requested_size, bool insert_fence);
size_t RequestBuffer(size_t requested_size);
std::optional<size_t> FindBuffer(size_t requested_size);
std::vector<OGLSync> syncs;
std::vector<OGLBuffer> buffers;
std::vector<u8*> maps;
std::vector<size_t> sizes;
GLenum storage_flags;
GLenum map_flags;
};
const Device& device;
StateTracker& state_tracker;
StagingBufferPool& staging_buffer_pool;
UtilShaders util_shaders;
FormatConversionPass format_conversion_pass;
std::array<std::unordered_map<GLenum, FormatProperties>, 3> format_properties;
bool has_broken_texture_view_formats = false;
StagingBuffers upload_buffers{GL_MAP_WRITE_BIT, GL_MAP_WRITE_BIT | GL_MAP_FLUSH_EXPLICIT_BIT};
StagingBuffers download_buffers{GL_MAP_READ_BIT | GL_CLIENT_STORAGE_BIT, GL_MAP_READ_BIT};
OGLTexture null_image_1d_array;
OGLTexture null_image_cube_array;
OGLTexture null_image_3d;
@@ -187,7 +213,7 @@ public:
void UploadMemory(GLuint buffer_handle, size_t buffer_offset,
std::span<const VideoCommon::BufferImageCopy> copies);
void UploadMemory(const StagingBufferMap& map,
void UploadMemory(const ImageBufferMap& map,
std::span<const VideoCommon::BufferImageCopy> copies);
void DownloadMemory(GLuint buffer_handle, size_t buffer_offset,
@@ -196,8 +222,7 @@ public:
void DownloadMemory(std::span<GLuint> buffer_handle, std::span<size_t> buffer_offset,
std::span<const VideoCommon::BufferImageCopy> copies);
void DownloadMemory(StagingBufferMap& map,
std::span<const VideoCommon::BufferImageCopy> copies);
void DownloadMemory(ImageBufferMap& map, std::span<const VideoCommon::BufferImageCopy> copies);
GLuint StorageHandle() noexcept;

View File

@@ -19,7 +19,6 @@
#include "video_core/host_shaders/pitch_unswizzle_comp.h"
#include "video_core/renderer_opengl/gl_shader_manager.h"
#include "video_core/renderer_opengl/gl_shader_util.h"
#include "video_core/renderer_opengl/gl_staging_buffer_pool.h"
#include "video_core/renderer_opengl/gl_texture_cache.h"
#include "video_core/renderer_opengl/util_shaders.h"
#include "video_core/texture_cache/accelerated_swizzle.h"
@@ -64,7 +63,7 @@ UtilShaders::UtilShaders(ProgramManager& program_manager_)
UtilShaders::~UtilShaders() = default;
void UtilShaders::ASTCDecode(Image& image, const StagingBufferMap& map,
void UtilShaders::ASTCDecode(Image& image, const ImageBufferMap& map,
std::span<const VideoCommon::SwizzleParameters> swizzles) {
static constexpr GLuint BINDING_INPUT_BUFFER = 0;
static constexpr GLuint BINDING_OUTPUT_IMAGE = 0;
@@ -112,7 +111,7 @@ void UtilShaders::ASTCDecode(Image& image, const StagingBufferMap& map,
program_manager.RestoreGuestCompute();
}
void UtilShaders::BlockLinearUpload2D(Image& image, const StagingBufferMap& map,
void UtilShaders::BlockLinearUpload2D(Image& image, const ImageBufferMap& map,
std::span<const SwizzleParameters> swizzles) {
static constexpr Extent3D WORKGROUP_SIZE{32, 32, 1};
static constexpr GLuint BINDING_SWIZZLE_BUFFER = 0;
@@ -149,7 +148,7 @@ void UtilShaders::BlockLinearUpload2D(Image& image, const StagingBufferMap& map,
program_manager.RestoreGuestCompute();
}
void UtilShaders::BlockLinearUpload3D(Image& image, const StagingBufferMap& map,
void UtilShaders::BlockLinearUpload3D(Image& image, const ImageBufferMap& map,
std::span<const SwizzleParameters> swizzles) {
static constexpr Extent3D WORKGROUP_SIZE{16, 8, 8};
@@ -190,7 +189,7 @@ void UtilShaders::BlockLinearUpload3D(Image& image, const StagingBufferMap& map,
program_manager.RestoreGuestCompute();
}
void UtilShaders::PitchUpload(Image& image, const StagingBufferMap& map,
void UtilShaders::PitchUpload(Image& image, const ImageBufferMap& map,
std::span<const SwizzleParameters> swizzles) {
static constexpr Extent3D WORKGROUP_SIZE{32, 32, 1};
static constexpr GLuint BINDING_INPUT_BUFFER = 0;

View File

@@ -16,23 +16,23 @@ namespace OpenGL {
class Image;
class ProgramManager;
struct StagingBufferMap;
struct ImageBufferMap;
class UtilShaders {
public:
explicit UtilShaders(ProgramManager& program_manager);
~UtilShaders();
void ASTCDecode(Image& image, const StagingBufferMap& map,
void ASTCDecode(Image& image, const ImageBufferMap& map,
std::span<const VideoCommon::SwizzleParameters> swizzles);
void BlockLinearUpload2D(Image& image, const StagingBufferMap& map,
void BlockLinearUpload2D(Image& image, const ImageBufferMap& map,
std::span<const VideoCommon::SwizzleParameters> swizzles);
void BlockLinearUpload3D(Image& image, const StagingBufferMap& map,
void BlockLinearUpload3D(Image& image, const ImageBufferMap& map,
std::span<const VideoCommon::SwizzleParameters> swizzles);
void PitchUpload(Image& image, const StagingBufferMap& map,
void PitchUpload(Image& image, const ImageBufferMap& map,
std::span<const VideoCommon::SwizzleParameters> swizzles);
void CopyBC4(Image& dst_image, Image& src_image,

View File

@@ -157,7 +157,6 @@ struct BufferCacheParams {
static constexpr bool USE_MEMORY_MAPS = true;
static constexpr bool SEPARATE_IMAGE_BUFFER_BINDINGS = false;
static constexpr bool IMPLEMENTS_ASYNC_DOWNLOADS = true;
static constexpr bool USE_MEMORY_MAPS_FOR_UPLOADS = true;
};
using BufferCache = VideoCommon::BufferCache<BufferCacheParams>;

View File

@@ -306,9 +306,6 @@ void PresentManager::CopyToSwapchain(Frame* frame) {
image_count = swapchain.GetImageCount();
};
#ifdef ANDROID
std::unique_lock lock{recreate_surface_mutex};
const auto needs_recreation = [&] {
if (last_render_surface != render_window.GetWindowInfo().render_surface) {
return true;
@@ -319,6 +316,9 @@ void PresentManager::CopyToSwapchain(Frame* frame) {
return false;
};
#ifdef ANDROID
std::unique_lock lock{recreate_surface_mutex};
recreate_surface_cv.wait_for(lock, std::chrono::milliseconds(400),
[&]() { return !needs_recreation(); });

View File

@@ -850,11 +850,15 @@ void TextureCache<P>::PopAsyncFlushes() {
template <class P>
ImageId TextureCache<P>::DmaImageId(const Tegra::DMA::ImageOperand& operand, bool is_upload) {
const ImageInfo dst_info(operand);
const ImageId image_id = FindDMAImage(dst_info, operand.address);
if (!image_id) {
const ImageId dst_id = FindDMAImage(dst_info, operand.address);
if (!dst_id) {
return NULL_IMAGE_ID;
}
auto& image = slot_images[dst_id];
if (False(image.flags & ImageFlagBits::GpuModified)) {
// No need to waste time on an image that's synced with guest
return NULL_IMAGE_ID;
}
auto& image = slot_images[image_id];
if (!is_upload && !image.info.dma_downloaded) {
// Force a full sync.
image.info.dma_downloaded = true;
@@ -864,7 +868,7 @@ ImageId TextureCache<P>::DmaImageId(const Tegra::DMA::ImageOperand& operand, boo
if (!base) {
return NULL_IMAGE_ID;
}
return image_id;
return dst_id;
}
template <class P>

View File

@@ -85,6 +85,7 @@
// Define extensions which must be supported.
#define FOR_EACH_VK_MANDATORY_EXTENSION(EXTENSION_NAME) \
EXTENSION_NAME(VK_EXT_ROBUSTNESS_2_EXTENSION_NAME) \
EXTENSION_NAME(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME) \
EXTENSION_NAME(VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME) \
EXTENSION_NAME(VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_EXTENSION_NAME) \
@@ -104,7 +105,6 @@
EXTENSION_NAME(VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME) \
EXTENSION_NAME(VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME) \
EXTENSION_NAME(VK_EXT_LINE_RASTERIZATION_EXTENSION_NAME) \
EXTENSION_NAME(VK_EXT_ROBUSTNESS_2_EXTENSION_NAME) \
EXTENSION_NAME(VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME) \
EXTENSION_NAME(VK_NV_GEOMETRY_SHADER_PASSTHROUGH_EXTENSION_NAME) \
EXTENSION_NAME(VK_NV_VIEWPORT_ARRAY2_EXTENSION_NAME) \
@@ -141,6 +141,9 @@
FEATURE_NAME(features, vertexPipelineStoresAndAtomics) \
FEATURE_NAME(features, wideLines) \
FEATURE_NAME(host_query_reset, hostQueryReset) \
FEATURE_NAME(robustness2, nullDescriptor) \
FEATURE_NAME(robustness2, robustBufferAccess2) \
FEATURE_NAME(robustness2, robustImageAccess2) \
FEATURE_NAME(shader_demote_to_helper_invocation, shaderDemoteToHelperInvocation) \
FEATURE_NAME(shader_draw_parameters, shaderDrawParameters) \
FEATURE_NAME(variable_pointer, variablePointers) \
@@ -153,9 +156,6 @@
FEATURE_NAME(index_type_uint8, indexTypeUint8) \
FEATURE_NAME(primitive_topology_list_restart, primitiveTopologyListRestart) \
FEATURE_NAME(provoking_vertex, provokingVertexLast) \
FEATURE_NAME(robustness2, nullDescriptor) \
FEATURE_NAME(robustness2, robustBufferAccess2) \
FEATURE_NAME(robustness2, robustImageAccess2) \
FEATURE_NAME(shader_float16_int8, shaderFloat16) \
FEATURE_NAME(shader_float16_int8, shaderInt8) \
FEATURE_NAME(timeline_semaphore, timelineSemaphore) \

View File

@@ -42,7 +42,6 @@ void ConfigureGraphicsAdvanced::SetConfiguration() {
Settings::values.use_vulkan_driver_pipeline_cache.GetValue());
ui->enable_compute_pipelines_checkbox->setChecked(
Settings::values.enable_compute_pipelines.GetValue());
ui->use_video_framerate_checkbox->setChecked(Settings::values.use_video_framerate.GetValue());
if (Settings::IsConfiguringGlobal()) {
ui->gpu_accuracy->setCurrentIndex(
@@ -92,8 +91,6 @@ void ConfigureGraphicsAdvanced::ApplyConfiguration() {
ConfigurationShared::ApplyPerGameSetting(&Settings::values.enable_compute_pipelines,
ui->enable_compute_pipelines_checkbox,
enable_compute_pipelines);
ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_video_framerate,
ui->use_video_framerate_checkbox, use_video_framerate);
}
void ConfigureGraphicsAdvanced::changeEvent(QEvent* event) {
@@ -128,8 +125,6 @@ void ConfigureGraphicsAdvanced::SetupPerGameUI() {
Settings::values.max_anisotropy.UsingGlobal());
ui->enable_compute_pipelines_checkbox->setEnabled(
Settings::values.enable_compute_pipelines.UsingGlobal());
ui->use_video_framerate_checkbox->setEnabled(
Settings::values.use_video_framerate.UsingGlobal());
return;
}
@@ -154,9 +149,6 @@ void ConfigureGraphicsAdvanced::SetupPerGameUI() {
ConfigurationShared::SetColoredTristate(ui->enable_compute_pipelines_checkbox,
Settings::values.enable_compute_pipelines,
enable_compute_pipelines);
ConfigurationShared::SetColoredTristate(ui->use_video_framerate_checkbox,
Settings::values.use_video_framerate,
use_video_framerate);
ConfigurationShared::SetColoredComboBox(
ui->gpu_accuracy, ui->label_gpu_accuracy,
static_cast<int>(Settings::values.gpu_accuracy.GetValue(true)));

View File

@@ -47,7 +47,6 @@ private:
ConfigurationShared::CheckState use_fast_gpu_time;
ConfigurationShared::CheckState use_vulkan_driver_pipeline_cache;
ConfigurationShared::CheckState enable_compute_pipelines;
ConfigurationShared::CheckState use_video_framerate;
const Core::System& system;
};

View File

@@ -191,16 +191,6 @@ Compute pipelines are always enabled on all other drivers.</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="use_video_framerate_checkbox">
<property name="toolTip">
<string>Run the game at normal speed during video playback, even when the framerate is unlocked.</string>
</property>
<property name="text">
<string>Sync to framerate of video playback</string>
</property>
</widget>
</item>
<item>
<widget class="QWidget" name="af_layout" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_1">

View File

@@ -3491,7 +3491,6 @@ void GMainWindow::ResetWindowSize1080() {
void GMainWindow::OnConfigure() {
const auto old_theme = UISettings::values.theme;
const bool old_discord_presence = UISettings::values.enable_discord_presence.GetValue();
const auto old_language_index = Settings::values.language_index.GetValue();
Settings::SetConfiguringGlobal(true);
ConfigureDialog configure_dialog(this, hotkey_registry, input_subsystem.get(), *system,
@@ -3560,7 +3559,7 @@ void GMainWindow::OnConfigure() {
emit UpdateThemedIcons();
const auto reload = UISettings::values.is_game_list_reload_pending.exchange(false);
if (reload || Settings::values.language_index.GetValue() != old_language_index) {
if (reload) {
game_list->PopulateAsync(UISettings::values.game_dirs);
}

View File

@@ -24,7 +24,6 @@
"fmt",
"lz4",
"nlohmann-json",
"range-v3",
"zlib",
"zstd"
],