Compare commits

...

218 Commits

Author SHA1 Message Date
11c51b8d69 Android #40 2023-08-15 00:58:01 +00:00
6d665a94ea Merge pull request #11256 from FearlessTobi/revert-10075
Partially Revert "Silence nifm spam"
2023-08-14 16:28:13 -07:00
bbc6b08fc7 Merge pull request #11273 from t895/setup-completion
android: Setup additions
2023-08-14 15:41:35 -07:00
2694f81462 Revert "Silence nifm spam"
This reverts commit 4da4ecb1ff.
2023-08-14 21:23:09 +02:00
d5adaeafdf Merge pull request #11271 from t895/settings-tweaks
android: Settings tweaks
2023-08-14 11:44:38 -07:00
58a4c86797 Merge pull request #11282 from ameerj/glasm-xfb
gl_graphics_pipeline: GLASM: Fix transform feedback with multiple buffers
2023-08-14 09:19:20 -04:00
35a77c3bb2 Merge pull request #11283 from ameerj/glasm-pipeline-detection
gl_graphics_pipeline: Fix GLASM storage buffer detection
2023-08-14 09:19:10 -04:00
c1016b68ae Merge pull request #11281 from liamwhite/vi-scale-mode
nvnflinger: add missing scale mode
2023-08-14 09:19:03 -04:00
b30df50076 Merge pull request #11259 from german77/hid
service: hid: Implement functions needed by QLaunch
2023-08-14 09:18:55 -04:00
5afe1367ba Merge pull request #11263 from liamwhite/my-feature-branch
vulkan_device: disable features associated with unloaded extensions
2023-08-14 09:18:47 -04:00
24700af3c2 Merge pull request #11264 from liamwhite/stray-code
ssl_backend_securetransport: remove stray .Code()
2023-08-14 09:18:32 -04:00
f9ef721ca6 gl_graphics_pipeline: Fix GLASM storage buffer detection 2023-08-13 17:06:45 -04:00
c34ed4bbd8 gl_graphics_pipeline: GLASM: Fix transform feedback with multiple buffers 2023-08-13 16:50:01 -04:00
7351884588 nvnflinger: add missing scale mode 2023-08-13 13:57:02 -04:00
242ce2a0b3 android: Page forward on setup step completion 2023-08-12 20:21:47 -04:00
8ab3685a39 android: Adjust setup fragment layout
Fixes padding issues in small and large layouts and allows viewpager to reach into system insets.
2023-08-12 17:02:59 -04:00
8bd0521b58 android: Show complete indicator during setup 2023-08-12 16:53:14 -04:00
64ea5522d3 android: Remove redundant option from slider dialog
You can already reset any setting by long pressing the settings item.
2023-08-12 15:45:27 -04:00
798a439eb1 android: Reduce opacity of non-editable settings 2023-08-12 15:42:55 -04:00
786b609151 android: Use string resource for slider value/units 2023-08-12 15:42:54 -04:00
89a2d308c3 android: Display setting value in setting list items 2023-08-12 14:38:46 -04:00
0d4bf53ad9 android: Set switch listener before assigning new value
Previously the switch could have its old listener triggered when recycled.
2023-08-12 01:00:42 -04:00
8b98c4e5a0 ssl_backend_securetransport: remove stray .Code() 2023-08-11 23:32:46 -04:00
26ff214719 Merge pull request #11219 from zeltermann/title-id-search
Allow searching by a substring of the title ID
2023-08-11 16:53:27 -04:00
640f7cd945 Merge pull request #11253 from liamwhite/i-hate-this-toolchain
general: fix apple clang build
2023-08-11 16:53:20 -04:00
7d8f748696 vulkan_device: disable features associated with unloaded extensions 2023-08-11 14:54:12 -04:00
bdd96118d1 service: hid: Implement functions needed by QLaunch 2023-08-11 10:13:21 -06:00
1ed9e8812b Allow searching by a substring of the title ID 2023-08-11 00:07:12 +07:00
9d3a293a4e Merge pull request #11093 from liamwhite/result-ergonomics
core: remove ResultVal type
2023-08-09 21:24:31 -07:00
3d6ce9dd2b Merge pull request #11247 from german77/pctl
service: pctl: Partially revert 11221
2023-08-09 21:24:06 -07:00
023b9b38cc general: fix apple clang build 2023-08-09 22:38:37 -04:00
6a43aff745 service: pctl: Partially revert 11221 2023-08-08 16:52:21 -06:00
1e394c6cdf fs: return result on null outputs 2023-08-08 16:12:04 -04:00
37b278a9a8 general: fix incorrect conversions 2023-08-08 11:09:37 -04:00
83eee1d226 ssl: remove ResultVal use 2023-08-08 11:09:37 -04:00
84cb20bc72 core: remove ResultVal type 2023-08-08 11:09:37 -04:00
85e3575496 Merge pull request #11216 from lat9nq/no-mesa-astc
gl_device: Detect Mesa to disable their ASTC
2023-08-07 11:34:22 -04:00
7f55c377b0 Merge pull request #11217 from german77/olsc
service: olsc: Implement IOlscServiceForSystemService ITransferTaskListController interfaces for QLaunch
2023-08-07 11:34:14 -04:00
9893a4d918 Merge pull request #11221 from german77/pctl
service: pctl: Implement functions needed for QLaunch
2023-08-07 11:34:07 -04:00
bed2fc8707 Merge pull request #11224 from german77/audio
service: audctl: Stub functions needed by Qlaunch
2023-08-07 11:33:55 -04:00
8d2f0dc707 service: audctl: Stub functions needed by Qlaunch 2023-08-05 20:16:26 -06:00
cb0b8442f0 gl_device: Filter more specifically for slow ASTC
Adds a check to find if the renderer is Intel DG (i.e. DG2).

gl_device: Detect Mesa to disable their ASTC

In our testing, our own ASTC decoder has shown itself to perform faster
than the included one from the driver. Disable theirs when Mesa is
detected.

Mesa detection depends on the vendor string. Some drivers never appear
outside of *nix contexts, so only check those in the *nix context.

gl_device: Internalize Intel DG detection
2023-08-05 15:19:16 -04:00
089e385944 service: olsc: Implement IOlscServiceForSystemService ITransferTaskListController interfaces for QLaunch 2023-08-05 11:47:51 -06:00
0d470b57ed service: pctl: Implement functions needed for QLaunch 2023-08-05 11:27:41 -06:00
755f45a522 Merge pull request #11213 from RngValue/master
📝 Update README.md
2023-08-05 12:58:45 -04:00
4533769f7f Merge pull request #11212 from Kelebek1/shader_stuff
Fix various misc pipeline/shader things
2023-08-05 12:58:39 -04:00
00d9a9c44e Merge pull request #11210 from german77/settings
service: set: Implement system settings for Qlaunch
2023-08-05 12:58:32 -04:00
35bdd5fff3 Merge pull request #11208 from german77/interface
service: am: Fix wrong interface ILibraryAppletSelfAccessor
2023-08-05 12:58:20 -04:00
7707768f80 service: set: Add more system settings and address comments 2023-08-04 17:20:40 -06:00
ae19eb1e10 Merge pull request #1 from RngValue/RngValue-patch-1
📝 Update README.md (A potential grammar error and a missing period)
2023-08-04 18:18:39 +02:00
a09507f271 📝 Update README.md 2023-08-04 17:58:49 +02:00
dfb7fc8293 Fix shader dumps with nvdisasm
skip fragment shaders when rasterizer is disabled
initialize env_ptrs
2023-08-03 15:30:27 +01:00
369fcadf08 Merge pull request #11209 from ameerj/subgroup_size_control
vulkan_device: Fix VK_EXT_subgroup_size_control detection
2023-08-03 10:15:12 -04:00
4bd4a95d84 service: set: Implement system settings for Qlaunch 2023-08-02 22:33:42 -06:00
cd80cbc420 vulkan_device: Fix subgroup_size_control detection on Vulkan 1.3 2023-08-02 20:45:03 -04:00
c7c44dc238 vulkan_device: Fix VK_EXT_subgroup_size_control detection 2023-08-02 19:25:14 -04:00
dd1cbd9c56 service: am: Fix wrong interface 2023-08-02 13:00:30 -06:00
096644c01c Merge pull request #11202 from abouvier/vulkan-config
vulkan: centralize config
2023-08-02 14:26:03 -04:00
fca7d975fd Merge pull request #10839 from lat9nq/pgc-plus
general: Reimplement per-game configurations
2023-08-02 14:25:52 -04:00
32b4d63a5b config(qt): Fix name of network category
Turns out the network interface is in the Services category. Can't wait
get rid of this whole config.

Addresses yuzu-emu/yuzu/issues/11205
2023-08-02 12:21:43 -04:00
09e265c116 config(qt): Use qt_config directly to read config
ReadSetting with the default is a convenience function reading
settings,  not for use in an internal environment. It tries to manage
the default value of a setting.
2023-08-02 12:20:19 -04:00
36aca262e3 Merge pull request #11204 from liamwhite/eds3-blend-amd
vulkan_device: disable EDS3 blending on all AMD drivers
2023-08-02 02:10:43 -03:00
d6d43e11a3 vulkan_device: disable EDS3 blending on all AMD drivers 2023-08-01 20:46:05 -04:00
9d6f8e88b2 vulkan: centralize config 2023-08-02 00:05:14 +02:00
7aa848080d shared_widget: Only save global settings as needed
Fixes a potential but not reproduced issue where the custom config
is being applied to the global config.
2023-07-30 12:26:55 -04:00
55c0b55d1d config(qt): Write the UiGeneral category 2023-07-30 12:09:32 -04:00
d90c622549 Merge branch 'pgc-plus' of github.com:lat9nq/yuzu into pgc-plus 2023-07-29 13:23:14 -04:00
05c8063ac1 config(qt): Fix generic read setting
Previously was not respecting whether the setting was default.
2023-07-29 13:23:06 -04:00
195403c87c (ui)settings: Add more runtime_modifiable settings 2023-07-25 23:14:13 -04:00
1bc0b673aa backend: Remove usage of explicit operator overload
Causes a crash on MSVC from a race condition on application quit.

Intended to address yuzu-emu/yuzu/issues/11137
2023-07-25 22:53:58 -04:00
397333b2d5 settings: Correct Linkage member impl location 2023-07-25 15:57:55 -04:00
b1716a9e14 settings: Set GPU as default ASTC decoder 2023-07-24 16:28:13 -04:00
ab2921121e shared_widget: Determine default request earlier
Fixes a bug where a restore button could be created for an unmanaged
widget.
2023-07-23 17:08:25 -04:00
f84e7b4656 settings_common: Document specializations 2023-07-23 16:21:08 -04:00
fc1bb93b01 shared_widget: Use QRegularExpression 2023-07-22 15:07:34 -04:00
fb7da1fa11 config: Read the Network category 2023-07-22 14:50:32 -04:00
85ed10f31f configure_audio/cpu: Sort settings
Was producing out of order settings as a result of the switch to vectors
2023-07-22 00:42:15 -04:00
33d118509a configure_dialog: Focus the button box on start
Without this, the Reset All Settings button would be selected by default
2023-07-21 23:56:01 -04:00
1d4f813c6a qt/configuration: Use deleteLater 2023-07-21 23:25:22 -04:00
17b9c1e171 common,qt-config: Remove usage of forward_list 2023-07-21 23:09:09 -04:00
2911988b85 settings_common: Use a vector in category linkage
Improve storage requirements.
2023-07-21 10:56:55 -04:00
ffb384463f settings: Remove sorting from log
Unecessary, and would run every time the settings are logged.
2023-07-21 10:56:55 -04:00
b54c3fba68 configure_system: Use lambda template to group settings 2023-07-21 10:56:55 -04:00
b55a763618 config-android: Update memory layout member name 2023-07-21 10:56:55 -04:00
8e91554e11 k_system_control: Always return some memory size 2023-07-21 10:56:55 -04:00
3211623192 common: Move global configuration state modifiers back to settings 2023-07-21 10:56:55 -04:00
b02e7eea78 settings_setting: Fix typo 2023-07-21 10:56:55 -04:00
1e093767a8 common,configure_system: Rename method to GetCategory
Fixes essentially a shadowing issue.
2023-07-21 10:56:55 -04:00
267f3c7905 settings: Cleanup
Addresses review feedback

Co-authored-by: Morph <39850852+Morph1984@users.noreply.github.com>
2023-07-21 10:56:55 -04:00
35872ad95b shared_translation: Update memory layout mode strings 2023-07-21 10:56:55 -04:00
127b3da0f1 core,common: Give memory layout setting an enum
Allows for 6GB and 8GB layouts to be selected.
2023-07-21 10:56:55 -04:00
ff6a5031d5 settings: Require time zone setting value for stirng 2023-07-21 10:56:55 -04:00
07e8477f5a shared_translation: Add missing time zones 2023-07-21 10:56:55 -04:00
ef6406a666 shared_translation: Add controller_applet_disabled 2023-07-21 10:56:55 -04:00
a14d2a6f83 shared_translation: Add barrier_feedback_loops 2023-07-21 10:56:55 -04:00
c1717b3f47 cmake: Reposition preprocessor switch comment
Co-authored-by: Morph <39850852+Morph1984@users.noreply.github.com>
2023-07-21 10:56:55 -04:00
ca8509d205 configuration: Use enum index 2023-07-21 10:56:55 -04:00
e7f01128f1 settings: Give indices to enums 2023-07-21 10:56:55 -04:00
ecc1feff64 cmake: Use standard preprocessor on MSVC 2023-07-21 10:56:55 -04:00
52cc7b438b settings_common: Remove unncessary enum spec 2023-07-21 10:56:55 -04:00
9186f08c3c shared_translation: Deobfuscate auto time zone 2023-07-21 10:56:55 -04:00
8497fb0a04 settings_enums: Remove casting
Not sure how I missed this earlier, but these vectors can be constructed
using the type of the enum.
2023-07-21 10:56:55 -04:00
54d58130a0 settings_setting: Silence shadowing warnings 2023-07-21 10:56:55 -04:00
926f3e3d3e settings,configuration: Add a default suffix 2023-07-21 10:56:55 -04:00
9de50d6194 configuration: Use paired settings 2023-07-21 10:56:55 -04:00
7f708e8d77 settings: Define paired settings
settings_common: Remove unused optional
2023-07-21 10:56:55 -04:00
d1de1c3bed shared_widget: Internalize component restoring 2023-07-21 10:56:55 -04:00
21723879e7 configuration: Use specialization of settings
Reduces some ugliness in frontend code.
2023-07-21 10:56:55 -04:00
b2438f1fb7 settings: Define specializations for settings
Suggests to a frontend how to represent each setting.
2023-07-21 10:56:55 -04:00
ad645c29a4 configuration: Use a builder to create widgets
This gets rid of some repeated code and sets us up to send more
information to the new widget.
2023-07-21 10:56:55 -04:00
62ffaa730f shared_translation: Fix context usage
Currently unused, but I don't want to start headaches when someone
decides to use it the first time.
2023-07-21 10:56:55 -04:00
8b28aa45b9 settings,translation: Fix time zone enum
Renames enum values to conform to naming convention.
2023-07-21 10:56:55 -04:00
8366736b67 settings,opengl,yuzu-qt: Fix AA, Filter maximums
The new enum macros don't support setting values directly.
For LastAA and LastFilter, this means we need a simpler approach to loop
around the toggle in the frontend...
2023-07-21 10:56:55 -04:00
7ffbffe170 settings_enums: More aggressively use macros
This lets us define an enum and all the textual representations
of its values in one swing. All for the price of some ugly macros.
2023-07-21 10:56:55 -04:00
02c48a80f6 config_shared: Remove storing the group from tab 2023-07-21 10:56:55 -04:00
fdbeb84168 settings,uisettings: Remove leading underscore 2023-07-21 10:56:55 -04:00
81a96bafe2 configuration: Move speed_limit to core 2023-07-21 10:56:55 -04:00
3a7705e774 settings: Move speed_limit to core 2023-07-21 10:56:55 -04:00
69bc8ea148 android-config: Update enum labels 2023-07-21 10:56:55 -04:00
3f0cc544cf common,yuzu-qt: Avoid explicit instantiation on old clang
Clang versions < 15 have compile issues with explicit instantiation.
Disable it for these versions.
2023-07-21 10:56:55 -04:00
c97cbd089b settings_setting: Fix MSVC error 2023-07-21 10:56:55 -04:00
246740f102 codespellrc: Ignore canonicalizations 2023-07-21 10:56:55 -04:00
89f89cf1df shared_widget: Correct spelling 2023-07-21 10:56:55 -04:00
ab795fe0e2 (android)config: Clang format 2023-07-21 10:56:55 -04:00
ee32b17782 common,yuzu-qt: GCC warning silences
Fixes -Wshadow, -Wdeprecated, and catch by copy rather than by ref.
2023-07-21 10:56:55 -04:00
916c6cd1a0 configure_graphics: Simplify UpdateAPILayout
Reduces branching/swictch cases for simplicity/code size
2023-07-21 10:56:54 -04:00
57a00e01d6 configure_graphcs: Fix setting shader/device in custom config 2023-07-21 10:56:54 -04:00
a7ee9d999f configuration: Use shorter constructor as needed
Reduces some confusion hopefully, since some parameters specified were not
specific to the setting in question.
2023-07-21 10:56:54 -04:00
6935332cba shared_widget: Some documentation, add shorter constructor
The shorter constructor enables us to specify some options without needing to
specify the default values of multiplier which wasn't always appropriate and
could be confusing.
2023-07-21 10:56:54 -04:00
3240d199a2 config: Remove unused functions 2023-07-21 10:56:54 -04:00
a0883526d6 settings: Delete cpu_accuracy_first_time
Almost a 2 year old migration setting now
2023-07-21 10:56:54 -04:00
7c52bb2772 shared_widget: Improve logging, use Setting::Ranged 2023-07-21 10:56:54 -04:00
27e53990ed settings: Document BasicSetting, add Ranged 2023-07-21 10:56:54 -04:00
b4f2ad3ff5 settings: Move IsConfiguringGlobal to settings_common 2023-07-21 10:56:54 -04:00
3b0650b70d configuration/shared: Clean up includes [IWYU] 2023-07-21 10:56:54 -04:00
512fb3abff configure_graphics: Fix vulkan_device bug 2023-07-21 10:56:54 -04:00
11e7e1b8ce settings: Move some simple data to BasicSetting
Reduces the need for the compiler to duplicate this code, by about
100KB executable size.
2023-07-21 10:56:54 -04:00
4903f40efe settings_setting: Fix errors
ToString didn't have a constexpr if statement where needed.
Canonicalize missed an else, causing unreachable code error on MSVC.
2023-07-21 10:56:54 -04:00
04d4b6ab80 (ui,)settings: Use explicit instantiation
Reduces compile times a tad on clang.
2023-07-21 10:56:54 -04:00
02265f19d9 settings: Remove redundant false literals 2023-07-21 10:56:54 -04:00
7515c502c5 shared_widget: Avoid calling QWidgetPrivate::setVisible
This particular setVisible function is unnecessary.
It also has horrible runtime performance, so much that it consumed maybe
80% of the time used to create a widget.
2023-07-21 10:56:54 -04:00
79024bb955 FIXME configuration: Avoid unnecessary allocations
ConfigurationShared::Widget needs to be created with a builder. This
would avoid some duplicated code.
2023-07-21 10:56:54 -04:00
c5f8b909ec shared_widget: Add SPDX header 2023-07-21 10:56:54 -04:00
0193add060 general: Add typeinfo where needed
Using typeid without including typeinfo first produces an ill-formed program.
2023-07-21 10:56:54 -04:00
2fba913d0b settings_enums: Add const type where needed 2023-07-21 10:56:54 -04:00
fe6e765b2d shared_widget: Use actionTriggered for user input signals
Clicking the slider without directly interacting with the slider handle would
change the value, but not trigger the restore button.
2023-07-21 10:56:54 -04:00
47d870b11f shared_translation: Populate combobox enums with macro 2023-07-21 10:56:54 -04:00
b86171d2b5 settings: yuzu is not capitalized why is it capitalized stop no bad 2023-07-21 10:56:54 -04:00
81e9cf0934 configuration: Document odd widget cases
Explain why we need to do things differently at times, to serve as a
reference.
2023-07-21 10:56:54 -04:00
163f229d26 settings: Reorder
Groups graphics audio and system settings together in a way that
reflects the frontend. This also just conceptually groups them more
nicely than they were.
2023-07-21 10:56:54 -04:00
681ebcf4a5 shared_translation: Add translation for use video framrate 2023-07-21 10:56:54 -04:00
78b2709373 settings: Report all contained settings values
Also adds a couple characters that denotes the state of the setting.
M for modified, or not default.
C for custom, in context of per-game settings.
2023-07-21 10:56:54 -04:00
8c17a945f7 settings_enums: Cannonicalize settings names
Gives every option of the enums a string literal via a macro.
2023-07-21 10:56:54 -04:00
d146dd9d12 settings,general: Rename non-confirming enums 2023-07-21 10:56:54 -04:00
9e3c94bb3d configuration: Use IDs to sort holds 2023-07-21 10:56:07 -04:00
f7948b7b64 settings,general: Rename/reorder setting ids 2023-07-21 10:56:07 -04:00
25cea2ef27 shared_widget: Fix includes 2023-07-21 10:56:07 -04:00
9a2a92673c shared_widget: Complete refactoring
Reduces code bloat a good bit by moving code specific to each sub widget
to their own functions.
2023-07-21 10:56:07 -04:00
d7dd023409 shared_widget: Refactor again
Starting with combobox

Putting code specific to the sub-widget in their own function.
2023-07-21 10:56:07 -04:00
d373cc3d3f android-config: Adapt settings rework 2023-07-21 10:56:07 -04:00
e6d65bf61c c_per_game: Inform when settings might not be configurable 2023-07-21 10:56:07 -04:00
cd1d8adc49 shared_translation: Fix pragma once 2023-07-21 10:56:07 -04:00
09f61656e3 shared_translation: Add translation for AstcRecompression 2023-07-21 10:56:07 -04:00
81860b4317 configure_system: Hide locale warn at start 2023-07-21 10:56:07 -04:00
b570b719de shared_widget: Force min width of 100 for restore button
Dark theme mandates a 100px minimum width for QAbstractButton, even
though this is not desired here.
2023-07-21 10:56:07 -04:00
3d932416e3 configuration: Workaround for Windows Qt bug
Odd issue happens that dragging the cpu or system tabs in custom configs
would cause the window to take up the entire verticle space of the
screen.
2023-07-21 10:56:07 -04:00
7734127f9e shared_translation: Add missing tooltips 2023-07-21 10:56:07 -04:00
3281ea935f settings: Make volume runtime-configurable 2023-07-21 10:56:07 -04:00
217fa04080 configuration: Clean up includes a bit 2023-07-21 10:56:07 -04:00
3337250746 configuration_shared: Remove old custom config setup functions 2023-07-21 10:56:07 -04:00
daa31121ee configure_cpu: Generate UI 2023-07-21 10:56:07 -04:00
c5a3642cb6 configuration: Use a mapping of setting value to name
Makes comboboxes always correspond to the value of the setting they're
modifying.
2023-07-21 10:56:07 -04:00
86ed82cdde settings, shared_widget: typo fixes 2023-07-21 10:56:07 -04:00
432f68ad29 configure_audio: Implement ui generation
Needs a considerable amount of management specific to some of
the comoboboxes due to the audio engine configuration.

general: Partial audio config implmentation

configure_audio: Implement ui generation

Needs a considerable amount of management specific to some of
the comoboboxes due to the audio engine configuration.

general: Partial audio config implmentation

settings: Make audio settings as enums
2023-07-21 10:56:07 -04:00
88d3de4e85 settings: Split enums to new file 2023-07-21 10:56:07 -04:00
f055f2dcf4 shared_widget: Use a better icon
This one looks more relevant on Windows.
2023-07-21 10:56:07 -04:00
4ff8255e4a shared_widget: Refactor helpers
Makes checkbox creation an option as opposed to a label.
2023-07-21 10:56:07 -04:00
4c4bc134a9 settings, uisettings: Initialize linkage counter 2023-07-21 10:56:07 -04:00
8e15146026 configure_system: Implement with for loop 2023-07-21 10:56:07 -04:00
56960bf9f8 per_game: Remove general tab
It's empty.
2023-07-21 10:56:07 -04:00
b11a2a206f shared_widget: Internalize extra setting configuration 2023-07-21 10:56:07 -04:00
cdb5dea269 settings: Move runtime and save to parameters
These don't need to be whole new types.
2023-07-21 10:56:07 -04:00
df2bd251fa graphics: Set speed limit to spinbox 2023-07-21 10:56:07 -04:00
97674bc888 shared_widget: Support checkbox + spinbox 2023-07-21 10:56:07 -04:00
def00e8c55 configure_debug: Reorganize 2023-07-21 10:56:07 -04:00
23f874ae60 configure_graphics: Reimplement bg_color
To specialized a setting to be worth adding to the shared_widget imo,
so add it roughly like before.
2023-07-21 10:56:07 -04:00
c1748b229a shared_widget: Make button creation static 2023-07-21 10:56:07 -04:00
8c03ae793e configure_general: Hide reset button in custom configs 2023-07-21 10:56:07 -04:00
e2de48f14b configure_general: Sort data 2023-07-21 10:56:07 -04:00
827082c5ac configure_general: Generate UI using containers
This leaves per-game config's General tab empty?
2023-07-21 10:56:07 -04:00
c530532de7 shared_translation: Add UI widget translations 2023-07-21 10:56:07 -04:00
d3d9c3568e shared_widget: Fix header 2023-07-21 10:56:07 -04:00
464aad52cd settings: Add UiGeneral class 2023-07-21 10:56:07 -04:00
ea4afbfc54 config: Don't merge the maps
Me shooting myself in the foot 3 days in advance.
2023-07-21 10:56:07 -04:00
640e7db60e configure_graphics: Remove redundant log 2023-07-21 10:56:07 -04:00
f66d617107 configuration: Move CreateWidget to a class
We were passing so many objects between the function and the caller that
it needed to be redesigned.
2023-07-21 10:56:07 -04:00
d35577d3ed configuration: Implement slider 2023-07-21 10:56:07 -04:00
39a1ffbb91 configuration: Use buttons instead of highlights
Only for updated configs at the moment
2023-07-21 10:56:07 -04:00
d72ff01726 shared_translations: Re flow strings 2023-07-21 10:56:07 -04:00
9a844bbf0c configure_graphics: More complete reimplementation 2023-07-21 10:56:07 -04:00
3a7a5edcea settings: Define base renderer runtime modifiable settings 2023-07-21 10:56:07 -04:00
05c26411a3 configuration_shared: Fix blank state hiding check box 2023-07-21 10:56:07 -04:00
a4de202cbd settings: Add anisotropy mode enum 2023-07-21 10:56:07 -04:00
cfb63c68db shared_translation: Finish using int ids 2023-07-21 10:56:07 -04:00
bafd569b47 settings,uisettings: Add IDs to settings 2023-07-21 10:56:07 -04:00
f8435d676f configure_graphics: Partial runtime implementation 2023-07-21 10:56:07 -04:00
75d7e40113 settings: Recategorize a bit
Will help with generating config UI later.
2023-07-21 10:56:07 -04:00
4a825268d6 shared_translation: Add the rest of the settings 2023-07-21 10:56:07 -04:00
4f545e3024 shared_translation: Add copyright and license 2023-07-21 10:56:07 -04:00
a007ac6b9c configure_graphics_advance: Generate UI at runtime
We can iterate through the AdvancedGraphics settings and generate the UI
during runtime. This doesn't help runtime efficiency, but it helps a ton
in reducing the amount of work a developer needs in order to add a new
setting.
2023-07-21 10:56:07 -04:00
b11b4be7cb configure_per_game: Rename group to tab_group 2023-07-21 10:56:07 -04:00
d3b94d64d4 configuration: Add base class to tabs
Tabs that largely configure SwitchableSetting's are now Tabs and grouped
together.
2023-07-21 10:56:07 -04:00
e5b981e1e4 configuration_shared: Create Tab base class 2023-07-21 10:56:07 -04:00
60773194a0 settings: Add a registry of settings
LoadString: Sanitize input

settings: Handle empty string, remove redundant category

settings: Rename Input to Controls, FS to DataStorage

settings: Fix Controls groups information

settings: Move use_docked_mode to System (again)

settings: Document

settings: Add type identification function

settings: Move registry into values

settings: Move global_reset_registry into values

settings: Separate AdvGraphics from Renderer

settings: More document

squash

settings: Use linkage object

uisettings: Move registry into settings

Probably wont build without

uisettings: Use settings linkage object

config: Load settings with a map

Uses the new all_settings vector to load settings.

qt-config: Rename settings category

qt config: Rename to read category

config: Read/write contols category with for_each

This is extremely limited due to the complexity of the Controls group,
but this handles the the settings that use the interface.

qt-config: Use new settings registry

qt-config: Read/write advgrphics

qt-config: Use settings linkage object

yuzu_cmd: Load setting off of vector

cmd-config: Finish settings rename

config: Read controls settings group with for_each

cmd/config: Move registry into values

cmd: Read adv graphics

cmd-config: Use settings linkage object
2023-07-21 10:56:07 -04:00
e7543e8b84 uisettings: Fix typings 2023-07-21 10:56:07 -04:00
4133165607 settings,core,config_sys: Remove optional type from custom_rtc, rng_seed
core: Fix MSVC errors
2023-07-21 10:56:07 -04:00
5ccfaf0517 settings: Pool SetGlobal functions 2023-07-21 10:56:07 -04:00
5cffa34288 settings,video_core: Consolidate ASTC decoding options
Just puts them all neatly into one place.
2023-07-21 10:56:07 -04:00
180 changed files with 7183 additions and 6088 deletions

View File

@ -3,4 +3,4 @@
[codespell]
skip = ./.git,./build,./dist,./Doxyfile,./externals,./LICENSES,./src/android/app/src/main/res
ignore-words-list = aci,allright,ba,deques,froms,hda,inout,lod,masia,nam,nax,nd,optin,pullrequests,pullrequest,te,transfered,unstall,uscaled,zink
ignore-words-list = aci,allright,ba,canonicalizations,deques,froms,hda,inout,lod,masia,nam,nax,nd,optin,pullrequests,pullrequest,te,transfered,unstall,uscaled,zink

View File

@ -1,3 +1,11 @@
| Pull Request | Commit | Title | Author | Merged? |
|----|----|----|----|----|
End of merge log. You can find the original README.md below the break.
-----
<!--
SPDX-FileCopyrightText: 2018 yuzu Emulator Project
SPDX-License-Identifier: GPL-2.0-or-later
@ -40,7 +48,7 @@ It is written in C++ with portability in mind, and we actively maintain builds f
The emulator is capable of running most commercial games at full speed, provided you meet the [necessary hardware requirements](https://yuzu-emu.org/help/quickstart/#hardware-requirements).
For a full list of games yuzu support, please visit our [Compatibility page](https://yuzu-emu.org/game/)
For a full list of games yuzu supports, please visit our [Compatibility page](https://yuzu-emu.org/game/).
Check out our [website](https://yuzu-emu.org/) for the latest news on exciting features, monthly progress reports, and more!

View File

@ -35,6 +35,7 @@ if (MSVC)
# /volatile:iso - Use strict standards-compliant volatile semantics.
# /Zc:externConstexpr - Allow extern constexpr variables to have external linkage, like the standard mandates
# /Zc:inline - Let codegen omit inline functions in object files
# /Zc:preprocessor - Enable standards-conforming preprocessor
# /Zc:throwingNew - Let codegen assume `operator new` (without std::nothrow) will never return null
# /GT - Supports fiber safety for data allocated using static thread-local storage
add_compile_options(
@ -48,6 +49,7 @@ if (MSVC)
/volatile:iso
/Zc:externConstexpr
/Zc:inline
/Zc:preprocessor
/Zc:throwingNew
/GT

View File

@ -49,6 +49,7 @@ class LicenseAdapter(private val activity: AppCompatActivity, var licenses: List
val context = YuzuApplication.appContext
binding.textSettingName.text = context.getString(license.titleId)
binding.textSettingDescription.text = context.getString(license.descriptionId)
binding.textSettingValue.visibility = View.GONE
}
}
}

View File

@ -5,13 +5,19 @@ package org.yuzu.yuzu_emu.adapters
import android.text.Html
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.res.ResourcesCompat
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.button.MaterialButton
import org.yuzu.yuzu_emu.databinding.PageSetupBinding
import org.yuzu.yuzu_emu.model.HomeViewModel
import org.yuzu.yuzu_emu.model.SetupCallback
import org.yuzu.yuzu_emu.model.SetupPage
import org.yuzu.yuzu_emu.model.StepState
import org.yuzu.yuzu_emu.utils.ViewUtils
class SetupAdapter(val activity: AppCompatActivity, val pages: List<SetupPage>) :
RecyclerView.Adapter<SetupAdapter.SetupPageViewHolder>() {
@ -26,7 +32,7 @@ class SetupAdapter(val activity: AppCompatActivity, val pages: List<SetupPage>)
holder.bind(pages[position])
inner class SetupPageViewHolder(val binding: PageSetupBinding) :
RecyclerView.ViewHolder(binding.root) {
RecyclerView.ViewHolder(binding.root), SetupCallback {
lateinit var page: SetupPage
init {
@ -35,6 +41,12 @@ class SetupAdapter(val activity: AppCompatActivity, val pages: List<SetupPage>)
fun bind(page: SetupPage) {
this.page = page
if (page.stepCompleted.invoke() == StepState.COMPLETE) {
binding.buttonAction.visibility = View.INVISIBLE
binding.textConfirmation.visibility = View.VISIBLE
}
binding.icon.setImageDrawable(
ResourcesCompat.getDrawable(
activity.resources,
@ -62,9 +74,15 @@ class SetupAdapter(val activity: AppCompatActivity, val pages: List<SetupPage>)
MaterialButton.ICON_GRAVITY_END
}
setOnClickListener {
page.buttonAction.invoke()
page.buttonAction.invoke(this@SetupPageViewHolder)
}
}
}
override fun onStepCompleted() {
ViewUtils.hideView(binding.buttonAction, 200)
ViewUtils.showView(binding.textConfirmation, 200)
ViewModelProvider(activity)[HomeViewModel::class.java].setShouldPageForward(true)
}
}
}

View File

@ -207,8 +207,11 @@ class SettingsAdapter(
val sliderBinding = DialogSliderBinding.inflate(inflater)
textSliderValue = sliderBinding.textValue
textSliderValue!!.text = sliderProgress.toString()
sliderBinding.textUnits.text = item.units
textSliderValue!!.text = String.format(
context.getString(R.string.value_with_units),
sliderProgress.toString(),
item.units
)
sliderBinding.slider.apply {
valueFrom = item.min.toFloat()
@ -216,7 +219,11 @@ class SettingsAdapter(
value = sliderProgress.toFloat()
addOnChangeListener { _: Slider, value: Float, _: Boolean ->
sliderProgress = value.toInt()
textSliderValue!!.text = sliderProgress.toString()
textSliderValue!!.text = String.format(
context.getString(R.string.value_with_units),
sliderProgress.toString(),
item.units
)
}
}
@ -225,10 +232,6 @@ class SettingsAdapter(
.setView(sliderBinding.root)
.setPositiveButton(android.R.string.ok, this)
.setNegativeButton(android.R.string.cancel, defaultCancelListener)
.setNeutralButton(R.string.slider_default) { dialog: DialogInterface, which: Int ->
sliderBinding.slider.value = item.defaultValue!!.toFloat()
onClick(dialog, which)
}
.show()
}

View File

@ -25,12 +25,17 @@ class DateTimeViewHolder(val binding: ListItemSettingBinding, adapter: SettingsA
binding.textSettingDescription.setText(item.descriptionId)
binding.textSettingDescription.visibility = View.VISIBLE
} else {
val epochTime = setting.value.toLong()
val instant = Instant.ofEpochMilli(epochTime * 1000)
val zonedTime = ZonedDateTime.ofInstant(instant, ZoneId.of("UTC"))
val dateFormatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM)
binding.textSettingDescription.text = dateFormatter.format(zonedTime)
binding.textSettingDescription.visibility = View.GONE
}
binding.textSettingValue.visibility = View.VISIBLE
val epochTime = setting.value.toLong()
val instant = Instant.ofEpochMilli(epochTime * 1000)
val zonedTime = ZonedDateTime.ofInstant(instant, ZoneId.of("UTC"))
val dateFormatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM)
binding.textSettingValue.text = dateFormatter.format(zonedTime)
setStyle(setting.isEditable, binding)
}
override fun onClick(clicked: View) {

View File

@ -23,6 +23,9 @@ class RunnableViewHolder(val binding: ListItemSettingBinding, adapter: SettingsA
} else {
binding.textSettingDescription.visibility = View.GONE
}
binding.textSettingValue.visibility = View.GONE
setStyle(setting.isEditable, binding)
}
override fun onClick(clicked: View) {

View File

@ -5,6 +5,8 @@ package org.yuzu.yuzu_emu.features.settings.ui.viewholder
import android.view.View
import androidx.recyclerview.widget.RecyclerView
import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding
import org.yuzu.yuzu_emu.databinding.ListItemSettingSwitchBinding
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
@ -33,4 +35,18 @@ abstract class SettingViewHolder(itemView: View, protected val adapter: Settings
abstract override fun onClick(clicked: View)
abstract override fun onLongClick(clicked: View): Boolean
fun setStyle(isEditable: Boolean, binding: ListItemSettingBinding) {
val opacity = if (isEditable) 1.0f else 0.5f
binding.textSettingName.alpha = opacity
binding.textSettingDescription.alpha = opacity
binding.textSettingValue.alpha = opacity
}
fun setStyle(isEditable: Boolean, binding: ListItemSettingSwitchBinding) {
binding.switchWidget.isEnabled = isEditable
val opacity = if (isEditable) 1.0f else 0.5f
binding.textSettingName.alpha = opacity
binding.textSettingDescription.alpha = opacity
}
}

View File

@ -17,28 +17,33 @@ class SingleChoiceViewHolder(val binding: ListItemSettingBinding, adapter: Setti
override fun bind(item: SettingsItem) {
setting = item
binding.textSettingName.setText(item.nameId)
binding.textSettingDescription.visibility = View.VISIBLE
if (item.descriptionId != 0) {
binding.textSettingDescription.setText(item.descriptionId)
} else if (item is SingleChoiceSetting) {
val resMgr = binding.textSettingDescription.context.resources
binding.textSettingDescription.visibility = View.VISIBLE
} else {
binding.textSettingDescription.visibility = View.GONE
}
binding.textSettingValue.visibility = View.VISIBLE
if (item is SingleChoiceSetting) {
val resMgr = binding.textSettingValue.context.resources
val values = resMgr.getIntArray(item.valuesId)
for (i in values.indices) {
if (values[i] == item.selectedValue) {
binding.textSettingDescription.text = resMgr.getStringArray(item.choicesId)[i]
return
binding.textSettingValue.text = resMgr.getStringArray(item.choicesId)[i]
break
}
}
} else if (item is StringSingleChoiceSetting) {
for (i in item.values!!.indices) {
if (item.values[i] == item.selectedValue) {
binding.textSettingDescription.text = item.choices[i]
return
binding.textSettingValue.text = item.choices[i]
break
}
}
} else {
binding.textSettingDescription.visibility = View.GONE
}
setStyle(setting.isEditable, binding)
}
override fun onClick(clicked: View) {

View File

@ -4,6 +4,7 @@
package org.yuzu.yuzu_emu.features.settings.ui.viewholder
import android.view.View
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
import org.yuzu.yuzu_emu.features.settings.model.view.SliderSetting
@ -22,6 +23,14 @@ class SliderViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAda
} else {
binding.textSettingDescription.visibility = View.GONE
}
binding.textSettingValue.visibility = View.VISIBLE
binding.textSettingValue.text = String.format(
binding.textSettingValue.context.getString(R.string.value_with_units),
setting.selectedValue,
setting.units
)
setStyle(setting.isEditable, binding)
}
override fun onClick(clicked: View) {

View File

@ -22,6 +22,7 @@ class SubmenuViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAd
} else {
binding.textSettingDescription.visibility = View.GONE
}
binding.textSettingValue.visibility = View.GONE
}
override fun onClick(clicked: View) {

View File

@ -25,12 +25,12 @@ class SwitchSettingViewHolder(val binding: ListItemSettingSwitchBinding, adapter
binding.textSettingDescription.text = ""
binding.textSettingDescription.visibility = View.GONE
}
binding.switchWidget.isChecked = setting.isChecked
binding.switchWidget.setOnCheckedChangeListener { _: CompoundButton, _: Boolean ->
adapter.onBooleanClick(item, bindingAdapterPosition, binding.switchWidget.isChecked)
}
binding.switchWidget.isChecked = setting.isChecked
binding.switchWidget.isEnabled = setting.isEditable
setStyle(setting.isEditable, binding)
}
override fun onClick(clicked: View) {

View File

@ -19,6 +19,7 @@ import androidx.core.content.ContextCompat
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.isVisible
import androidx.core.view.updatePadding
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.navigation.findNavController
@ -32,10 +33,13 @@ import org.yuzu.yuzu_emu.adapters.SetupAdapter
import org.yuzu.yuzu_emu.databinding.FragmentSetupBinding
import org.yuzu.yuzu_emu.features.settings.model.Settings
import org.yuzu.yuzu_emu.model.HomeViewModel
import org.yuzu.yuzu_emu.model.SetupCallback
import org.yuzu.yuzu_emu.model.SetupPage
import org.yuzu.yuzu_emu.model.StepState
import org.yuzu.yuzu_emu.ui.main.MainActivity
import org.yuzu.yuzu_emu.utils.DirectoryInitialization
import org.yuzu.yuzu_emu.utils.GameHelper
import org.yuzu.yuzu_emu.utils.ViewUtils
class SetupFragment : Fragment() {
private var _binding: FragmentSetupBinding? = null
@ -112,14 +116,22 @@ class SetupFragment : Fragment() {
0,
false,
R.string.give_permission,
{ permissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS) },
{
notificationCallback = it
permissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS)
},
true,
R.string.notification_warning,
R.string.notification_warning_description,
0,
{
NotificationManagerCompat.from(requireContext())
if (NotificationManagerCompat.from(requireContext())
.areNotificationsEnabled()
) {
StepState.COMPLETE
} else {
StepState.INCOMPLETE
}
}
)
)
@ -133,12 +145,22 @@ class SetupFragment : Fragment() {
R.drawable.ic_add,
true,
R.string.select_keys,
{ mainActivity.getProdKey.launch(arrayOf("*/*")) },
{
keyCallback = it
getProdKey.launch(arrayOf("*/*"))
},
true,
R.string.install_prod_keys_warning,
R.string.install_prod_keys_warning_description,
R.string.install_prod_keys_warning_help,
{ File(DirectoryInitialization.userDirectory + "/keys/prod.keys").exists() }
{
val file = File(DirectoryInitialization.userDirectory + "/keys/prod.keys")
if (file.exists()) {
StepState.COMPLETE
} else {
StepState.INCOMPLETE
}
}
)
)
add(
@ -150,9 +172,8 @@ class SetupFragment : Fragment() {
true,
R.string.add_games,
{
mainActivity.getGamesDirectory.launch(
Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).data
)
gamesDirCallback = it
getGamesDirectory.launch(Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).data)
},
true,
R.string.add_games_warning,
@ -163,7 +184,11 @@ class SetupFragment : Fragment() {
PreferenceManager.getDefaultSharedPreferences(
YuzuApplication.appContext
)
preferences.getString(GameHelper.KEY_GAME_PATH, "")!!.isNotEmpty()
if (preferences.getString(GameHelper.KEY_GAME_PATH, "")!!.isNotEmpty()) {
StepState.COMPLETE
} else {
StepState.INCOMPLETE
}
}
)
)
@ -181,6 +206,13 @@ class SetupFragment : Fragment() {
)
}
homeViewModel.shouldPageForward.observe(viewLifecycleOwner) {
if (it) {
pageForward()
homeViewModel.setShouldPageForward(false)
}
}
binding.viewPager2.apply {
adapter = SetupAdapter(requireActivity() as AppCompatActivity, pages)
offscreenPageLimit = 2
@ -194,15 +226,15 @@ class SetupFragment : Fragment() {
super.onPageSelected(position)
if (position == 1 && previousPosition == 0) {
showView(binding.buttonNext)
showView(binding.buttonBack)
ViewUtils.showView(binding.buttonNext)
ViewUtils.showView(binding.buttonBack)
} else if (position == 0 && previousPosition == 1) {
hideView(binding.buttonBack)
hideView(binding.buttonNext)
ViewUtils.hideView(binding.buttonBack)
ViewUtils.hideView(binding.buttonNext)
} else if (position == pages.size - 1 && previousPosition == pages.size - 2) {
hideView(binding.buttonNext)
ViewUtils.hideView(binding.buttonNext)
} else if (position == pages.size - 2 && previousPosition == pages.size - 1) {
showView(binding.buttonNext)
ViewUtils.showView(binding.buttonNext)
}
previousPosition = position
@ -215,7 +247,8 @@ class SetupFragment : Fragment() {
// Checks if the user has completed the task on the current page
if (currentPage.hasWarning) {
if (currentPage.taskCompleted.invoke()) {
val stepState = currentPage.stepCompleted.invoke()
if (stepState != StepState.INCOMPLETE) {
pageForward()
return@setOnClickListener
}
@ -264,9 +297,15 @@ class SetupFragment : Fragment() {
_binding = null
}
private lateinit var notificationCallback: SetupCallback
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
private val permissionLauncher =
registerForActivityResult(ActivityResultContracts.RequestPermission()) {
if (it) {
notificationCallback.onStepCompleted()
}
if (!it &&
!shouldShowRequestPermissionRationale(Manifest.permission.POST_NOTIFICATIONS)
) {
@ -277,6 +316,27 @@ class SetupFragment : Fragment() {
}
}
private lateinit var keyCallback: SetupCallback
val getProdKey =
registerForActivityResult(ActivityResultContracts.OpenDocument()) { result ->
if (result != null) {
if (mainActivity.processKey(result)) {
keyCallback.onStepCompleted()
}
}
}
private lateinit var gamesDirCallback: SetupCallback
val getGamesDirectory =
registerForActivityResult(ActivityResultContracts.OpenDocumentTree()) { result ->
if (result != null) {
mainActivity.processGamesDir(result)
gamesDirCallback.onStepCompleted()
}
}
private fun finishSetup() {
PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext).edit()
.putBoolean(Settings.PREF_FIRST_APP_LAUNCH, false)
@ -284,33 +344,6 @@ class SetupFragment : Fragment() {
mainActivity.finishSetup(binding.root.findNavController())
}
private fun showView(view: View) {
view.apply {
alpha = 0f
visibility = View.VISIBLE
isClickable = true
}.animate().apply {
duration = 300
alpha(1f)
}.start()
}
private fun hideView(view: View) {
if (view.visibility == View.INVISIBLE) {
return
}
view.apply {
alpha = 1f
isClickable = false
}.animate().apply {
duration = 300
alpha(0f)
}.withEndAction {
view.visibility = View.INVISIBLE
}
}
fun pageForward() {
binding.viewPager2.currentItem = binding.viewPager2.currentItem + 1
}
@ -326,15 +359,29 @@ class SetupFragment : Fragment() {
private fun setInsets() =
ViewCompat.setOnApplyWindowInsetsListener(
binding.root
) { view: View, windowInsets: WindowInsetsCompat ->
) { _: View, windowInsets: WindowInsetsCompat ->
val barInsets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
val cutoutInsets = windowInsets.getInsets(WindowInsetsCompat.Type.displayCutout())
view.setPadding(
barInsets.left + cutoutInsets.left,
barInsets.top + cutoutInsets.top,
barInsets.right + cutoutInsets.right,
barInsets.bottom + cutoutInsets.bottom
)
val leftPadding = barInsets.left + cutoutInsets.left
val topPadding = barInsets.top + cutoutInsets.top
val rightPadding = barInsets.right + cutoutInsets.right
val bottomPadding = barInsets.bottom + cutoutInsets.bottom
if (resources.getBoolean(R.bool.small_layout)) {
binding.viewPager2
.updatePadding(left = leftPadding, top = topPadding, right = rightPadding)
binding.constraintButtons
.updatePadding(left = leftPadding, right = rightPadding, bottom = bottomPadding)
} else {
binding.viewPager2.updatePadding(top = topPadding, bottom = bottomPadding)
binding.constraintButtons
.updatePadding(
left = leftPadding,
right = rightPadding,
bottom = bottomPadding
)
}
windowInsets
}
}

View File

@ -14,6 +14,9 @@ class HomeViewModel : ViewModel() {
private val _statusBarShadeVisible = MutableLiveData(true)
val statusBarShadeVisible: LiveData<Boolean> get() = _statusBarShadeVisible
private val _shouldPageForward = MutableLiveData(false)
val shouldPageForward: LiveData<Boolean> get() = _shouldPageForward
var navigatedToSetup = false
init {
@ -33,4 +36,8 @@ class HomeViewModel : ViewModel() {
}
_statusBarShadeVisible.value = visible
}
fun setShouldPageForward(pageForward: Boolean) {
_shouldPageForward.value = pageForward
}
}

View File

@ -10,10 +10,20 @@ data class SetupPage(
val buttonIconId: Int,
val leftAlignedIcon: Boolean,
val buttonTextId: Int,
val buttonAction: () -> Unit,
val buttonAction: (callback: SetupCallback) -> Unit,
val hasWarning: Boolean,
val warningTitleId: Int = 0,
val warningDescriptionId: Int = 0,
val warningHelpLinkId: Int = 0,
val taskCompleted: () -> Boolean = { true }
val stepCompleted: () -> StepState = { StepState.UNDEFINED }
)
interface SetupCallback {
fun onStepCompleted()
}
enum class StepState {
COMPLETE,
INCOMPLETE,
UNDEFINED
}

View File

@ -266,74 +266,81 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
val getGamesDirectory =
registerForActivityResult(ActivityResultContracts.OpenDocumentTree()) { result ->
if (result == null) {
return@registerForActivityResult
if (result != null) {
processGamesDir(result)
}
contentResolver.takePersistableUriPermission(
result,
Intent.FLAG_GRANT_READ_URI_PERMISSION
)
// When a new directory is picked, we currently will reset the existing games
// database. This effectively means that only one game directory is supported.
PreferenceManager.getDefaultSharedPreferences(applicationContext).edit()
.putString(GameHelper.KEY_GAME_PATH, result.toString())
.apply()
Toast.makeText(
applicationContext,
R.string.games_dir_selected,
Toast.LENGTH_LONG
).show()
gamesViewModel.reloadGames(true)
}
fun processGamesDir(result: Uri) {
contentResolver.takePersistableUriPermission(
result,
Intent.FLAG_GRANT_READ_URI_PERMISSION
)
// When a new directory is picked, we currently will reset the existing games
// database. This effectively means that only one game directory is supported.
PreferenceManager.getDefaultSharedPreferences(applicationContext).edit()
.putString(GameHelper.KEY_GAME_PATH, result.toString())
.apply()
Toast.makeText(
applicationContext,
R.string.games_dir_selected,
Toast.LENGTH_LONG
).show()
gamesViewModel.reloadGames(true)
}
val getProdKey =
registerForActivityResult(ActivityResultContracts.OpenDocument()) { result ->
if (result == null) {
return@registerForActivityResult
}
if (FileUtil.getExtension(result) != "keys") {
MessageDialogFragment.newInstance(
R.string.reading_keys_failure,
R.string.install_prod_keys_failure_extension_description
).show(supportFragmentManager, MessageDialogFragment.TAG)
return@registerForActivityResult
}
contentResolver.takePersistableUriPermission(
result,
Intent.FLAG_GRANT_READ_URI_PERMISSION
)
val dstPath = DirectoryInitialization.userDirectory + "/keys/"
if (FileUtil.copyUriToInternalStorage(
applicationContext,
result,
dstPath,
"prod.keys"
)
) {
if (NativeLibrary.reloadKeys()) {
Toast.makeText(
applicationContext,
R.string.install_keys_success,
Toast.LENGTH_SHORT
).show()
gamesViewModel.reloadGames(true)
} else {
MessageDialogFragment.newInstance(
R.string.invalid_keys_error,
R.string.install_keys_failure_description,
R.string.dumping_keys_quickstart_link
).show(supportFragmentManager, MessageDialogFragment.TAG)
}
if (result != null) {
processKey(result)
}
}
fun processKey(result: Uri): Boolean {
if (FileUtil.getExtension(result) != "keys") {
MessageDialogFragment.newInstance(
R.string.reading_keys_failure,
R.string.install_prod_keys_failure_extension_description
).show(supportFragmentManager, MessageDialogFragment.TAG)
return false
}
contentResolver.takePersistableUriPermission(
result,
Intent.FLAG_GRANT_READ_URI_PERMISSION
)
val dstPath = DirectoryInitialization.userDirectory + "/keys/"
if (FileUtil.copyUriToInternalStorage(
applicationContext,
result,
dstPath,
"prod.keys"
)
) {
if (NativeLibrary.reloadKeys()) {
Toast.makeText(
applicationContext,
R.string.install_keys_success,
Toast.LENGTH_SHORT
).show()
gamesViewModel.reloadGames(true)
return true
} else {
MessageDialogFragment.newInstance(
R.string.invalid_keys_error,
R.string.install_keys_failure_description,
R.string.dumping_keys_quickstart_link
).show(supportFragmentManager, MessageDialogFragment.TAG)
return false
}
}
return false
}
val getFirmware =
registerForActivityResult(ActivityResultContracts.OpenDocument()) { result ->
if (result == null) {

View File

@ -0,0 +1,35 @@
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
package org.yuzu.yuzu_emu.utils
import android.view.View
object ViewUtils {
fun showView(view: View, length: Long = 300) {
view.apply {
alpha = 0f
visibility = View.VISIBLE
isClickable = true
}.animate().apply {
duration = length
alpha(1f)
}.start()
}
fun hideView(view: View, length: Long = 300) {
if (view.visibility == View.INVISIBLE) {
return
}
view.apply {
alpha = 1f
isClickable = false
}.animate().apply {
duration = length
alpha(0f)
}.withEndAction {
view.visibility = View.INVISIBLE
}.start()
}
}

View File

@ -150,15 +150,17 @@ void Config::ReadValues() {
if (rng_seed_enabled) {
Settings::values.rng_seed.SetValue(config->GetInteger("System", "rng_seed", 0));
} else {
Settings::values.rng_seed.SetValue(std::nullopt);
Settings::values.rng_seed.SetValue(0);
}
Settings::values.rng_seed_enabled.SetValue(rng_seed_enabled);
const auto custom_rtc_enabled = config->GetBoolean("System", "custom_rtc_enabled", false);
if (custom_rtc_enabled) {
Settings::values.custom_rtc = config->GetInteger("System", "custom_rtc", 0);
} else {
Settings::values.custom_rtc = std::nullopt;
Settings::values.custom_rtc = 0;
}
Settings::values.custom_rtc_enabled = custom_rtc_enabled;
ReadSetting("System", Settings::values.language_index);
ReadSetting("System", Settings::values.region_index);
@ -167,7 +169,7 @@ void Config::ReadValues() {
// Core
ReadSetting("Core", Settings::values.use_multi_core);
ReadSetting("Core", Settings::values.use_unsafe_extended_memory_layout);
ReadSetting("Core", Settings::values.memory_layout_mode);
// Cpu
ReadSetting("Cpu", Settings::values.cpu_accuracy);
@ -222,14 +224,17 @@ void Config::ReadValues() {
ReadSetting("Renderer", Settings::values.bg_blue);
// Use GPU accuracy normal by default on Android
Settings::values.gpu_accuracy = static_cast<Settings::GPUAccuracy>(config->GetInteger(
"Renderer", "gpu_accuracy", static_cast<u32>(Settings::GPUAccuracy::Normal)));
Settings::values.gpu_accuracy = static_cast<Settings::GpuAccuracy>(config->GetInteger(
"Renderer", "gpu_accuracy", static_cast<u32>(Settings::GpuAccuracy::Normal)));
// Use GPU default anisotropic filtering on Android
Settings::values.max_anisotropy = config->GetInteger("Renderer", "max_anisotropy", 1);
Settings::values.max_anisotropy =
static_cast<Settings::AnisotropyMode>(config->GetInteger("Renderer", "max_anisotropy", 1));
// Disable ASTC compute by default on Android
Settings::values.accelerate_astc = config->GetBoolean("Renderer", "accelerate_astc", false);
Settings::values.accelerate_astc.SetValue(
config->GetBoolean("Renderer", "accelerate_astc", false) ? Settings::AstcDecodeMode::Gpu
: Settings::AstcDecodeMode::Cpu);
// Enable asynchronous presentation by default on Android
Settings::values.async_presentation =

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/setup_root"
@ -8,33 +8,39 @@
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/viewPager2"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentTop="true"
android:layout_alignParentBottom="true"
android:clipToPadding="false" />
<com.google.android.material.button.MaterialButton
style="@style/Widget.Material3.Button.TextButton"
android:id="@+id/button_next"
android:layout_width="wrap_content"
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/constraint_buttons"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:text="@string/next"
android:visibility="invisible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
android:layout_alignParentBottom="true"
android:layout_margin="8dp">
<com.google.android.material.button.MaterialButton
android:id="@+id/button_back"
style="@style/Widget.Material3.Button.TextButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:text="@string/back"
android:visibility="invisible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<com.google.android.material.button.MaterialButton
android:id="@+id/button_next"
style="@style/Widget.Material3.Button.TextButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/next"
android:visibility="invisible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<com.google.android.material.button.MaterialButton
android:id="@+id/button_back"
style="@style/Widget.Material3.Button.TextButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/back"
android:visibility="invisible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</RelativeLayout>

View File

@ -21,45 +21,76 @@
</LinearLayout>
<LinearLayout
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="vertical"
android:gravity="center">
android:layout_weight="1">
<com.google.android.material.textview.MaterialTextView
style="@style/TextAppearance.Material3.DisplaySmall"
android:id="@+id/text_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAlignment="center"
style="@style/TextAppearance.Material3.DisplaySmall"
android:layout_width="0dp"
android:layout_height="0dp"
android:gravity="center"
android:textColor="?attr/colorOnSurface"
android:textStyle="bold"
app:layout_constraintBottom_toTopOf="@+id/text_description"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_weight="2"
tools:text="@string/welcome" />
<com.google.android.material.textview.MaterialTextView
style="@style/TextAppearance.Material3.TitleLarge"
android:id="@+id/text_description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:paddingHorizontal="32dp"
android:textAlignment="center"
android:textSize="26sp"
app:lineHeight="40sp"
style="@style/TextAppearance.Material3.TitleLarge"
android:layout_width="0dp"
android:layout_height="0dp"
android:gravity="center"
android:textSize="20sp"
android:paddingHorizontal="16dp"
app:layout_constraintBottom_toTopOf="@+id/button_action"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/text_title"
app:layout_constraintVertical_weight="2"
app:lineHeight="30sp"
tools:text="@string/welcome_description" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/text_confirmation"
style="@style/TextAppearance.Material3.TitleLarge"
android:layout_width="0dp"
android:layout_height="0dp"
android:paddingHorizontal="16dp"
android:paddingBottom="20dp"
android:gravity="center"
android:textSize="30sp"
android:visibility="invisible"
android:text="@string/step_complete"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/text_description"
app:layout_constraintVertical_weight="1"
app:lineHeight="30sp" />
<com.google.android.material.button.MaterialButton
android:id="@+id/button_action"
android:layout_width="wrap_content"
android:layout_height="56dp"
android:layout_marginTop="32dp"
android:layout_marginTop="16dp"
android:layout_marginBottom="48dp"
android:textSize="20sp"
app:iconSize="24sp"
app:iconGravity="end"
app:iconSize="24sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/text_description"
tools:text="Get started" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout>

View File

@ -5,23 +5,16 @@
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
<com.google.android.material.textview.MaterialTextView
android:id="@+id/text_value"
style="@style/TextAppearance.Material3.LabelMedium"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="@dimen/spacing_medlarge"
android:layout_marginTop="@dimen/spacing_medlarge"
tools:text="75" />
<TextView
android:id="@+id/text_units"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignTop="@+id/text_value"
android:layout_toEndOf="@+id/text_value"
tools:text="%" />
tools:text="75%" />
<com.google.android.material.slider.Slider
android:id="@+id/slider"

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/setup_root"
@ -8,35 +8,39 @@
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/viewPager2"
android:layout_width="0dp"
android:layout_height="0dp"
android:clipToPadding="false"
android:layout_marginBottom="16dp"
app:layout_constraintBottom_toTopOf="@+id/button_next"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.button.MaterialButton
style="@style/Widget.Material3.Button.TextButton"
android:id="@+id/button_next"
android:layout_width="wrap_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="12dp"
android:text="@string/next"
android:visibility="invisible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
android:layout_above="@+id/constraint_buttons"
android:layout_alignParentTop="true"
android:clipToPadding="false" />
<com.google.android.material.button.MaterialButton
style="@style/Widget.Material3.Button.TextButton"
android:id="@+id/button_back"
android:layout_width="wrap_content"
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/constraint_buttons"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="12dp"
android:text="@string/back"
android:visibility="invisible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent" />
android:layout_margin="8dp"
android:layout_alignParentBottom="true">
</androidx.constraintlayout.widget.ConstraintLayout>
<com.google.android.material.button.MaterialButton
android:id="@+id/button_next"
style="@style/Widget.Material3.Button.TextButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/next"
android:visibility="invisible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<com.google.android.material.button.MaterialButton
android:id="@+id/button_back"
style="@style/Widget.Material3.Button.TextButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/back"
android:visibility="invisible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</RelativeLayout>

View File

@ -1,9 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="?android:attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"
@ -11,31 +12,40 @@
android:minHeight="72dp"
android:padding="@dimen/spacing_large">
<com.google.android.material.textview.MaterialTextView
style="@style/TextAppearance.Material3.HeadlineMedium"
android:id="@+id/text_setting_name"
android:layout_width="0dp"
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:textSize="16sp"
android:textAlignment="viewStart"
app:lineHeight="28dp"
tools:text="Setting Name" />
android:orientation="vertical">
<TextView
style="@style/TextAppearance.Material3.BodySmall"
android:id="@+id/text_setting_description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentStart="true"
android:layout_alignStart="@+id/text_setting_name"
android:layout_below="@+id/text_setting_name"
android:layout_marginTop="@dimen/spacing_small"
android:visibility="visible"
android:textAlignment="viewStart"
tools:text="@string/app_disclaimer" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/text_setting_name"
style="@style/TextAppearance.Material3.HeadlineMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAlignment="viewStart"
android:textSize="16sp"
app:lineHeight="22dp"
tools:text="Setting Name" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/text_setting_description"
style="@style/TextAppearance.Material3.BodySmall"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/spacing_small"
android:textAlignment="viewStart"
tools:text="@string/app_disclaimer" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/text_setting_value"
style="@style/TextAppearance.Material3.LabelMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/spacing_small"
android:textAlignment="viewStart"
android:textStyle="bold"
tools:text="1x" />
</LinearLayout>
</RelativeLayout>

View File

@ -21,11 +21,12 @@
app:layout_constraintVertical_chainStyle="spread"
app:layout_constraintWidth_max="220dp"
app:layout_constraintWidth_min="110dp"
app:layout_constraintVertical_weight="3" />
app:layout_constraintVertical_weight="3"
tools:src="@drawable/ic_notification" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/text_title"
style="@style/TextAppearance.Material3.DisplayMedium"
style="@style/TextAppearance.Material3.DisplaySmall"
android:layout_width="0dp"
android:layout_height="0dp"
android:textAlignment="center"
@ -44,23 +45,42 @@
android:layout_width="0dp"
android:layout_height="0dp"
android:textAlignment="center"
android:textSize="26sp"
android:textSize="20sp"
android:paddingHorizontal="16dp"
app:layout_constraintBottom_toTopOf="@+id/button_action"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/text_title"
app:layout_constraintVertical_weight="2"
app:lineHeight="40sp"
app:lineHeight="30sp"
tools:text="@string/welcome_description" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/text_confirmation"
style="@style/TextAppearance.Material3.TitleLarge"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:paddingHorizontal="16dp"
android:paddingTop="24dp"
android:textAlignment="center"
android:textSize="30sp"
android:visibility="invisible"
android:text="@string/step_complete"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/text_description"
app:layout_constraintVertical_weight="1"
app:lineHeight="30sp" />
<com.google.android.material.button.MaterialButton
android:id="@+id/button_action"
android:layout_width="wrap_content"
android:layout_height="56dp"
android:textSize="20sp"
android:layout_marginTop="16dp"
android:layout_marginBottom="48dp"
android:textSize="20sp"
app:iconGravity="end"
app:iconSize="24sp"
app:layout_constraintBottom_toBottomOf="parent"

View File

@ -29,6 +29,7 @@
<string name="back">Back</string>
<string name="add_games">Add Games</string>
<string name="add_games_description">Select your games folder</string>
<string name="step_complete">Complete!</string>
<!-- Home strings -->
<string name="home_games">Games</string>
@ -149,6 +150,7 @@
<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="cpu_accuracy">CPU accuracy</string>
<string name="value_with_units">%1$s%2$s</string>
<!-- System settings strings -->
<string name="use_docked_mode">Docked Mode</string>

View File

@ -15,6 +15,7 @@
#endif
#include "audio_core/sink/null_sink.h"
#include "common/logging/log.h"
#include "common/settings_enums.h"
namespace AudioCore::Sink {
namespace {
@ -24,7 +25,7 @@ struct SinkDetails {
using LatencyFn = u32 (*)();
/// Name for this sink.
std::string_view id;
Settings::AudioEngine id;
/// A method to call to construct an instance of this type of sink.
FactoryFn factory;
/// A method to call to list available devices.
@ -37,7 +38,7 @@ struct SinkDetails {
constexpr SinkDetails sink_details[] = {
#ifdef HAVE_CUBEB
SinkDetails{
"cubeb",
Settings::AudioEngine::Cubeb,
[](std::string_view device_id) -> std::unique_ptr<Sink> {
return std::make_unique<CubebSink>(device_id);
},
@ -47,7 +48,7 @@ constexpr SinkDetails sink_details[] = {
#endif
#ifdef HAVE_SDL2
SinkDetails{
"sdl2",
Settings::AudioEngine::Sdl2,
[](std::string_view device_id) -> std::unique_ptr<Sink> {
return std::make_unique<SDLSink>(device_id);
},
@ -55,46 +56,47 @@ constexpr SinkDetails sink_details[] = {
&GetSDLLatency,
},
#endif
SinkDetails{"null",
SinkDetails{Settings::AudioEngine::Null,
[](std::string_view device_id) -> std::unique_ptr<Sink> {
return std::make_unique<NullSink>(device_id);
},
[](bool capture) { return std::vector<std::string>{"null"}; }, []() { return 0u; }},
};
const SinkDetails& GetOutputSinkDetails(std::string_view sink_id) {
const auto find_backend{[](std::string_view id) {
const SinkDetails& GetOutputSinkDetails(Settings::AudioEngine sink_id) {
const auto find_backend{[](Settings::AudioEngine id) {
return std::find_if(std::begin(sink_details), std::end(sink_details),
[&id](const auto& sink_detail) { return sink_detail.id == id; });
}};
auto iter = find_backend(sink_id);
if (sink_id == "auto") {
if (sink_id == Settings::AudioEngine::Auto) {
// Auto-select a backend. Prefer CubeB, but it may report a large minimum latency which
// causes audio issues, in that case go with SDL.
#if defined(HAVE_CUBEB) && defined(HAVE_SDL2)
iter = find_backend("cubeb");
iter = find_backend(Settings::AudioEngine::Cubeb);
if (iter->latency() > TargetSampleCount * 3) {
iter = find_backend("sdl2");
iter = find_backend(Settings::AudioEngine::Sdl2);
}
#else
iter = std::begin(sink_details);
#endif
LOG_INFO(Service_Audio, "Auto-selecting the {} backend", iter->id);
LOG_INFO(Service_Audio, "Auto-selecting the {} backend",
Settings::CanonicalizeEnum(iter->id));
}
if (iter == std::end(sink_details)) {
LOG_ERROR(Audio, "Invalid sink_id {}", sink_id);
iter = find_backend("null");
LOG_ERROR(Audio, "Invalid sink_id {}", Settings::CanonicalizeEnum(sink_id));
iter = find_backend(Settings::AudioEngine::Null);
}
return *iter;
}
} // Anonymous namespace
std::vector<std::string_view> GetSinkIDs() {
std::vector<std::string_view> sink_ids(std::size(sink_details));
std::vector<Settings::AudioEngine> GetSinkIDs() {
std::vector<Settings::AudioEngine> sink_ids(std::size(sink_details));
std::transform(std::begin(sink_details), std::end(sink_details), std::begin(sink_ids),
[](const auto& sink) { return sink.id; });
@ -102,11 +104,11 @@ std::vector<std::string_view> GetSinkIDs() {
return sink_ids;
}
std::vector<std::string> GetDeviceListForSink(std::string_view sink_id, bool capture) {
std::vector<std::string> GetDeviceListForSink(Settings::AudioEngine sink_id, bool capture) {
return GetOutputSinkDetails(sink_id).list_devices(capture);
}
std::unique_ptr<Sink> CreateSinkFromID(std::string_view sink_id, std::string_view device_id) {
std::unique_ptr<Sink> CreateSinkFromID(Settings::AudioEngine sink_id, std::string_view device_id) {
return GetOutputSinkDetails(sink_id).factory(device_id);
}

View File

@ -3,9 +3,11 @@
#pragma once
#include <memory>
#include <string>
#include <string_view>
#include <vector>
#include "common/settings_enums.h"
namespace AudioCore {
class AudioManager;
@ -19,7 +21,7 @@ class Sink;
*
* @return Vector of available sink names.
*/
std::vector<std::string_view> GetSinkIDs();
std::vector<Settings::AudioEngine> GetSinkIDs();
/**
* Gets the list of devices for a particular sink identified by the given ID.
@ -28,7 +30,7 @@ std::vector<std::string_view> GetSinkIDs();
* @param capture - Get capture (input) devices, or output devices?
* @return Vector of device names.
*/
std::vector<std::string> GetDeviceListForSink(std::string_view sink_id, bool capture);
std::vector<std::string> GetDeviceListForSink(Settings::AudioEngine sink_id, bool capture);
/**
* Creates an audio sink identified by the given device ID.
@ -37,7 +39,7 @@ std::vector<std::string> GetDeviceListForSink(std::string_view sink_id, bool cap
* @param device_id - Name of the device to create.
* @return Pointer to the created sink.
*/
std::unique_ptr<Sink> CreateSinkFromID(std::string_view sink_id, std::string_view device_id);
std::unique_ptr<Sink> CreateSinkFromID(Settings::AudioEngine sink_id, std::string_view device_id);
} // namespace Sink
} // namespace AudioCore

View File

@ -110,8 +110,12 @@ add_library(common STATIC
scratch_buffer.h
settings.cpp
settings.h
settings_common.cpp
settings_common.h
settings_enums.h
settings_input.cpp
settings_input.h
settings_setting.h
socket_types.h
spin_lock.cpp
spin_lock.h
@ -193,9 +197,16 @@ if (MSVC)
/we4254 # 'operator': conversion from 'type1:field_bits' to 'type2:field_bits', possible loss of data
/we4800 # Implicit conversion from 'type' to bool. Possible information loss
)
else()
endif()
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
target_compile_options(common PRIVATE
$<$<CXX_COMPILER_ID:Clang>:-fsized-deallocation>
-fsized-deallocation
-Werror=unreachable-code-aggressive
)
target_compile_definitions(common PRIVATE
# Clang 14 and earlier have errors when explicitly instantiating Settings::Setting
$<$<VERSION_LESS:$<CXX_COMPILER_VERSION>,15>:CANNOT_EXPLICITLY_INSTANTIATE>
)
endif()

View File

@ -108,7 +108,7 @@ public:
using namespace Common::Literals;
// Prevent logs from exceeding a set maximum size in the event that log entries are spammed.
const auto write_limit = Settings::values.extended_logging ? 1_GiB : 100_MiB;
const auto write_limit = Settings::values.extended_logging.GetValue() ? 1_GiB : 100_MiB;
const bool write_limit_exceeded = bytes_written > write_limit;
if (entry.log_level >= Level::Error || write_limit_exceeded) {
if (write_limit_exceeded) {

View File

@ -7,9 +7,16 @@
#include <exception>
#include <stdexcept>
#endif
#include <compare>
#include <cstddef>
#include <filesystem>
#include <functional>
#include <string_view>
#include <type_traits>
#include <fmt/core.h>
#include "common/assert.h"
#include "common/fs/fs_util.h"
#include "common/fs/path_util.h"
#include "common/logging/log.h"
#include "common/settings.h"
@ -17,11 +24,50 @@
namespace Settings {
Values values;
static bool configuring_global = true;
// Clang 14 and earlier have errors when explicitly instantiating these classes
#ifndef CANNOT_EXPLICITLY_INSTANTIATE
#define SETTING(TYPE, RANGED) template class Setting<TYPE, RANGED>
#define SWITCHABLE(TYPE, RANGED) template class SwitchableSetting<TYPE, RANGED>
std::string GetTimeZoneString() {
const auto time_zone_index = static_cast<std::size_t>(values.time_zone_index.GetValue());
SETTING(AudioEngine, false);
SETTING(bool, false);
SETTING(int, false);
SETTING(std::string, false);
SETTING(u16, false);
SWITCHABLE(AnisotropyMode, true);
SWITCHABLE(AntiAliasing, false);
SWITCHABLE(AspectRatio, true);
SWITCHABLE(AstcDecodeMode, true);
SWITCHABLE(AstcRecompression, true);
SWITCHABLE(AudioMode, true);
SWITCHABLE(CpuAccuracy, true);
SWITCHABLE(FullscreenMode, true);
SWITCHABLE(GpuAccuracy, true);
SWITCHABLE(Language, true);
SWITCHABLE(NvdecEmulation, false);
SWITCHABLE(Region, true);
SWITCHABLE(RendererBackend, true);
SWITCHABLE(ScalingFilter, false);
SWITCHABLE(ShaderBackend, true);
SWITCHABLE(TimeZone, true);
SETTING(VSyncMode, true);
SWITCHABLE(bool, false);
SWITCHABLE(int, false);
SWITCHABLE(int, true);
SWITCHABLE(s64, false);
SWITCHABLE(u16, true);
SWITCHABLE(u32, false);
SWITCHABLE(u8, false);
SWITCHABLE(u8, true);
#undef SETTING
#undef SWITCHABLE
#endif
Values values;
std::string GetTimeZoneString(TimeZone time_zone) {
const auto time_zone_index = static_cast<std::size_t>(time_zone);
ASSERT(time_zone_index < Common::TimeZone::GetTimeZoneStrings().size());
std::string location_name;
@ -61,73 +107,35 @@ void LogSettings() {
};
LOG_INFO(Config, "yuzu Configuration:");
log_setting("Controls_UseDockedMode", values.use_docked_mode.GetValue());
log_setting("System_RngSeed", values.rng_seed.GetValue().value_or(0));
log_setting("System_DeviceName", values.device_name.GetValue());
log_setting("System_CurrentUser", values.current_user.GetValue());
log_setting("System_LanguageIndex", values.language_index.GetValue());
log_setting("System_RegionIndex", values.region_index.GetValue());
log_setting("System_TimeZoneIndex", values.time_zone_index.GetValue());
log_setting("System_UnsafeMemoryLayout", values.use_unsafe_extended_memory_layout.GetValue());
log_setting("Core_UseMultiCore", values.use_multi_core.GetValue());
log_setting("CPU_Accuracy", values.cpu_accuracy.GetValue());
log_setting("Renderer_UseResolutionScaling", values.resolution_setup.GetValue());
log_setting("Renderer_ScalingFilter", values.scaling_filter.GetValue());
log_setting("Renderer_FSRSlider", values.fsr_sharpening_slider.GetValue());
log_setting("Renderer_AntiAliasing", values.anti_aliasing.GetValue());
log_setting("Renderer_UseSpeedLimit", values.use_speed_limit.GetValue());
log_setting("Renderer_SpeedLimit", values.speed_limit.GetValue());
log_setting("Renderer_UseDiskShaderCache", values.use_disk_shader_cache.GetValue());
log_setting("Renderer_GPUAccuracyLevel", values.gpu_accuracy.GetValue());
log_setting("Renderer_UseAsynchronousGpuEmulation",
values.use_asynchronous_gpu_emulation.GetValue());
log_setting("Renderer_NvdecEmulation", values.nvdec_emulation.GetValue());
log_setting("Renderer_AccelerateASTC", values.accelerate_astc.GetValue());
log_setting("Renderer_AsyncASTC", values.async_astc.GetValue());
log_setting("Renderer_AstcRecompression", values.astc_recompression.GetValue());
log_setting("Renderer_UseVsync", values.vsync_mode.GetValue());
log_setting("Renderer_UseReactiveFlushing", values.use_reactive_flushing.GetValue());
log_setting("Renderer_ShaderBackend", values.shader_backend.GetValue());
log_setting("Renderer_UseAsynchronousShaders", values.use_asynchronous_shaders.GetValue());
log_setting("Renderer_AnisotropicFilteringLevel", values.max_anisotropy.GetValue());
log_setting("Audio_OutputEngine", values.sink_id.GetValue());
log_setting("Audio_OutputDevice", values.audio_output_device_id.GetValue());
log_setting("Audio_InputDevice", values.audio_input_device_id.GetValue());
log_setting("DataStorage_UseVirtualSd", values.use_virtual_sd.GetValue());
for (auto& [category, settings] : values.linkage.by_category) {
for (const auto& setting : settings) {
if (setting->Id() == values.yuzu_token.Id()) {
// Hide the token secret, for security reasons.
continue;
}
const auto name = fmt::format(
"{:c}{:c} {}.{}", setting->ToString() == setting->DefaultToString() ? '-' : 'M',
setting->UsingGlobal() ? '-' : 'C', TranslateCategory(category),
setting->GetLabel());
log_setting(name, setting->Canonicalize());
}
}
log_path("DataStorage_CacheDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::CacheDir));
log_path("DataStorage_ConfigDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::ConfigDir));
log_path("DataStorage_LoadDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::LoadDir));
log_path("DataStorage_NANDDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir));
log_path("DataStorage_SDMCDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::SDMCDir));
log_setting("Debugging_ProgramArgs", values.program_args.GetValue());
log_setting("Debugging_GDBStub", values.use_gdbstub.GetValue());
log_setting("Input_EnableMotion", values.motion_enabled.GetValue());
log_setting("Input_EnableVibration", values.vibration_enabled.GetValue());
log_setting("Input_EnableTouch", values.touchscreen.enabled);
log_setting("Input_EnableMouse", values.mouse_enabled.GetValue());
log_setting("Input_EnableKeyboard", values.keyboard_enabled.GetValue());
log_setting("Input_EnableRingController", values.enable_ring_controller.GetValue());
log_setting("Input_EnableIrSensor", values.enable_ir_sensor.GetValue());
log_setting("Input_EnableCustomJoycon", values.enable_joycon_driver.GetValue());
log_setting("Input_EnableCustomProController", values.enable_procon_driver.GetValue());
log_setting("Input_EnableRawInput", values.enable_raw_input.GetValue());
}
bool IsConfiguringGlobal() {
return configuring_global;
}
void SetConfiguringGlobal(bool is_global) {
configuring_global = is_global;
}
bool IsGPULevelExtreme() {
return values.gpu_accuracy.GetValue() == GPUAccuracy::Extreme;
return values.gpu_accuracy.GetValue() == GpuAccuracy::Extreme;
}
bool IsGPULevelHigh() {
return values.gpu_accuracy.GetValue() == GPUAccuracy::Extreme ||
values.gpu_accuracy.GetValue() == GPUAccuracy::High;
return values.gpu_accuracy.GetValue() == GpuAccuracy::Extreme ||
values.gpu_accuracy.GetValue() == GpuAccuracy::High;
}
bool IsFastmemEnabled() {
@ -144,6 +152,61 @@ float Volume() {
return values.volume.GetValue() / static_cast<f32>(values.volume.GetDefault());
}
const char* TranslateCategory(Category category) {
switch (category) {
case Category::Audio:
return "Audio";
case Category::Core:
return "Core";
case Category::Cpu:
case Category::CpuDebug:
case Category::CpuUnsafe:
return "Cpu";
case Category::Renderer:
case Category::RendererAdvanced:
case Category::RendererDebug:
return "Renderer";
case Category::System:
case Category::SystemAudio:
return "System";
case Category::DataStorage:
return "Data Storage";
case Category::Debugging:
case Category::DebuggingGraphics:
return "Debugging";
case Category::Miscellaneous:
return "Miscellaneous";
case Category::Network:
return "Network";
case Category::WebService:
return "WebService";
case Category::AddOns:
return "DisabledAddOns";
case Category::Controls:
return "Controls";
case Category::Ui:
case Category::UiGeneral:
return "UI";
case Category::UiLayout:
return "UiLayout";
case Category::UiGameList:
return "UiGameList";
case Category::Screenshots:
return "Screenshots";
case Category::Shortcuts:
return "Shortcuts";
case Category::Multiplayer:
return "Multiplayer";
case Category::Services:
return "Services";
case Category::Paths:
return "Paths";
case Category::MaxEnum:
break;
}
return "Miscellaneous";
}
void UpdateRescalingInfo() {
const auto setup = values.resolution_setup.GetValue();
auto& info = values.resolution_info;
@ -212,66 +275,19 @@ void RestoreGlobalState(bool is_powered_on) {
return;
}
// Audio
values.volume.SetGlobal(true);
for (const auto& reset : values.linkage.restore_functions) {
reset();
}
}
// Core
values.use_multi_core.SetGlobal(true);
values.use_unsafe_extended_memory_layout.SetGlobal(true);
static bool configuring_global = true;
// CPU
values.cpu_accuracy.SetGlobal(true);
values.cpuopt_unsafe_unfuse_fma.SetGlobal(true);
values.cpuopt_unsafe_reduce_fp_error.SetGlobal(true);
values.cpuopt_unsafe_ignore_standard_fpcr.SetGlobal(true);
values.cpuopt_unsafe_inaccurate_nan.SetGlobal(true);
values.cpuopt_unsafe_fastmem_check.SetGlobal(true);
values.cpuopt_unsafe_ignore_global_monitor.SetGlobal(true);
bool IsConfiguringGlobal() {
return configuring_global;
}
// Renderer
values.fsr_sharpening_slider.SetGlobal(true);
values.renderer_backend.SetGlobal(true);
values.async_presentation.SetGlobal(true);
values.renderer_force_max_clock.SetGlobal(true);
values.vulkan_device.SetGlobal(true);
values.fullscreen_mode.SetGlobal(true);
values.aspect_ratio.SetGlobal(true);
values.resolution_setup.SetGlobal(true);
values.scaling_filter.SetGlobal(true);
values.anti_aliasing.SetGlobal(true);
values.max_anisotropy.SetGlobal(true);
values.use_speed_limit.SetGlobal(true);
values.speed_limit.SetGlobal(true);
values.use_disk_shader_cache.SetGlobal(true);
values.gpu_accuracy.SetGlobal(true);
values.use_asynchronous_gpu_emulation.SetGlobal(true);
values.nvdec_emulation.SetGlobal(true);
values.accelerate_astc.SetGlobal(true);
values.async_astc.SetGlobal(true);
values.astc_recompression.SetGlobal(true);
values.use_reactive_flushing.SetGlobal(true);
values.shader_backend.SetGlobal(true);
values.use_asynchronous_shaders.SetGlobal(true);
values.use_fast_gpu_time.SetGlobal(true);
values.use_vulkan_driver_pipeline_cache.SetGlobal(true);
values.bg_red.SetGlobal(true);
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);
values.region_index.SetGlobal(true);
values.time_zone_index.SetGlobal(true);
values.rng_seed.SetGlobal(true);
values.sound_index.SetGlobal(true);
// Controls
values.players.SetGlobal(true);
values.use_docked_mode.SetGlobal(true);
values.vibration_enabled.SetGlobal(true);
values.motion_enabled.SetGlobal(true);
void SetConfiguringGlobal(bool is_global) {
configuring_global = is_global;
}
} // namespace Settings

View File

@ -6,95 +6,21 @@
#include <algorithm>
#include <array>
#include <map>
#include <optional>
#include <memory>
#include <stdexcept>
#include <string>
#include <utility>
#include <vector>
#include "common/common_types.h"
#include "common/settings_common.h"
#include "common/settings_enums.h"
#include "common/settings_input.h"
#include "common/settings_setting.h"
namespace Settings {
enum class VSyncMode : u32 {
Immediate = 0,
Mailbox = 1,
FIFO = 2,
FIFORelaxed = 3,
};
enum class RendererBackend : u32 {
OpenGL = 0,
Vulkan = 1,
Null = 2,
};
enum class ShaderBackend : u32 {
GLSL = 0,
GLASM = 1,
SPIRV = 2,
};
enum class GPUAccuracy : u32 {
Normal = 0,
High = 1,
Extreme = 2,
};
enum class CPUAccuracy : u32 {
Auto = 0,
Accurate = 1,
Unsafe = 2,
Paranoid = 3,
};
enum class FullscreenMode : u32 {
Borderless = 0,
Exclusive = 1,
};
enum class NvdecEmulation : u32 {
Off = 0,
CPU = 1,
GPU = 2,
};
enum class ResolutionSetup : u32 {
Res1_2X = 0,
Res3_4X = 1,
Res1X = 2,
Res3_2X = 3,
Res2X = 4,
Res3X = 5,
Res4X = 6,
Res5X = 7,
Res6X = 8,
Res7X = 9,
Res8X = 10,
};
enum class ScalingFilter : u32 {
NearestNeighbor = 0,
Bilinear = 1,
Bicubic = 2,
Gaussian = 3,
ScaleForce = 4,
Fsr = 5,
LastFilter = Fsr,
};
enum class AntiAliasing : u32 {
None = 0,
Fxaa = 1,
Smaa = 2,
LastAA = Smaa,
};
enum class AstcRecompression : u32 {
Uncompressed = 0,
Bc1 = 1,
Bc3 = 2,
};
const char* TranslateCategory(Settings::Category category);
struct ResolutionScalingInfo {
u32 up_scale{1};
@ -119,239 +45,47 @@ struct ResolutionScalingInfo {
}
};
/** The Setting class is a simple resource manager. It defines a label and default value alongside
* the actual value of the setting for simpler and less-error prone use with frontend
* configurations. Specifying a default value and label is required. A minimum and maximum range can
* be specified for sanitization.
*/
template <typename Type, bool ranged = false>
class Setting {
protected:
Setting() = default;
#ifndef CANNOT_EXPLICITLY_INSTANTIATE
// Instantiate the classes elsewhere (settings.cpp) to reduce compiler/linker work
#define SETTING(TYPE, RANGED) extern template class Setting<TYPE, RANGED>
#define SWITCHABLE(TYPE, RANGED) extern template class SwitchableSetting<TYPE, RANGED>
/**
* Only sets the setting to the given initializer, leaving the other members to their default
* initializers.
*
* @param global_val Initial value of the setting
*/
explicit Setting(const Type& val) : value{val} {}
SETTING(AudioEngine, false);
SETTING(bool, false);
SETTING(int, false);
SETTING(s32, false);
SETTING(std::string, false);
SETTING(std::string, false);
SETTING(u16, false);
SWITCHABLE(AnisotropyMode, true);
SWITCHABLE(AntiAliasing, false);
SWITCHABLE(AspectRatio, true);
SWITCHABLE(AstcDecodeMode, true);
SWITCHABLE(AstcRecompression, true);
SWITCHABLE(AudioMode, true);
SWITCHABLE(CpuAccuracy, true);
SWITCHABLE(FullscreenMode, true);
SWITCHABLE(GpuAccuracy, true);
SWITCHABLE(Language, true);
SWITCHABLE(NvdecEmulation, false);
SWITCHABLE(Region, true);
SWITCHABLE(RendererBackend, true);
SWITCHABLE(ScalingFilter, false);
SWITCHABLE(ShaderBackend, true);
SWITCHABLE(TimeZone, true);
SETTING(VSyncMode, true);
SWITCHABLE(bool, false);
SWITCHABLE(int, false);
SWITCHABLE(int, true);
SWITCHABLE(s64, false);
SWITCHABLE(u16, true);
SWITCHABLE(u32, false);
SWITCHABLE(u8, false);
SWITCHABLE(u8, true);
public:
/**
* Sets a default value, label, and setting value.
*
* @param default_val Initial value of the setting, and default value of the setting
* @param name Label for the setting
*/
explicit Setting(const Type& default_val, const std::string& name)
requires(!ranged)
: value{default_val}, default_value{default_val}, label{name} {}
virtual ~Setting() = default;
/**
* Sets a default value, minimum value, maximum value, and label.
*
* @param default_val Initial value of the setting, and default value of the setting
* @param min_val Sets the minimum allowed value of the setting
* @param max_val Sets the maximum allowed value of the setting
* @param name Label for the setting
*/
explicit Setting(const Type& default_val, const Type& min_val, const Type& max_val,
const std::string& name)
requires(ranged)
: value{default_val},
default_value{default_val}, maximum{max_val}, minimum{min_val}, label{name} {}
/**
* Returns a reference to the setting's value.
*
* @returns A reference to the setting
*/
[[nodiscard]] virtual const Type& GetValue() const {
return value;
}
/**
* Sets the setting to the given value.
*
* @param val The desired value
*/
virtual void SetValue(const Type& val) {
Type temp{ranged ? std::clamp(val, minimum, maximum) : val};
std::swap(value, temp);
}
/**
* Returns the value that this setting was created with.
*
* @returns A reference to the default value
*/
[[nodiscard]] const Type& GetDefault() const {
return default_value;
}
/**
* Returns the label this setting was created with.
*
* @returns A reference to the label
*/
[[nodiscard]] const std::string& GetLabel() const {
return label;
}
/**
* Assigns a value to the setting.
*
* @param val The desired setting value
*
* @returns A reference to the setting
*/
virtual const Type& operator=(const Type& val) {
Type temp{ranged ? std::clamp(val, minimum, maximum) : val};
std::swap(value, temp);
return value;
}
/**
* Returns a reference to the setting.
*
* @returns A reference to the setting
*/
explicit virtual operator const Type&() const {
return value;
}
protected:
Type value{}; ///< The setting
const Type default_value{}; ///< The default value
const Type maximum{}; ///< Maximum allowed value of the setting
const Type minimum{}; ///< Minimum allowed value of the setting
const std::string label{}; ///< The setting's label
};
/**
* The SwitchableSetting class is a slightly more complex version of the Setting class. This adds a
* custom setting to switch to when a guest application specifically requires it. The effect is that
* other components of the emulator can access the setting's intended value without any need for the
* component to ask whether the custom or global setting is needed at the moment.
*
* By default, the global setting is used.
*/
template <typename Type, bool ranged = false>
class SwitchableSetting : virtual public Setting<Type, ranged> {
public:
/**
* Sets a default value, label, and setting value.
*
* @param default_val Initial value of the setting, and default value of the setting
* @param name Label for the setting
*/
explicit SwitchableSetting(const Type& default_val, const std::string& name)
requires(!ranged)
: Setting<Type>{default_val, name} {}
virtual ~SwitchableSetting() = default;
/**
* Sets a default value, minimum value, maximum value, and label.
*
* @param default_val Initial value of the setting, and default value of the setting
* @param min_val Sets the minimum allowed value of the setting
* @param max_val Sets the maximum allowed value of the setting
* @param name Label for the setting
*/
explicit SwitchableSetting(const Type& default_val, const Type& min_val, const Type& max_val,
const std::string& name)
requires(ranged)
: Setting<Type, true>{default_val, min_val, max_val, name} {}
/**
* Tells this setting to represent either the global or custom setting when other member
* functions are used.
*
* @param to_global Whether to use the global or custom setting.
*/
void SetGlobal(bool to_global) {
use_global = to_global;
}
/**
* Returns whether this setting is using the global setting or not.
*
* @returns The global state
*/
[[nodiscard]] bool UsingGlobal() const {
return use_global;
}
/**
* Returns either the global or custom setting depending on the values of this setting's global
* state or if the global value was specifically requested.
*
* @param need_global Request global value regardless of setting's state; defaults to false
*
* @returns The required value of the setting
*/
[[nodiscard]] virtual const Type& GetValue() const override {
if (use_global) {
return this->value;
}
return custom;
}
[[nodiscard]] virtual const Type& GetValue(bool need_global) const {
if (use_global || need_global) {
return this->value;
}
return custom;
}
/**
* Sets the current setting value depending on the global state.
*
* @param val The new value
*/
void SetValue(const Type& val) override {
Type temp{ranged ? std::clamp(val, this->minimum, this->maximum) : val};
if (use_global) {
std::swap(this->value, temp);
} else {
std::swap(custom, temp);
}
}
/**
* Assigns the current setting value depending on the global state.
*
* @param val The new value
*
* @returns A reference to the current setting value
*/
const Type& operator=(const Type& val) override {
Type temp{ranged ? std::clamp(val, this->minimum, this->maximum) : val};
if (use_global) {
std::swap(this->value, temp);
return this->value;
}
std::swap(custom, temp);
return custom;
}
/**
* Returns the current setting value depending on the global state.
*
* @returns A reference to the current setting value
*/
virtual explicit operator const Type&() const override {
if (use_global) {
return this->value;
}
return custom;
}
protected:
bool use_global{true}; ///< The setting's global state
Type custom{}; ///< The custom value of the setting
};
#undef SETTING
#undef SWITCHABLE
#endif
/**
* The InputSetting class allows for getting a reference to either the global or custom members.
@ -391,208 +125,388 @@ struct TouchFromButtonMap {
};
struct Values {
Linkage linkage{};
// Audio
Setting<std::string> sink_id{"auto", "output_engine"};
Setting<std::string> audio_output_device_id{"auto", "output_device"};
Setting<std::string> audio_input_device_id{"auto", "input_device"};
Setting<bool> audio_muted{false, "audio_muted"};
SwitchableSetting<u8, true> volume{100, 0, 200, "volume"};
Setting<bool> dump_audio_commands{false, "dump_audio_commands"};
Setting<AudioEngine> sink_id{linkage, AudioEngine::Auto, "output_engine", Category::Audio,
Specialization::RuntimeList};
Setting<std::string> audio_output_device_id{linkage, "auto", "output_device", Category::Audio,
Specialization::RuntimeList};
Setting<std::string> audio_input_device_id{linkage, "auto", "input_device", Category::Audio,
Specialization::RuntimeList};
SwitchableSetting<AudioMode, true> sound_index{
linkage, AudioMode::Stereo, AudioMode::Mono, AudioMode::Surround,
"sound_index", Category::SystemAudio, Specialization::Default, true,
true};
SwitchableSetting<u8, true> volume{linkage,
100,
0,
200,
"volume",
Category::Audio,
Specialization::Scalar | Specialization::Percentage,
true,
true};
Setting<bool, false> audio_muted{
linkage, false, "audio_muted", Category::Audio, Specialization::Default, false, true};
Setting<bool, false> dump_audio_commands{
linkage, false, "dump_audio_commands", Category::Audio, Specialization::Default, false};
// Core
SwitchableSetting<bool> use_multi_core{true, "use_multi_core"};
SwitchableSetting<bool> use_unsafe_extended_memory_layout{false,
"use_unsafe_extended_memory_layout"};
SwitchableSetting<bool> use_multi_core{linkage, true, "use_multi_core", Category::Core};
SwitchableSetting<MemoryLayout, true> memory_layout_mode{linkage,
MemoryLayout::Memory_4Gb,
MemoryLayout::Memory_4Gb,
MemoryLayout::Memory_8Gb,
"memory_layout_mode",
Category::Core};
SwitchableSetting<bool> use_speed_limit{
linkage, true, "use_speed_limit", Category::Core, Specialization::Paired, false, true};
SwitchableSetting<u16, true> speed_limit{linkage,
100,
0,
9999,
"speed_limit",
Category::Core,
Specialization::Countable | Specialization::Percentage,
true,
true,
&use_speed_limit};
// Cpu
SwitchableSetting<CPUAccuracy, true> cpu_accuracy{CPUAccuracy::Auto, CPUAccuracy::Auto,
CPUAccuracy::Paranoid, "cpu_accuracy"};
// TODO: remove cpu_accuracy_first_time, migration setting added 8 July 2021
Setting<bool> cpu_accuracy_first_time{true, "cpu_accuracy_first_time"};
Setting<bool> cpu_debug_mode{false, "cpu_debug_mode"};
SwitchableSetting<CpuAccuracy, true> cpu_accuracy{linkage, CpuAccuracy::Auto,
CpuAccuracy::Auto, CpuAccuracy::Paranoid,
"cpu_accuracy", Category::Cpu};
Setting<bool> cpu_debug_mode{linkage, false, "cpu_debug_mode", Category::CpuDebug};
Setting<bool> cpuopt_page_tables{true, "cpuopt_page_tables"};
Setting<bool> cpuopt_block_linking{true, "cpuopt_block_linking"};
Setting<bool> cpuopt_return_stack_buffer{true, "cpuopt_return_stack_buffer"};
Setting<bool> cpuopt_fast_dispatcher{true, "cpuopt_fast_dispatcher"};
Setting<bool> cpuopt_context_elimination{true, "cpuopt_context_elimination"};
Setting<bool> cpuopt_const_prop{true, "cpuopt_const_prop"};
Setting<bool> cpuopt_misc_ir{true, "cpuopt_misc_ir"};
Setting<bool> cpuopt_reduce_misalign_checks{true, "cpuopt_reduce_misalign_checks"};
Setting<bool> cpuopt_fastmem{true, "cpuopt_fastmem"};
Setting<bool> cpuopt_fastmem_exclusives{true, "cpuopt_fastmem_exclusives"};
Setting<bool> cpuopt_recompile_exclusives{true, "cpuopt_recompile_exclusives"};
Setting<bool> cpuopt_ignore_memory_aborts{true, "cpuopt_ignore_memory_aborts"};
Setting<bool> cpuopt_page_tables{linkage, true, "cpuopt_page_tables", Category::CpuDebug};
Setting<bool> cpuopt_block_linking{linkage, true, "cpuopt_block_linking", Category::CpuDebug};
Setting<bool> cpuopt_return_stack_buffer{linkage, true, "cpuopt_return_stack_buffer",
Category::CpuDebug};
Setting<bool> cpuopt_fast_dispatcher{linkage, true, "cpuopt_fast_dispatcher",
Category::CpuDebug};
Setting<bool> cpuopt_context_elimination{linkage, true, "cpuopt_context_elimination",
Category::CpuDebug};
Setting<bool> cpuopt_const_prop{linkage, true, "cpuopt_const_prop", Category::CpuDebug};
Setting<bool> cpuopt_misc_ir{linkage, true, "cpuopt_misc_ir", Category::CpuDebug};
Setting<bool> cpuopt_reduce_misalign_checks{linkage, true, "cpuopt_reduce_misalign_checks",
Category::CpuDebug};
Setting<bool> cpuopt_fastmem{linkage, true, "cpuopt_fastmem", Category::CpuDebug};
Setting<bool> cpuopt_fastmem_exclusives{linkage, true, "cpuopt_fastmem_exclusives",
Category::CpuDebug};
Setting<bool> cpuopt_recompile_exclusives{linkage, true, "cpuopt_recompile_exclusives",
Category::CpuDebug};
Setting<bool> cpuopt_ignore_memory_aborts{linkage, true, "cpuopt_ignore_memory_aborts",
Category::CpuDebug};
SwitchableSetting<bool> cpuopt_unsafe_unfuse_fma{true, "cpuopt_unsafe_unfuse_fma"};
SwitchableSetting<bool> cpuopt_unsafe_reduce_fp_error{true, "cpuopt_unsafe_reduce_fp_error"};
SwitchableSetting<bool> cpuopt_unsafe_unfuse_fma{linkage, true, "cpuopt_unsafe_unfuse_fma",
Category::CpuUnsafe};
SwitchableSetting<bool> cpuopt_unsafe_reduce_fp_error{
linkage, true, "cpuopt_unsafe_reduce_fp_error", Category::CpuUnsafe};
SwitchableSetting<bool> cpuopt_unsafe_ignore_standard_fpcr{
true, "cpuopt_unsafe_ignore_standard_fpcr"};
SwitchableSetting<bool> cpuopt_unsafe_inaccurate_nan{true, "cpuopt_unsafe_inaccurate_nan"};
SwitchableSetting<bool> cpuopt_unsafe_fastmem_check{true, "cpuopt_unsafe_fastmem_check"};
linkage, true, "cpuopt_unsafe_ignore_standard_fpcr", Category::CpuUnsafe};
SwitchableSetting<bool> cpuopt_unsafe_inaccurate_nan{
linkage, true, "cpuopt_unsafe_inaccurate_nan", Category::CpuUnsafe};
SwitchableSetting<bool> cpuopt_unsafe_fastmem_check{
linkage, true, "cpuopt_unsafe_fastmem_check", Category::CpuUnsafe};
SwitchableSetting<bool> cpuopt_unsafe_ignore_global_monitor{
true, "cpuopt_unsafe_ignore_global_monitor"};
linkage, true, "cpuopt_unsafe_ignore_global_monitor", Category::CpuUnsafe};
// Renderer
SwitchableSetting<RendererBackend, true> renderer_backend{
RendererBackend::Vulkan, RendererBackend::OpenGL, RendererBackend::Null, "backend"};
SwitchableSetting<bool> async_presentation{false, "async_presentation"};
SwitchableSetting<bool> renderer_force_max_clock{false, "force_max_clock"};
Setting<bool> renderer_debug{false, "debug"};
Setting<bool> renderer_shader_feedback{false, "shader_feedback"};
Setting<bool> enable_nsight_aftermath{false, "nsight_aftermath"};
Setting<bool> disable_shader_loop_safety_checks{false, "disable_shader_loop_safety_checks"};
SwitchableSetting<int> vulkan_device{0, "vulkan_device"};
linkage, RendererBackend::Vulkan, RendererBackend::OpenGL, RendererBackend::Null,
"backend", Category::Renderer};
SwitchableSetting<ShaderBackend, true> shader_backend{
linkage, ShaderBackend::Glsl, ShaderBackend::Glsl, ShaderBackend::SpirV,
"shader_backend", Category::Renderer, Specialization::RuntimeList};
SwitchableSetting<int> vulkan_device{linkage, 0, "vulkan_device", Category::Renderer,
Specialization::RuntimeList};
ResolutionScalingInfo resolution_info{};
SwitchableSetting<ResolutionSetup> resolution_setup{ResolutionSetup::Res1X, "resolution_setup"};
SwitchableSetting<ScalingFilter> scaling_filter{ScalingFilter::Bilinear, "scaling_filter"};
SwitchableSetting<int, true> fsr_sharpening_slider{25, 0, 200, "fsr_sharpening_slider"};
SwitchableSetting<AntiAliasing> anti_aliasing{AntiAliasing::None, "anti_aliasing"};
SwitchableSetting<bool> use_disk_shader_cache{linkage, true, "use_disk_shader_cache",
Category::Renderer};
SwitchableSetting<bool> use_asynchronous_gpu_emulation{
linkage, true, "use_asynchronous_gpu_emulation", Category::Renderer};
SwitchableSetting<AstcDecodeMode, true> accelerate_astc{linkage,
AstcDecodeMode::Gpu,
AstcDecodeMode::Cpu,
AstcDecodeMode::CpuAsynchronous,
"accelerate_astc",
Category::Renderer};
Setting<VSyncMode, true> vsync_mode{
linkage, VSyncMode::Fifo, VSyncMode::Immediate, VSyncMode::FifoRelaxed,
"use_vsync", Category::Renderer, Specialization::RuntimeList, true,
true};
SwitchableSetting<NvdecEmulation> nvdec_emulation{linkage, NvdecEmulation::Gpu,
"nvdec_emulation", Category::Renderer};
// *nix platforms may have issues with the borderless windowed fullscreen mode.
// Default to exclusive fullscreen on these platforms for now.
SwitchableSetting<FullscreenMode, true> fullscreen_mode{
SwitchableSetting<FullscreenMode, true> fullscreen_mode{linkage,
#ifdef _WIN32
FullscreenMode::Borderless,
FullscreenMode::Borderless,
#else
FullscreenMode::Exclusive,
FullscreenMode::Exclusive,
#endif
FullscreenMode::Borderless, FullscreenMode::Exclusive, "fullscreen_mode"};
SwitchableSetting<int, true> aspect_ratio{0, 0, 4, "aspect_ratio"};
SwitchableSetting<int, true> max_anisotropy{0, 0, 5, "max_anisotropy"};
SwitchableSetting<bool> use_speed_limit{true, "use_speed_limit"};
SwitchableSetting<u16, true> speed_limit{100, 0, 9999, "speed_limit"};
SwitchableSetting<bool> use_disk_shader_cache{true, "use_disk_shader_cache"};
SwitchableSetting<GPUAccuracy, true> gpu_accuracy{GPUAccuracy::High, GPUAccuracy::Normal,
GPUAccuracy::Extreme, "gpu_accuracy"};
SwitchableSetting<bool> use_asynchronous_gpu_emulation{true, "use_asynchronous_gpu_emulation"};
SwitchableSetting<NvdecEmulation> nvdec_emulation{NvdecEmulation::GPU, "nvdec_emulation"};
SwitchableSetting<bool> accelerate_astc{true, "accelerate_astc"};
SwitchableSetting<bool> async_astc{false, "async_astc"};
Setting<VSyncMode, true> vsync_mode{VSyncMode::FIFO, VSyncMode::Immediate,
VSyncMode::FIFORelaxed, "use_vsync"};
SwitchableSetting<bool> use_reactive_flushing{true, "use_reactive_flushing"};
SwitchableSetting<ShaderBackend, true> shader_backend{ShaderBackend::GLSL, ShaderBackend::GLSL,
ShaderBackend::SPIRV, "shader_backend"};
SwitchableSetting<bool> use_asynchronous_shaders{false, "use_asynchronous_shaders"};
SwitchableSetting<bool> use_fast_gpu_time{true, "use_fast_gpu_time"};
SwitchableSetting<bool> use_vulkan_driver_pipeline_cache{true,
"use_vulkan_driver_pipeline_cache"};
SwitchableSetting<bool> enable_compute_pipelines{false, "enable_compute_pipelines"};
SwitchableSetting<AstcRecompression, true> astc_recompression{
AstcRecompression::Uncompressed, AstcRecompression::Uncompressed, AstcRecompression::Bc3,
"astc_recompression"};
SwitchableSetting<bool> use_video_framerate{false, "use_video_framerate"};
SwitchableSetting<bool> barrier_feedback_loops{true, "barrier_feedback_loops"};
FullscreenMode::Borderless,
FullscreenMode::Exclusive,
"fullscreen_mode",
Category::Renderer,
Specialization::Default,
true,
true};
SwitchableSetting<AspectRatio, true> aspect_ratio{linkage,
AspectRatio::R16_9,
AspectRatio::R16_9,
AspectRatio::Stretch,
"aspect_ratio",
Category::Renderer,
Specialization::Default,
true,
true};
SwitchableSetting<u8> bg_red{0, "bg_red"};
SwitchableSetting<u8> bg_green{0, "bg_green"};
SwitchableSetting<u8> bg_blue{0, "bg_blue"};
ResolutionScalingInfo resolution_info{};
SwitchableSetting<ResolutionSetup> resolution_setup{linkage, ResolutionSetup::Res1X,
"resolution_setup", Category::Renderer};
SwitchableSetting<ScalingFilter> scaling_filter{linkage,
ScalingFilter::Bilinear,
"scaling_filter",
Category::Renderer,
Specialization::Default,
true,
true};
SwitchableSetting<AntiAliasing> anti_aliasing{linkage,
AntiAliasing::None,
"anti_aliasing",
Category::Renderer,
Specialization::Default,
true,
true};
SwitchableSetting<int, true> fsr_sharpening_slider{linkage,
25,
0,
200,
"fsr_sharpening_slider",
Category::Renderer,
Specialization::Scalar |
Specialization::Percentage,
true,
true};
SwitchableSetting<u8, false> bg_red{
linkage, 0, "bg_red", Category::Renderer, Specialization::Default, true, true};
SwitchableSetting<u8, false> bg_green{
linkage, 0, "bg_green", Category::Renderer, Specialization::Default, true, true};
SwitchableSetting<u8, false> bg_blue{
linkage, 0, "bg_blue", Category::Renderer, Specialization::Default, true, true};
SwitchableSetting<GpuAccuracy, true> gpu_accuracy{linkage,
GpuAccuracy::High,
GpuAccuracy::Normal,
GpuAccuracy::Extreme,
"gpu_accuracy",
Category::RendererAdvanced,
Specialization::Default,
true,
true};
SwitchableSetting<AnisotropyMode, true> max_anisotropy{
linkage, AnisotropyMode::Automatic, AnisotropyMode::Automatic, AnisotropyMode::X16,
"max_anisotropy", Category::RendererAdvanced};
SwitchableSetting<AstcRecompression, true> astc_recompression{linkage,
AstcRecompression::Uncompressed,
AstcRecompression::Uncompressed,
AstcRecompression::Bc3,
"astc_recompression",
Category::RendererAdvanced};
SwitchableSetting<bool> async_presentation{linkage, false, "async_presentation",
Category::RendererAdvanced};
SwitchableSetting<bool> renderer_force_max_clock{linkage, false, "force_max_clock",
Category::RendererAdvanced};
SwitchableSetting<bool> use_reactive_flushing{linkage, true, "use_reactive_flushing",
Category::RendererAdvanced};
SwitchableSetting<bool> use_asynchronous_shaders{linkage, false, "use_asynchronous_shaders",
Category::RendererAdvanced};
SwitchableSetting<bool> use_fast_gpu_time{
linkage, true, "use_fast_gpu_time", Category::RendererAdvanced, Specialization::Default,
true, true};
SwitchableSetting<bool> use_vulkan_driver_pipeline_cache{linkage,
true,
"use_vulkan_driver_pipeline_cache",
Category::RendererAdvanced,
Specialization::Default,
true,
true};
SwitchableSetting<bool> enable_compute_pipelines{linkage, false, "enable_compute_pipelines",
Category::RendererAdvanced};
SwitchableSetting<bool> use_video_framerate{linkage, false, "use_video_framerate",
Category::RendererAdvanced};
SwitchableSetting<bool> barrier_feedback_loops{linkage, true, "barrier_feedback_loops",
Category::RendererAdvanced};
Setting<bool> renderer_debug{linkage, false, "debug", Category::RendererDebug};
Setting<bool> renderer_shader_feedback{linkage, false, "shader_feedback",
Category::RendererDebug};
Setting<bool> enable_nsight_aftermath{linkage, false, "nsight_aftermath",
Category::RendererDebug};
Setting<bool> disable_shader_loop_safety_checks{
linkage, false, "disable_shader_loop_safety_checks", Category::RendererDebug};
// System
SwitchableSetting<std::optional<u32>> rng_seed{std::optional<u32>(), "rng_seed"};
Setting<std::string> device_name{"Yuzu", "device_name"};
SwitchableSetting<Language, true> language_index{linkage,
Language::EnglishAmerican,
Language::Japanese,
Language::PortugueseBrazilian,
"language_index",
Category::System};
SwitchableSetting<Region, true> region_index{linkage, Region::Usa, Region::Japan,
Region::Taiwan, "region_index", Category::System};
SwitchableSetting<TimeZone, true> time_zone_index{linkage, TimeZone::Auto,
TimeZone::Auto, TimeZone::Zulu,
"time_zone_index", Category::System};
// Measured in seconds since epoch
std::optional<s64> custom_rtc;
SwitchableSetting<bool> custom_rtc_enabled{
linkage, false, "custom_rtc_enabled", Category::System, Specialization::Paired, true, true};
SwitchableSetting<s64> custom_rtc{
linkage, 0, "custom_rtc", Category::System, Specialization::Time,
true, true, &custom_rtc_enabled};
// Set on game boot, reset on stop. Seconds difference between current time and `custom_rtc`
s64 custom_rtc_differential;
SwitchableSetting<bool> rng_seed_enabled{
linkage, false, "rng_seed_enabled", Category::System, Specialization::Paired, true, true};
SwitchableSetting<u32> rng_seed{
linkage, 0, "rng_seed", Category::System, Specialization::Hex,
true, true, &rng_seed_enabled};
Setting<std::string> device_name{
linkage, "yuzu", "device_name", Category::System, Specialization::Default, true, true};
Setting<s32> current_user{0, "current_user"};
SwitchableSetting<s32, true> language_index{1, 0, 17, "language_index"};
SwitchableSetting<s32, true> region_index{1, 0, 6, "region_index"};
SwitchableSetting<s32, true> time_zone_index{0, 0, 45, "time_zone_index"};
SwitchableSetting<s32, true> sound_index{1, 0, 2, "sound_index"};
Setting<s32> current_user{linkage, 0, "current_user", Category::System};
SwitchableSetting<bool> use_docked_mode{linkage, true, "use_docked_mode", Category::System};
// Controls
InputSetting<std::array<PlayerInput, 10>> players;
SwitchableSetting<bool> use_docked_mode{true, "use_docked_mode"};
Setting<bool> enable_raw_input{
linkage, false, "enable_raw_input", Category::Controls, Specialization::Default,
// Only read/write enable_raw_input on Windows platforms
#ifdef _WIN32
true
#else
false
#endif
};
Setting<bool> controller_navigation{linkage, true, "controller_navigation", Category::Controls};
Setting<bool> enable_joycon_driver{linkage, true, "enable_joycon_driver", Category::Controls};
Setting<bool> enable_procon_driver{linkage, false, "enable_procon_driver", Category::Controls};
Setting<bool> enable_raw_input{false, "enable_raw_input"};
Setting<bool> controller_navigation{true, "controller_navigation"};
Setting<bool> enable_joycon_driver{true, "enable_joycon_driver"};
Setting<bool> enable_procon_driver{false, "enable_procon_driver"};
SwitchableSetting<bool> vibration_enabled{linkage, true, "vibration_enabled",
Category::Controls};
SwitchableSetting<bool> enable_accurate_vibrations{linkage, false, "enable_accurate_vibrations",
Category::Controls};
SwitchableSetting<bool> vibration_enabled{true, "vibration_enabled"};
SwitchableSetting<bool> enable_accurate_vibrations{false, "enable_accurate_vibrations"};
SwitchableSetting<bool> motion_enabled{linkage, true, "motion_enabled", Category::Controls};
Setting<std::string> udp_input_servers{linkage, "127.0.0.1:26760", "udp_input_servers",
Category::Controls};
Setting<bool> enable_udp_controller{linkage, false, "enable_udp_controller",
Category::Controls};
SwitchableSetting<bool> motion_enabled{true, "motion_enabled"};
Setting<std::string> udp_input_servers{"127.0.0.1:26760", "udp_input_servers"};
Setting<bool> enable_udp_controller{false, "enable_udp_controller"};
Setting<bool> pause_tas_on_load{linkage, true, "pause_tas_on_load", Category::Controls};
Setting<bool> tas_enable{linkage, false, "tas_enable", Category::Controls};
Setting<bool> tas_loop{linkage, false, "tas_loop", Category::Controls};
Setting<bool> pause_tas_on_load{true, "pause_tas_on_load"};
Setting<bool> tas_enable{false, "tas_enable"};
Setting<bool> tas_loop{false, "tas_loop"};
Setting<bool> mouse_panning{
linkage, false, "mouse_panning", Category::Controls, Specialization::Default, false};
Setting<u8, true> mouse_panning_sensitivity{
linkage, 50, 1, 100, "mouse_panning_sensitivity", Category::Controls};
Setting<bool> mouse_enabled{linkage, false, "mouse_enabled", Category::Controls};
Setting<bool> mouse_panning{false, "mouse_panning"};
Setting<u8, true> mouse_panning_x_sensitivity{50, 1, 100, "mouse_panning_x_sensitivity"};
Setting<u8, true> mouse_panning_y_sensitivity{50, 1, 100, "mouse_panning_y_sensitivity"};
Setting<u8, true> mouse_panning_deadzone_counterweight{20, 0, 100,
"mouse_panning_deadzone_counterweight"};
Setting<u8, true> mouse_panning_decay_strength{18, 0, 100, "mouse_panning_decay_strength"};
Setting<u8, true> mouse_panning_min_decay{6, 0, 100, "mouse_panning_min_decay"};
Setting<u8, true> mouse_panning_x_sensitivity{
linkage, 50, 1, 100, "mouse_panning_x_sensitivity", Category::Controls};
Setting<u8, true> mouse_panning_y_sensitivity{
linkage, 50, 1, 100, "mouse_panning_y_sensitivity", Category::Controls};
Setting<u8, true> mouse_panning_deadzone_counterweight{
linkage, 20, 0, 100, "mouse_panning_deadzone_counterweight", Category::Controls};
Setting<u8, true> mouse_panning_decay_strength{
linkage, 18, 0, 100, "mouse_panning_decay_strength", Category::Controls};
Setting<u8, true> mouse_panning_min_decay{
linkage, 6, 0, 100, "mouse_panning_min_decay", Category::Controls};
Setting<bool> mouse_enabled{false, "mouse_enabled"};
Setting<bool> emulate_analog_keyboard{false, "emulate_analog_keyboard"};
Setting<bool> keyboard_enabled{false, "keyboard_enabled"};
Setting<bool> emulate_analog_keyboard{linkage, false, "emulate_analog_keyboard",
Category::Controls};
Setting<bool> keyboard_enabled{linkage, false, "keyboard_enabled", Category::Controls};
Setting<bool> debug_pad_enabled{false, "debug_pad_enabled"};
Setting<bool> debug_pad_enabled{linkage, false, "debug_pad_enabled", Category::Controls};
ButtonsRaw debug_pad_buttons;
AnalogsRaw debug_pad_analogs;
TouchscreenInput touchscreen;
Setting<std::string> touch_device{"min_x:100,min_y:50,max_x:1800,max_y:850", "touch_device"};
Setting<int> touch_from_button_map_index{0, "touch_from_button_map"};
Setting<std::string> touch_device{linkage, "min_x:100,min_y:50,max_x:1800,max_y:850",
"touch_device", Category::Controls};
Setting<int> touch_from_button_map_index{linkage, 0, "touch_from_button_map",
Category::Controls};
std::vector<TouchFromButtonMap> touch_from_button_maps;
Setting<bool> enable_ring_controller{true, "enable_ring_controller"};
Setting<bool> enable_ring_controller{linkage, true, "enable_ring_controller",
Category::Controls};
RingconRaw ringcon_analogs;
Setting<bool> enable_ir_sensor{false, "enable_ir_sensor"};
Setting<std::string> ir_sensor_device{"auto", "ir_sensor_device"};
Setting<bool> enable_ir_sensor{linkage, false, "enable_ir_sensor", Category::Controls};
Setting<std::string> ir_sensor_device{linkage, "auto", "ir_sensor_device", Category::Controls};
Setting<bool> random_amiibo_id{false, "random_amiibo_id"};
Setting<bool> random_amiibo_id{linkage, false, "random_amiibo_id", Category::Controls};
// Data Storage
Setting<bool> use_virtual_sd{true, "use_virtual_sd"};
Setting<bool> gamecard_inserted{false, "gamecard_inserted"};
Setting<bool> gamecard_current_game{false, "gamecard_current_game"};
Setting<std::string> gamecard_path{std::string(), "gamecard_path"};
Setting<bool> use_virtual_sd{linkage, true, "use_virtual_sd", Category::DataStorage};
Setting<bool> gamecard_inserted{linkage, false, "gamecard_inserted", Category::DataStorage};
Setting<bool> gamecard_current_game{linkage, false, "gamecard_current_game",
Category::DataStorage};
Setting<std::string> gamecard_path{linkage, std::string(), "gamecard_path",
Category::DataStorage};
// Debugging
bool record_frame_times;
Setting<bool> use_gdbstub{false, "use_gdbstub"};
Setting<u16> gdbstub_port{6543, "gdbstub_port"};
Setting<std::string> program_args{std::string(), "program_args"};
Setting<bool> dump_exefs{false, "dump_exefs"};
Setting<bool> dump_nso{false, "dump_nso"};
Setting<bool> dump_shaders{false, "dump_shaders"};
Setting<bool> dump_macros{false, "dump_macros"};
Setting<bool> enable_fs_access_log{false, "enable_fs_access_log"};
Setting<bool> reporting_services{false, "reporting_services"};
Setting<bool> quest_flag{false, "quest_flag"};
Setting<bool> disable_macro_jit{false, "disable_macro_jit"};
Setting<bool> disable_macro_hle{false, "disable_macro_hle"};
Setting<bool> extended_logging{false, "extended_logging"};
Setting<bool> use_debug_asserts{false, "use_debug_asserts"};
Setting<bool> use_auto_stub{false, "use_auto_stub"};
Setting<bool> enable_all_controllers{false, "enable_all_controllers"};
Setting<bool> create_crash_dumps{false, "create_crash_dumps"};
Setting<bool> perform_vulkan_check{true, "perform_vulkan_check"};
Setting<bool> use_gdbstub{linkage, false, "use_gdbstub", Category::Debugging};
Setting<u16> gdbstub_port{linkage, 6543, "gdbstub_port", Category::Debugging};
Setting<std::string> program_args{linkage, std::string(), "program_args", Category::Debugging};
Setting<bool> dump_exefs{linkage, false, "dump_exefs", Category::Debugging};
Setting<bool> dump_nso{linkage, false, "dump_nso", Category::Debugging};
Setting<bool> dump_shaders{
linkage, false, "dump_shaders", Category::DebuggingGraphics, Specialization::Default,
false};
Setting<bool> dump_macros{
linkage, false, "dump_macros", Category::DebuggingGraphics, Specialization::Default, false};
Setting<bool> enable_fs_access_log{linkage, false, "enable_fs_access_log", Category::Debugging};
Setting<bool> reporting_services{
linkage, false, "reporting_services", Category::Debugging, Specialization::Default, false};
Setting<bool> quest_flag{linkage, false, "quest_flag", Category::Debugging};
Setting<bool> disable_macro_jit{linkage, false, "disable_macro_jit",
Category::DebuggingGraphics};
Setting<bool> disable_macro_hle{linkage, false, "disable_macro_hle",
Category::DebuggingGraphics};
Setting<bool> extended_logging{
linkage, false, "extended_logging", Category::Debugging, Specialization::Default, false};
Setting<bool> use_debug_asserts{linkage, false, "use_debug_asserts", Category::Debugging};
Setting<bool> use_auto_stub{
linkage, false, "use_auto_stub", Category::Debugging, Specialization::Default, false};
Setting<bool> enable_all_controllers{linkage, false, "enable_all_controllers",
Category::Debugging};
Setting<bool> create_crash_dumps{linkage, false, "create_crash_dumps", Category::Debugging};
Setting<bool> perform_vulkan_check{linkage, true, "perform_vulkan_check", Category::Debugging};
// Miscellaneous
Setting<std::string> log_filter{"*:Info", "log_filter"};
Setting<bool> use_dev_keys{false, "use_dev_keys"};
Setting<std::string> log_filter{linkage, "*:Info", "log_filter", Category::Miscellaneous};
Setting<bool> use_dev_keys{linkage, false, "use_dev_keys", Category::Miscellaneous};
// Network
Setting<std::string> network_interface{std::string(), "network_interface"};
Setting<std::string> network_interface{linkage, std::string(), "network_interface",
Category::Network};
// WebService
Setting<bool> enable_telemetry{true, "enable_telemetry"};
Setting<std::string> web_api_url{"https://api.yuzu-emu.org", "web_api_url"};
Setting<std::string> yuzu_username{std::string(), "yuzu_username"};
Setting<std::string> yuzu_token{std::string(), "yuzu_token"};
Setting<bool> enable_telemetry{linkage, true, "enable_telemetry", Category::WebService};
Setting<std::string> web_api_url{linkage, "https://api.yuzu-emu.org", "web_api_url",
Category::WebService};
Setting<std::string> yuzu_username{linkage, std::string(), "yuzu_username",
Category::WebService};
Setting<std::string> yuzu_token{linkage, std::string(), "yuzu_token", Category::WebService};
// Add-Ons
std::map<u64, std::vector<std::string>> disabled_addons;
@ -600,9 +514,6 @@ struct Values {
extern Values values;
bool IsConfiguringGlobal();
void SetConfiguringGlobal(bool is_global);
bool IsGPULevelExtreme();
bool IsGPULevelHigh();
@ -610,7 +521,7 @@ bool IsFastmemEnabled();
float Volume();
std::string GetTimeZoneString();
std::string GetTimeZoneString(TimeZone time_zone);
void LogSettings();
@ -619,4 +530,7 @@ void UpdateRescalingInfo();
// Restore the global state of all applicable settings in the Values struct
void RestoreGlobalState(bool is_powered_on);
bool IsConfiguringGlobal();
void SetConfiguringGlobal(bool is_global);
} // namespace Settings

View File

@ -0,0 +1,60 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <functional>
#include <string>
#include <vector>
#include "common/settings_common.h"
namespace Settings {
BasicSetting::BasicSetting(Linkage& linkage, const std::string& name, enum Category category_,
bool save_, bool runtime_modifiable_, u32 specialization_,
BasicSetting* other_setting_)
: label{name}, category{category_}, id{linkage.count}, save{save_},
runtime_modifiable{runtime_modifiable_}, specialization{specialization_},
other_setting{other_setting_} {
linkage.by_category[category].push_back(this);
linkage.count++;
}
BasicSetting::~BasicSetting() = default;
std::string BasicSetting::ToStringGlobal() const {
return this->ToString();
}
bool BasicSetting::UsingGlobal() const {
return true;
}
void BasicSetting::SetGlobal(bool global) {}
bool BasicSetting::Save() const {
return save;
}
bool BasicSetting::RuntimeModfiable() const {
return runtime_modifiable;
}
Category BasicSetting::GetCategory() const {
return category;
}
u32 BasicSetting::Specialization() const {
return specialization;
}
BasicSetting* BasicSetting::PairedSetting() const {
return other_setting;
}
const std::string& BasicSetting::GetLabel() const {
return label;
}
Linkage::Linkage(u32 initial_count) : count{initial_count} {}
Linkage::~Linkage() = default;
} // namespace Settings

View File

@ -0,0 +1,256 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <functional>
#include <map>
#include <string>
#include <typeindex>
#include "common/common_types.h"
namespace Settings {
enum class Category : u32 {
Audio,
Core,
Cpu,
CpuDebug,
CpuUnsafe,
Renderer,
RendererAdvanced,
RendererDebug,
System,
SystemAudio,
DataStorage,
Debugging,
DebuggingGraphics,
Miscellaneous,
Network,
WebService,
AddOns,
Controls,
Ui,
UiGeneral,
UiLayout,
UiGameList,
Screenshots,
Shortcuts,
Multiplayer,
Services,
Paths,
MaxEnum,
};
constexpr u8 SpecializationTypeMask = 0xf;
constexpr u8 SpecializationAttributeMask = 0xf0;
constexpr u8 SpecializationAttributeOffset = 4;
// Scalar and countable could have better names
enum Specialization : u8 {
Default = 0,
Time = 1, // Duration or specific moment in time
Hex = 2, // Hexadecimal number
List = 3, // Setting has specific members
RuntimeList = 4, // Members of the list are determined during runtime
Scalar = 5, // Values are continuous
Countable = 6, // Can be stepped through
Paired = 7, // Another setting is associated with this setting
Percentage = (1 << SpecializationAttributeOffset), // Should be represented as a percentage
};
class BasicSetting;
class Linkage {
public:
explicit Linkage(u32 initial_count = 0);
~Linkage();
std::map<Category, std::vector<BasicSetting*>> by_category{};
std::vector<std::function<void()>> restore_functions{};
u32 count;
};
/**
* BasicSetting is an abstract class that only keeps track of metadata. The string methods are
* available to get data values out.
*/
class BasicSetting {
protected:
explicit BasicSetting(Linkage& linkage, const std::string& name, Category category_, bool save_,
bool runtime_modifiable_, u32 specialization,
BasicSetting* other_setting);
public:
virtual ~BasicSetting();
/*
* Data retrieval
*/
/**
* Returns a string representation of the internal data. If the Setting is Switchable, it
* respects the internal global state: it is based on GetValue().
*
* @returns A string representation of the internal data.
*/
[[nodiscard]] virtual std::string ToString() const = 0;
/**
* Returns a string representation of the global version of internal data. If the Setting is
* not Switchable, it behaves like ToString.
*
* @returns A string representation of the global version of internal data.
*/
[[nodiscard]] virtual std::string ToStringGlobal() const;
/**
* @returns A string representation of the Setting's default value.
*/
[[nodiscard]] virtual std::string DefaultToString() const = 0;
/**
* Returns a string representation of the minimum value of the setting. If the Setting is not
* ranged, the string represents the default initialization of the data type.
*
* @returns A string representation of the minimum value of the setting.
*/
[[nodiscard]] virtual std::string MinVal() const = 0;
/**
* Returns a string representation of the maximum value of the setting. If the Setting is not
* ranged, the string represents the default initialization of the data type.
*
* @returns A string representation of the maximum value of the setting.
*/
[[nodiscard]] virtual std::string MaxVal() const = 0;
/**
* Takes a string input, converts it to the internal data type if necessary, and then runs
* SetValue with it.
*
* @param load String of the input data.
*/
virtual void LoadString(const std::string& load) = 0;
/**
* Returns a string representation of the data. If the data is an enum, it returns a string of
* the enum value. If the internal data type is not an enum, this is equivalent to ToString.
*
* e.g. renderer_backend.Canonicalize() == "OpenGL"
*
* @returns Canonicalized string representation of the internal data
*/
[[nodiscard]] virtual std::string Canonicalize() const = 0;
/*
* Metadata
*/
/**
* @returns A unique identifier for the Setting's internal data type.
*/
[[nodiscard]] virtual std::type_index TypeId() const = 0;
/**
* Returns true if the Setting's internal data type is an enum.
*
* @returns True if the Setting's internal data type is an enum
*/
[[nodiscard]] virtual constexpr bool IsEnum() const = 0;
/**
* Returns true if the current setting is Switchable.
*
* @returns If the setting is a SwitchableSetting
*/
[[nodiscard]] virtual constexpr bool Switchable() const {
return false;
}
/**
* Returns true to suggest that a frontend can read or write the setting to a configuration
* file.
*
* @returns The save preference
*/
[[nodiscard]] bool Save() const;
/**
* @returns true if the current setting can be changed while the guest is running.
*/
[[nodiscard]] bool RuntimeModfiable() const;
/**
* @returns A unique number corresponding to the setting.
*/
[[nodiscard]] constexpr u32 Id() const {
return id;
}
/**
* Returns the setting's category AKA INI group.
*
* @returns The setting's category
*/
[[nodiscard]] Category GetCategory() const;
/**
* @returns Extra metadata for data representation in frontend implementations.
*/
[[nodiscard]] u32 Specialization() const;
/**
* @returns Another BasicSetting if one is paired, or nullptr otherwise.
*/
[[nodiscard]] BasicSetting* PairedSetting() const;
/**
* Returns the label this setting was created with.
*
* @returns A reference to the label
*/
[[nodiscard]] const std::string& GetLabel() const;
/**
* @returns If the Setting checks input values for valid ranges.
*/
[[nodiscard]] virtual constexpr bool Ranged() const = 0;
/**
* @returns The index of the enum if the underlying setting type is an enum, else max of u32.
*/
[[nodiscard]] virtual constexpr u32 EnumIndex() const = 0;
/*
* Switchable settings
*/
/**
* Sets a setting's global state. True means use the normal setting, false to use a custom
* value. Has no effect if the Setting is not Switchable.
*
* @param global The desired state
*/
virtual void SetGlobal(bool global);
/**
* Returns true if the setting is using the normal setting value. Always true if the setting is
* not Switchable.
*
* @returns The Setting's global state
*/
[[nodiscard]] virtual bool UsingGlobal() const;
private:
const std::string label; ///< The setting's label
const Category category; ///< The setting's category AKA INI group
const u32 id; ///< Unique integer for the setting
const bool save; ///< Suggests if the setting should be saved and read to a frontend config
const bool
runtime_modifiable; ///< Suggests if the setting can be modified while a guest is running
const u32 specialization; ///< Extra data to identify representation of a setting
BasicSetting* const other_setting; ///< A paired setting
};
} // namespace Settings

214
src/common/settings_enums.h Normal file
View File

@ -0,0 +1,214 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <string>
#include <utility>
#include <vector>
#include "common/common_types.h"
namespace Settings {
template <typename T>
struct EnumMetadata {
static std::vector<std::pair<std::string, T>> Canonicalizations();
static u32 Index();
};
#define PAIR_45(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_46(N, __VA_ARGS__))
#define PAIR_44(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_45(N, __VA_ARGS__))
#define PAIR_43(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_44(N, __VA_ARGS__))
#define PAIR_42(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_43(N, __VA_ARGS__))
#define PAIR_41(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_42(N, __VA_ARGS__))
#define PAIR_40(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_41(N, __VA_ARGS__))
#define PAIR_39(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_40(N, __VA_ARGS__))
#define PAIR_38(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_39(N, __VA_ARGS__))
#define PAIR_37(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_38(N, __VA_ARGS__))
#define PAIR_36(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_37(N, __VA_ARGS__))
#define PAIR_35(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_36(N, __VA_ARGS__))
#define PAIR_34(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_35(N, __VA_ARGS__))
#define PAIR_33(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_34(N, __VA_ARGS__))
#define PAIR_32(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_33(N, __VA_ARGS__))
#define PAIR_31(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_32(N, __VA_ARGS__))
#define PAIR_30(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_31(N, __VA_ARGS__))
#define PAIR_29(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_30(N, __VA_ARGS__))
#define PAIR_28(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_29(N, __VA_ARGS__))
#define PAIR_27(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_28(N, __VA_ARGS__))
#define PAIR_26(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_27(N, __VA_ARGS__))
#define PAIR_25(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_26(N, __VA_ARGS__))
#define PAIR_24(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_25(N, __VA_ARGS__))
#define PAIR_23(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_24(N, __VA_ARGS__))
#define PAIR_22(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_23(N, __VA_ARGS__))
#define PAIR_21(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_22(N, __VA_ARGS__))
#define PAIR_20(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_21(N, __VA_ARGS__))
#define PAIR_19(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_20(N, __VA_ARGS__))
#define PAIR_18(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_19(N, __VA_ARGS__))
#define PAIR_17(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_18(N, __VA_ARGS__))
#define PAIR_16(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_17(N, __VA_ARGS__))
#define PAIR_15(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_16(N, __VA_ARGS__))
#define PAIR_14(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_15(N, __VA_ARGS__))
#define PAIR_13(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_14(N, __VA_ARGS__))
#define PAIR_12(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_13(N, __VA_ARGS__))
#define PAIR_11(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_12(N, __VA_ARGS__))
#define PAIR_10(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_11(N, __VA_ARGS__))
#define PAIR_9(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_10(N, __VA_ARGS__))
#define PAIR_8(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_9(N, __VA_ARGS__))
#define PAIR_7(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_8(N, __VA_ARGS__))
#define PAIR_6(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_7(N, __VA_ARGS__))
#define PAIR_5(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_6(N, __VA_ARGS__))
#define PAIR_4(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_5(N, __VA_ARGS__))
#define PAIR_3(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_4(N, __VA_ARGS__))
#define PAIR_2(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_3(N, __VA_ARGS__))
#define PAIR_1(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_2(N, __VA_ARGS__))
#define PAIR(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_1(N, __VA_ARGS__))
#define ENUM(NAME, ...) \
enum class NAME : u32 { __VA_ARGS__ }; \
template <> \
inline std::vector<std::pair<std::string, NAME>> EnumMetadata<NAME>::Canonicalizations() { \
return {PAIR(NAME, __VA_ARGS__)}; \
} \
template <> \
inline u32 EnumMetadata<NAME>::Index() { \
return __COUNTER__; \
}
// AudioEngine must be specified discretely due to having existing but slightly different
// canonicalizations
// TODO (lat9nq): Remove explicit definition of AudioEngine/sink_id
enum class AudioEngine : u32 {
Auto,
Cubeb,
Sdl2,
Null,
};
template <>
inline std::vector<std::pair<std::string, AudioEngine>>
EnumMetadata<AudioEngine>::Canonicalizations() {
return {
{"auto", AudioEngine::Auto},
{"cubeb", AudioEngine::Cubeb},
{"sdl2", AudioEngine::Sdl2},
{"null", AudioEngine::Null},
};
}
template <>
inline u32 EnumMetadata<AudioEngine>::Index() {
// This is just a sufficiently large number that is more than the number of other enums declared
// here
return 100;
}
ENUM(AudioMode, Mono, Stereo, Surround);
ENUM(Language, Japanese, EnglishAmerican, French, German, Italian, Spanish, Chinese, Korean, Dutch,
Portuguese, Russian, Taiwanese, EnglishBritish, FrenchCanadian, SpanishLatin,
ChineseSimplified, ChineseTraditional, PortugueseBrazilian);
ENUM(Region, Japan, Usa, Europe, Australia, China, Korea, Taiwan);
ENUM(TimeZone, Auto, Default, Cet, Cst6Cdt, Cuba, Eet, Egypt, Eire, Est, Est5Edt, Gb, GbEire, Gmt,
GmtPlusZero, GmtMinusZero, GmtZero, Greenwich, Hongkong, Hst, Iceland, Iran, Israel, Jamaica,
Japan, Kwajalein, Libya, Met, Mst, Mst7Mdt, Navajo, Nz, NzChat, Poland, Portugal, Prc, Pst8Pdt,
Roc, Rok, Singapore, Turkey, Uct, Universal, Utc, WSu, Wet, Zulu);
ENUM(AnisotropyMode, Automatic, Default, X2, X4, X8, X16);
ENUM(AstcDecodeMode, Cpu, Gpu, CpuAsynchronous);
ENUM(AstcRecompression, Uncompressed, Bc1, Bc3);
ENUM(VSyncMode, Immediate, Mailbox, Fifo, FifoRelaxed);
ENUM(RendererBackend, OpenGL, Vulkan, Null);
ENUM(ShaderBackend, Glsl, Glasm, SpirV);
ENUM(GpuAccuracy, Normal, High, Extreme);
ENUM(CpuAccuracy, Auto, Accurate, Unsafe, Paranoid);
ENUM(MemoryLayout, Memory_4Gb, Memory_6Gb, Memory_8Gb);
ENUM(FullscreenMode, Borderless, Exclusive);
ENUM(NvdecEmulation, Off, Cpu, Gpu);
ENUM(ResolutionSetup, Res1_2X, Res3_4X, Res1X, Res3_2X, Res2X, Res3X, Res4X, Res5X, Res6X, Res7X,
Res8X);
ENUM(ScalingFilter, NearestNeighbor, Bilinear, Bicubic, Gaussian, ScaleForce, Fsr, MaxEnum);
ENUM(AntiAliasing, None, Fxaa, Smaa, MaxEnum);
ENUM(AspectRatio, R16_9, R4_3, R21_9, R16_10, Stretch);
template <typename Type>
inline std::string CanonicalizeEnum(Type id) {
const auto group = EnumMetadata<Type>::Canonicalizations();
for (auto& [name, value] : group) {
if (value == id) {
return name;
}
}
return "unknown";
}
template <typename Type>
inline Type ToEnum(const std::string& canonicalization) {
const auto group = EnumMetadata<Type>::Canonicalizations();
for (auto& [name, value] : group) {
if (name == canonicalization) {
return value;
}
}
return {};
}
} // namespace Settings
#undef ENUM
#undef PAIR
#undef PAIR_1
#undef PAIR_2
#undef PAIR_3
#undef PAIR_4
#undef PAIR_5
#undef PAIR_6
#undef PAIR_7
#undef PAIR_8
#undef PAIR_9
#undef PAIR_10
#undef PAIR_12
#undef PAIR_13
#undef PAIR_14
#undef PAIR_15
#undef PAIR_16
#undef PAIR_17
#undef PAIR_18
#undef PAIR_19
#undef PAIR_20
#undef PAIR_22
#undef PAIR_23
#undef PAIR_24
#undef PAIR_25
#undef PAIR_26
#undef PAIR_27
#undef PAIR_28
#undef PAIR_29
#undef PAIR_30
#undef PAIR_32
#undef PAIR_33
#undef PAIR_34
#undef PAIR_35
#undef PAIR_36
#undef PAIR_37
#undef PAIR_38
#undef PAIR_39
#undef PAIR_40
#undef PAIR_42
#undef PAIR_43
#undef PAIR_44
#undef PAIR_45

View File

@ -0,0 +1,394 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <limits>
#include <map>
#include <optional>
#include <stdexcept>
#include <string>
#include <typeindex>
#include <typeinfo>
#include "common/common_types.h"
#include "common/settings_common.h"
#include "common/settings_enums.h"
namespace Settings {
/** The Setting class is a simple resource manager. It defines a label and default value
* alongside the actual value of the setting for simpler and less-error prone use with frontend
* configurations. Specifying a default value and label is required. A minimum and maximum range
* can be specified for sanitization.
*/
template <typename Type, bool ranged = false>
class Setting : public BasicSetting {
protected:
Setting() = default;
public:
/**
* Sets a default value, label, and setting value.
*
* @param linkage Setting registry
* @param default_val Initial value of the setting, and default value of the setting
* @param name Label for the setting
* @param category_ Category of the setting AKA INI group
* @param specialization_ Suggestion for how frontend implementations represent this in a config
* @param save_ Suggests that this should or should not be saved to a frontend config file
* @param runtime_modifiable_ Suggests whether this is modifiable while a guest is loaded
* @param other_setting_ A second Setting to associate to this one in metadata
*/
explicit Setting(Linkage& linkage, const Type& default_val, const std::string& name,
Category category_, u32 specialization_ = Specialization::Default,
bool save_ = true, bool runtime_modifiable_ = false,
BasicSetting* other_setting_ = nullptr)
requires(!ranged)
: BasicSetting(linkage, name, category_, save_, runtime_modifiable_, specialization_,
other_setting_),
value{default_val}, default_value{default_val} {}
virtual ~Setting() = default;
/**
* Sets a default value, minimum value, maximum value, and label.
*
* @param linkage Setting registry
* @param default_val Initial value of the setting, and default value of the setting
* @param min_val Sets the minimum allowed value of the setting
* @param max_val Sets the maximum allowed value of the setting
* @param name Label for the setting
* @param category_ Category of the setting AKA INI group
* @param specialization_ Suggestion for how frontend implementations represent this in a config
* @param save_ Suggests that this should or should not be saved to a frontend config file
* @param runtime_modifiable_ Suggests whether this is modifiable while a guest is loaded
* @param other_setting_ A second Setting to associate to this one in metadata
*/
explicit Setting(Linkage& linkage, const Type& default_val, const Type& min_val,
const Type& max_val, const std::string& name, Category category_,
u32 specialization_ = Specialization::Default, bool save_ = true,
bool runtime_modifiable_ = false, BasicSetting* other_setting_ = nullptr)
requires(ranged)
: BasicSetting(linkage, name, category_, save_, runtime_modifiable_, specialization_,
other_setting_),
value{default_val}, default_value{default_val}, maximum{max_val}, minimum{min_val} {}
/**
* Returns a reference to the setting's value.
*
* @returns A reference to the setting
*/
[[nodiscard]] virtual const Type& GetValue() const {
return value;
}
/**
* Sets the setting to the given value.
*
* @param val The desired value
*/
virtual void SetValue(const Type& val) {
Type temp{ranged ? std::clamp(val, minimum, maximum) : val};
std::swap(value, temp);
}
/**
* Returns the value that this setting was created with.
*
* @returns A reference to the default value
*/
[[nodiscard]] const Type& GetDefault() const {
return default_value;
}
[[nodiscard]] constexpr bool IsEnum() const override {
return std::is_enum_v<Type>;
}
protected:
[[nodiscard]] std::string ToString(const Type& value_) const {
if constexpr (std::is_same_v<Type, std::string>) {
return value_;
} else if constexpr (std::is_same_v<Type, std::optional<u32>>) {
return value_.has_value() ? std::to_string(*value_) : "none";
} else if constexpr (std::is_same_v<Type, bool>) {
return value_ ? "true" : "false";
} else if constexpr (std::is_same_v<Type, AudioEngine>) {
// Compatibility with old AudioEngine setting being a string
return CanonicalizeEnum(value_);
} else {
return std::to_string(static_cast<u64>(value_));
}
}
public:
/**
* Converts the value of the setting to a std::string. Respects the global state if the setting
* has one.
*
* @returns The current setting as a std::string
*/
[[nodiscard]] std::string ToString() const override {
return ToString(this->GetValue());
}
/**
* Returns the default value of the setting as a std::string.
*
* @returns The default value as a string.
*/
[[nodiscard]] std::string DefaultToString() const override {
return ToString(default_value);
}
/**
* Assigns a value to the setting.
*
* @param val The desired setting value
*
* @returns A reference to the setting
*/
virtual const Type& operator=(const Type& val) {
Type temp{ranged ? std::clamp(val, minimum, maximum) : val};
std::swap(value, temp);
return value;
}
/**
* Returns a reference to the setting.
*
* @returns A reference to the setting
*/
explicit virtual operator const Type&() const {
return value;
}
/**
* Converts the given value to the Setting's type of value. Uses SetValue to enter the setting,
* thus respecting its constraints.
*
* @param input The desired value
*/
void LoadString(const std::string& input) override final {
if (input.empty()) {
this->SetValue(this->GetDefault());
return;
}
try {
if constexpr (std::is_same_v<Type, std::string>) {
this->SetValue(input);
} else if constexpr (std::is_same_v<Type, std::optional<u32>>) {
this->SetValue(static_cast<u32>(std::stoul(input)));
} else if constexpr (std::is_same_v<Type, bool>) {
this->SetValue(input == "true");
} else if constexpr (std::is_same_v<Type, AudioEngine>) {
this->SetValue(ToEnum<Type>(input));
} else {
this->SetValue(static_cast<Type>(std::stoll(input)));
}
} catch (std::invalid_argument&) {
this->SetValue(this->GetDefault());
}
}
[[nodiscard]] std::string Canonicalize() const override final {
if constexpr (std::is_enum_v<Type>) {
return CanonicalizeEnum(this->GetValue());
} else {
return ToString(this->GetValue());
}
}
/**
* Gives us another way to identify the setting without having to go through a string.
*
* @returns the type_index of the setting's type
*/
[[nodiscard]] std::type_index TypeId() const override final {
return std::type_index(typeid(Type));
}
[[nodiscard]] constexpr u32 EnumIndex() const override final {
if constexpr (std::is_enum_v<Type>) {
return EnumMetadata<Type>::Index();
} else {
return std::numeric_limits<u32>::max();
}
}
[[nodiscard]] std::string MinVal() const override final {
return this->ToString(minimum);
}
[[nodiscard]] std::string MaxVal() const override final {
return this->ToString(maximum);
}
[[nodiscard]] constexpr bool Ranged() const override {
return ranged;
}
protected:
Type value{}; ///< The setting
const Type default_value{}; ///< The default value
const Type maximum{}; ///< Maximum allowed value of the setting
const Type minimum{}; ///< Minimum allowed value of the setting
};
/**
* The SwitchableSetting class is a slightly more complex version of the Setting class. This adds a
* custom setting to switch to when a guest application specifically requires it. The effect is that
* other components of the emulator can access the setting's intended value without any need for the
* component to ask whether the custom or global setting is needed at the moment.
*
* By default, the global setting is used.
*/
template <typename Type, bool ranged = false>
class SwitchableSetting : virtual public Setting<Type, ranged> {
public:
/**
* Sets a default value, label, and setting value.
*
* @param linkage Setting registry
* @param default_val Initial value of the setting, and default value of the setting
* @param name Label for the setting
* @param category_ Category of the setting AKA INI group
* @param specialization_ Suggestion for how frontend implementations represent this in a config
* @param save_ Suggests that this should or should not be saved to a frontend config file
* @param runtime_modifiable_ Suggests whether this is modifiable while a guest is loaded
* @param other_setting_ A second Setting to associate to this one in metadata
*/
template <typename T = BasicSetting>
explicit SwitchableSetting(Linkage& linkage, const Type& default_val, const std::string& name,
Category category_, u32 specialization_ = Specialization::Default,
bool save_ = true, bool runtime_modifiable_ = false,
typename std::enable_if<!ranged, T*>::type other_setting_ = nullptr)
: Setting<Type, false>{
linkage, default_val, name, category_, specialization_,
save_, runtime_modifiable_, other_setting_} {
linkage.restore_functions.emplace_back([this]() { this->SetGlobal(true); });
}
virtual ~SwitchableSetting() = default;
/**
* Sets a default value, minimum value, maximum value, and label.
*
* @param linkage Setting registry
* @param default_val Initial value of the setting, and default value of the setting
* @param min_val Sets the minimum allowed value of the setting
* @param max_val Sets the maximum allowed value of the setting
* @param name Label for the setting
* @param category_ Category of the setting AKA INI group
* @param specialization_ Suggestion for how frontend implementations represent this in a config
* @param save_ Suggests that this should or should not be saved to a frontend config file
* @param runtime_modifiable_ Suggests whether this is modifiable while a guest is loaded
* @param other_setting_ A second Setting to associate to this one in metadata
*/
template <typename T = BasicSetting>
explicit SwitchableSetting(Linkage& linkage, const Type& default_val, const Type& min_val,
const Type& max_val, const std::string& name, Category category_,
u32 specialization_ = Specialization::Default, bool save_ = true,
bool runtime_modifiable_ = false,
typename std::enable_if<ranged, T*>::type other_setting_ = nullptr)
: Setting<Type, true>{linkage, default_val, min_val,
max_val, name, category_,
specialization_, save_, runtime_modifiable_,
other_setting_} {
linkage.restore_functions.emplace_back([this]() { this->SetGlobal(true); });
}
/**
* Tells this setting to represent either the global or custom setting when other member
* functions are used.
*
* @param to_global Whether to use the global or custom setting.
*/
void SetGlobal(bool to_global) override final {
use_global = to_global;
}
/**
* Returns whether this setting is using the global setting or not.
*
* @returns The global state
*/
[[nodiscard]] bool UsingGlobal() const override final {
return use_global;
}
/**
* Returns either the global or custom setting depending on the values of this setting's global
* state or if the global value was specifically requested.
*
* @param need_global Request global value regardless of setting's state; defaults to false
*
* @returns The required value of the setting
*/
[[nodiscard]] const Type& GetValue() const override final {
if (use_global) {
return this->value;
}
return custom;
}
[[nodiscard]] const Type& GetValue(bool need_global) const {
if (use_global || need_global) {
return this->value;
}
return custom;
}
/**
* Sets the current setting value depending on the global state.
*
* @param val The new value
*/
void SetValue(const Type& val) override final {
Type temp{ranged ? std::clamp(val, this->minimum, this->maximum) : val};
if (use_global) {
std::swap(this->value, temp);
} else {
std::swap(custom, temp);
}
}
[[nodiscard]] constexpr bool Switchable() const override final {
return true;
}
[[nodiscard]] std::string ToStringGlobal() const override final {
return this->ToString(this->value);
}
/**
* Assigns the current setting value depending on the global state.
*
* @param val The new value
*
* @returns A reference to the current setting value
*/
const Type& operator=(const Type& val) override final {
Type temp{ranged ? std::clamp(val, this->minimum, this->maximum) : val};
if (use_global) {
std::swap(this->value, temp);
return this->value;
}
std::swap(custom, temp);
return custom;
}
/**
* Returns the current setting value depending on the global state.
*
* @returns A reference to the current setting value
*/
explicit operator const Type&() const override final {
if (use_global) {
return this->value;
}
return custom;
}
protected:
bool use_global{true}; ///< The setting's global state
Type custom{}; ///< The custom value of the setting
};
} // namespace Settings

View File

@ -287,7 +287,7 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable*
}
} else {
// Unsafe optimizations
if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Unsafe) {
if (Settings::values.cpu_accuracy.GetValue() == Settings::CpuAccuracy::Unsafe) {
config.unsafe_optimizations = true;
if (Settings::values.cpuopt_unsafe_unfuse_fma) {
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA;
@ -307,7 +307,7 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable*
}
// Curated optimizations
if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Auto) {
if (Settings::values.cpu_accuracy.GetValue() == Settings::CpuAccuracy::Auto) {
config.unsafe_optimizations = true;
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA;
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreStandardFPCRValue;
@ -316,7 +316,7 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable*
}
// Paranoia mode for debugging optimizations
if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Paranoid) {
if (Settings::values.cpu_accuracy.GetValue() == Settings::CpuAccuracy::Paranoid) {
config.unsafe_optimizations = false;
config.optimizations = Dynarmic::no_optimizations;
}

View File

@ -347,7 +347,7 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable*
}
} else {
// Unsafe optimizations
if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Unsafe) {
if (Settings::values.cpu_accuracy.GetValue() == Settings::CpuAccuracy::Unsafe) {
config.unsafe_optimizations = true;
if (Settings::values.cpuopt_unsafe_unfuse_fma) {
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA;
@ -367,7 +367,7 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable*
}
// Curated optimizations
if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Auto) {
if (Settings::values.cpu_accuracy.GetValue() == Settings::CpuAccuracy::Auto) {
config.unsafe_optimizations = true;
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA;
config.fastmem_address_space_bits = 64;
@ -375,7 +375,7 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable*
}
// Paranoia mode for debugging optimizations
if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Paranoid) {
if (Settings::values.cpu_accuracy.GetValue() == Settings::CpuAccuracy::Paranoid) {
config.unsafe_optimizations = false;
config.optimizations = Dynarmic::no_optimizations;
}

View File

@ -12,6 +12,7 @@
#include "common/logging/log.h"
#include "common/microprofile.h"
#include "common/settings.h"
#include "common/settings_enums.h"
#include "common/string_util.h"
#include "core/arm/exclusive_monitor.h"
#include "core/core.h"
@ -140,16 +141,13 @@ struct System::Impl {
device_memory = std::make_unique<Core::DeviceMemory>();
is_multicore = Settings::values.use_multi_core.GetValue();
extended_memory_layout = Settings::values.use_unsafe_extended_memory_layout.GetValue();
extended_memory_layout =
Settings::values.memory_layout_mode.GetValue() != Settings::MemoryLayout::Memory_4Gb;
core_timing.SetMulticore(is_multicore);
core_timing.Initialize([&system]() { system.RegisterHostThread(); });
const auto posix_time = std::chrono::system_clock::now().time_since_epoch();
const auto current_time =
std::chrono::duration_cast<std::chrono::seconds>(posix_time).count();
Settings::values.custom_rtc_differential =
Settings::values.custom_rtc.value_or(current_time) - current_time;
RefreshTime();
// Create a default fs if one doesn't already exist.
if (virtual_filesystem == nullptr) {
@ -172,7 +170,8 @@ struct System::Impl {
void ReinitializeIfNecessary(System& system) {
const bool must_reinitialize =
is_multicore != Settings::values.use_multi_core.GetValue() ||
extended_memory_layout != Settings::values.use_unsafe_extended_memory_layout.GetValue();
extended_memory_layout != (Settings::values.memory_layout_mode.GetValue() !=
Settings::MemoryLayout::Memory_4Gb);
if (!must_reinitialize) {
return;
@ -181,11 +180,22 @@ struct System::Impl {
LOG_DEBUG(Kernel, "Re-initializing");
is_multicore = Settings::values.use_multi_core.GetValue();
extended_memory_layout = Settings::values.use_unsafe_extended_memory_layout.GetValue();
extended_memory_layout =
Settings::values.memory_layout_mode.GetValue() != Settings::MemoryLayout::Memory_4Gb;
Initialize(system);
}
void RefreshTime() {
const auto posix_time = std::chrono::system_clock::now().time_since_epoch();
const auto current_time =
std::chrono::duration_cast<std::chrono::seconds>(posix_time).count();
Settings::values.custom_rtc_differential =
(Settings::values.custom_rtc_enabled ? Settings::values.custom_rtc.GetValue()
: current_time) -
current_time;
}
void Run() {
std::unique_lock<std::mutex> lk(suspend_guard);
@ -1028,6 +1038,8 @@ void System::Exit() {
}
void System::ApplySettings() {
impl->RefreshTime();
if (IsPoweredOn()) {
Renderer().RefreshBaseSettings();
}

View File

@ -68,7 +68,8 @@ NACP::NACP(VirtualFile file) {
NACP::~NACP() = default;
const LanguageEntry& NACP::GetLanguageEntry() const {
Language language = language_to_codes[Settings::values.language_index.GetValue()];
Language language =
language_to_codes[static_cast<s32>(Settings::values.language_index.GetValue())];
{
const auto& language_entry = raw.language_entries.at(static_cast<u8>(language));

View File

@ -626,8 +626,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());
const auto language_code = Service::Set::GetLanguageCodeFromIndex(
static_cast<u32>(Settings::values.language_index.GetValue()));
// Convert to application language and get priority list
const auto application_language =

View File

@ -35,7 +35,7 @@ void RomFSFactory::SetPackedUpdate(VirtualFile update_raw_file) {
update_raw = std::move(update_raw_file);
}
ResultVal<VirtualFile> RomFSFactory::OpenCurrentProcess(u64 current_process_title_id) const {
VirtualFile RomFSFactory::OpenCurrentProcess(u64 current_process_title_id) const {
if (!updatable) {
return file;
}
@ -45,12 +45,11 @@ ResultVal<VirtualFile> RomFSFactory::OpenCurrentProcess(u64 current_process_titl
return patch_manager.PatchRomFS(file, ivfc_offset, ContentRecordType::Program, update_raw);
}
ResultVal<VirtualFile> RomFSFactory::OpenPatchedRomFS(u64 title_id, ContentRecordType type) const {
VirtualFile RomFSFactory::OpenPatchedRomFS(u64 title_id, ContentRecordType type) const {
auto nca = content_provider.GetEntry(title_id, type);
if (nca == nullptr) {
// TODO: Find the right error code to use here
return ResultUnknown;
return nullptr;
}
const PatchManager patch_manager{title_id, filesystem_controller, content_provider};
@ -58,28 +57,20 @@ ResultVal<VirtualFile> RomFSFactory::OpenPatchedRomFS(u64 title_id, ContentRecor
return patch_manager.PatchRomFS(nca->GetRomFS(), nca->GetBaseIVFCOffset(), type);
}
ResultVal<VirtualFile> RomFSFactory::OpenPatchedRomFSWithProgramIndex(
u64 title_id, u8 program_index, ContentRecordType type) const {
VirtualFile RomFSFactory::OpenPatchedRomFSWithProgramIndex(u64 title_id, u8 program_index,
ContentRecordType type) const {
const auto res_title_id = GetBaseTitleIDWithProgramIndex(title_id, program_index);
return OpenPatchedRomFS(res_title_id, type);
}
ResultVal<VirtualFile> RomFSFactory::Open(u64 title_id, StorageId storage,
ContentRecordType type) const {
VirtualFile RomFSFactory::Open(u64 title_id, StorageId storage, ContentRecordType type) const {
const std::shared_ptr<NCA> res = GetEntry(title_id, storage, type);
if (res == nullptr) {
// TODO(DarkLordZach): Find the right error code to use here
return ResultUnknown;
return nullptr;
}
const auto romfs = res->GetRomFS();
if (romfs == nullptr) {
// TODO(DarkLordZach): Find the right error code to use here
return ResultUnknown;
}
return romfs;
return res->GetRomFS();
}
std::shared_ptr<NCA> RomFSFactory::GetEntry(u64 title_id, StorageId storage,

View File

@ -41,13 +41,11 @@ public:
~RomFSFactory();
void SetPackedUpdate(VirtualFile update_raw_file);
[[nodiscard]] ResultVal<VirtualFile> OpenCurrentProcess(u64 current_process_title_id) const;
[[nodiscard]] ResultVal<VirtualFile> OpenPatchedRomFS(u64 title_id,
ContentRecordType type) const;
[[nodiscard]] ResultVal<VirtualFile> OpenPatchedRomFSWithProgramIndex(
u64 title_id, u8 program_index, ContentRecordType type) const;
[[nodiscard]] ResultVal<VirtualFile> Open(u64 title_id, StorageId storage,
ContentRecordType type) const;
[[nodiscard]] VirtualFile OpenCurrentProcess(u64 current_process_title_id) const;
[[nodiscard]] VirtualFile OpenPatchedRomFS(u64 title_id, ContentRecordType type) const;
[[nodiscard]] VirtualFile OpenPatchedRomFSWithProgramIndex(u64 title_id, u8 program_index,
ContentRecordType type) const;
[[nodiscard]] VirtualFile Open(u64 title_id, StorageId storage, ContentRecordType type) const;
private:
[[nodiscard]] std::shared_ptr<NCA> GetEntry(u64 title_id, StorageId storage,

View File

@ -108,26 +108,16 @@ SaveDataFactory::SaveDataFactory(Core::System& system_, VirtualDir save_director
SaveDataFactory::~SaveDataFactory() = default;
ResultVal<VirtualDir> SaveDataFactory::Create(SaveDataSpaceId space,
const SaveDataAttribute& meta) const {
VirtualDir SaveDataFactory::Create(SaveDataSpaceId space, const SaveDataAttribute& meta) const {
PrintSaveDataAttributeWarnings(meta);
const auto save_directory =
GetFullPath(system, dir, space, meta.type, meta.title_id, meta.user_id, meta.save_id);
auto out = dir->CreateDirectoryRelative(save_directory);
// Return an error if the save data doesn't actually exist.
if (out == nullptr) {
// TODO(DarkLordZach): Find out correct error code.
return ResultUnknown;
}
return out;
return dir->CreateDirectoryRelative(save_directory);
}
ResultVal<VirtualDir> SaveDataFactory::Open(SaveDataSpaceId space,
const SaveDataAttribute& meta) const {
VirtualDir SaveDataFactory::Open(SaveDataSpaceId space, const SaveDataAttribute& meta) const {
const auto save_directory =
GetFullPath(system, dir, space, meta.type, meta.title_id, meta.user_id, meta.save_id);
@ -138,12 +128,6 @@ ResultVal<VirtualDir> SaveDataFactory::Open(SaveDataSpaceId space,
return Create(space, meta);
}
// Return an error if the save data doesn't actually exist.
if (out == nullptr) {
// TODO(Subv): Find out correct error code.
return ResultUnknown;
}
return out;
}

View File

@ -89,8 +89,8 @@ public:
explicit SaveDataFactory(Core::System& system_, VirtualDir save_directory_);
~SaveDataFactory();
ResultVal<VirtualDir> Create(SaveDataSpaceId space, const SaveDataAttribute& meta) const;
ResultVal<VirtualDir> Open(SaveDataSpaceId space, const SaveDataAttribute& meta) const;
VirtualDir Create(SaveDataSpaceId space, const SaveDataAttribute& meta) const;
VirtualDir Open(SaveDataSpaceId space, const SaveDataAttribute& meta) const;
VirtualDir GetSaveDataSpaceDirectory(SaveDataSpaceId space) const;

View File

@ -23,7 +23,7 @@ SDMCFactory::SDMCFactory(VirtualDir sd_dir_, VirtualDir sd_mod_dir_)
SDMCFactory::~SDMCFactory() = default;
ResultVal<VirtualDir> SDMCFactory::Open() const {
VirtualDir SDMCFactory::Open() const {
return sd_dir;
}

View File

@ -18,7 +18,7 @@ public:
explicit SDMCFactory(VirtualDir sd_dir_, VirtualDir sd_mod_dir_);
~SDMCFactory();
ResultVal<VirtualDir> Open() const;
VirtualDir Open() const;
VirtualDir GetSDMCModificationLoadRoot(u64 title_id) const;
VirtualDir GetSDMCContentDirectory() const;

View File

@ -289,6 +289,19 @@ enum class GyroscopeZeroDriftMode : u32 {
Tight = 2,
};
// This is nn::settings::system::TouchScreenMode
enum class TouchScreenMode : u32 {
Stylus = 0,
Standard = 1,
};
// This is nn::hid::TouchScreenModeForNx
enum class TouchScreenModeForNx : u8 {
UseSystemSetting,
Finger,
Heat2,
};
// This is nn::hid::NpadStyleTag
struct NpadStyleTag {
union {
@ -334,6 +347,14 @@ struct TouchState {
};
static_assert(sizeof(TouchState) == 0x28, "Touchstate is an invalid size");
// This is nn::hid::TouchScreenConfigurationForNx
struct TouchScreenConfigurationForNx {
TouchScreenModeForNx mode{TouchScreenModeForNx::UseSystemSetting};
INSERT_PADDING_BYTES(0xF);
};
static_assert(sizeof(TouchScreenConfigurationForNx) == 0x10,
"TouchScreenConfigurationForNx is an invalid size");
struct NpadColor {
u8 r{};
u8 g{};
@ -662,6 +683,11 @@ struct MouseState {
};
static_assert(sizeof(MouseState) == 0x28, "MouseState is an invalid size");
struct UniquePadId {
u64 id;
};
static_assert(sizeof(UniquePadId) == 0x8, "UniquePadId is an invalid size");
/// Converts a NpadIdType to an array index.
constexpr size_t NpadIdTypeToIndex(NpadIdType npad_id_type) {
switch (npad_id_type) {

View File

@ -35,13 +35,27 @@ namespace {
using namespace Common::Literals;
u32 GetMemorySizeForInit() {
return Settings::values.use_unsafe_extended_memory_layout ? Smc::MemorySize_8GB
: Smc::MemorySize_4GB;
switch (Settings::values.memory_layout_mode.GetValue()) {
case Settings::MemoryLayout::Memory_4Gb:
return Smc::MemorySize_4GB;
case Settings::MemoryLayout::Memory_6Gb:
return Smc::MemorySize_6GB;
case Settings::MemoryLayout::Memory_8Gb:
return Smc::MemorySize_8GB;
}
return Smc::MemorySize_4GB;
}
Smc::MemoryArrangement GetMemoryArrangeForInit() {
return Settings::values.use_unsafe_extended_memory_layout ? Smc::MemoryArrangement_8GB
: Smc::MemoryArrangement_4GB;
switch (Settings::values.memory_layout_mode.GetValue()) {
case Settings::MemoryLayout::Memory_4Gb:
return Smc::MemoryArrangement_4GB;
case Settings::MemoryLayout::Memory_6Gb:
return Smc::MemoryArrangement_6GB;
case Settings::MemoryLayout::Memory_8Gb:
return Smc::MemoryArrangement_8GB;
}
return Smc::MemoryArrangement_4GB;
}
} // namespace

View File

@ -768,7 +768,7 @@ Result KPageTable::UnmapProcessMemory(KProcessAddress dst_addr, size_t size,
m_memory_block_slab_manager, num_allocator_blocks);
R_TRY(allocator_result);
CASCADE_CODE(Operate(dst_addr, num_pages, KMemoryPermission::None, OperationType::Unmap));
R_TRY(Operate(dst_addr, num_pages, KMemoryPermission::None, OperationType::Unmap));
// Apply the memory block update.
m_memory_block_manager.Update(std::addressof(allocator), dst_addr, num_pages,

View File

@ -81,7 +81,8 @@ Result KProcess::Initialize(KProcess* process, Core::System& system, std::string
process->m_capabilities.InitializeForMetadatalessProcess();
process->m_is_initialized = true;
std::mt19937 rng(Settings::values.rng_seed.GetValue().value_or(std::time(nullptr)));
std::mt19937 rng(Settings::values.rng_seed_enabled ? Settings::values.rng_seed.GetValue()
: static_cast<u32>(std::time(nullptr)));
std::uniform_int_distribution<u64> distribution;
std::generate(process->m_random_entropy.begin(), process->m_random_entropy.end(),
[&] { return distribution(rng); });

View File

@ -283,159 +283,6 @@ private:
u32 description_end;
};
/**
* This is an optional value type. It holds a `Result` and, if that code is ResultSuccess, it
* also holds a result of type `T`. If the code is an error code (not ResultSuccess), then trying
* to access the inner value with operator* is undefined behavior and will assert with Unwrap().
* Users of this class must be cognizant to check the status of the ResultVal with operator bool(),
* Code(), Succeeded() or Failed() prior to accessing the inner value.
*
* An example of how it could be used:
* \code
* ResultVal<int> Frobnicate(float strength) {
* if (strength < 0.f || strength > 1.0f) {
* // Can't frobnicate too weakly or too strongly
* return Result{ErrorModule::Common, 1};
* } else {
* // Frobnicated! Give caller a cookie
* return 42;
* }
* }
* \endcode
*
* \code
* auto frob_result = Frobnicate(0.75f);
* if (frob_result) {
* // Frobbed ok
* printf("My cookie is %d\n", *frob_result);
* } else {
* printf("Guess I overdid it. :( Error code: %ux\n", frob_result.Code().raw);
* }
* \endcode
*/
template <typename T>
class ResultVal {
public:
constexpr ResultVal() : expected{} {}
constexpr ResultVal(Result code) : expected{Common::Unexpected(code)} {}
constexpr ResultVal(ResultRange range) : expected{Common::Unexpected(range)} {}
template <typename U>
constexpr ResultVal(U&& val) : expected{std::forward<U>(val)} {}
template <typename... Args>
constexpr ResultVal(Args&&... args) : expected{std::in_place, std::forward<Args>(args)...} {}
~ResultVal() = default;
constexpr ResultVal(const ResultVal&) = default;
constexpr ResultVal(ResultVal&&) = default;
ResultVal& operator=(const ResultVal&) = default;
ResultVal& operator=(ResultVal&&) = default;
[[nodiscard]] constexpr explicit operator bool() const noexcept {
return expected.has_value();
}
[[nodiscard]] constexpr Result Code() const {
return expected.has_value() ? ResultSuccess : expected.error();
}
[[nodiscard]] constexpr bool Succeeded() const {
return expected.has_value();
}
[[nodiscard]] constexpr bool Failed() const {
return !expected.has_value();
}
[[nodiscard]] constexpr T* operator->() {
return std::addressof(expected.value());
}
[[nodiscard]] constexpr const T* operator->() const {
return std::addressof(expected.value());
}
[[nodiscard]] constexpr T& operator*() & {
return *expected;
}
[[nodiscard]] constexpr const T& operator*() const& {
return *expected;
}
[[nodiscard]] constexpr T&& operator*() && {
return *expected;
}
[[nodiscard]] constexpr const T&& operator*() const&& {
return *expected;
}
[[nodiscard]] constexpr T& Unwrap() & {
ASSERT_MSG(Succeeded(), "Tried to Unwrap empty ResultVal");
return expected.value();
}
[[nodiscard]] constexpr const T& Unwrap() const& {
ASSERT_MSG(Succeeded(), "Tried to Unwrap empty ResultVal");
return expected.value();
}
[[nodiscard]] constexpr T&& Unwrap() && {
ASSERT_MSG(Succeeded(), "Tried to Unwrap empty ResultVal");
return std::move(expected.value());
}
[[nodiscard]] constexpr const T&& Unwrap() const&& {
ASSERT_MSG(Succeeded(), "Tried to Unwrap empty ResultVal");
return std::move(expected.value());
}
template <typename U>
[[nodiscard]] constexpr T ValueOr(U&& v) const& {
return expected.value_or(v);
}
template <typename U>
[[nodiscard]] constexpr T ValueOr(U&& v) && {
return expected.value_or(v);
}
private:
// TODO (Morph): Replace this with C++23 std::expected.
Common::Expected<T, Result> expected;
};
/**
* Check for the success of `source` (which must evaluate to a ResultVal). If it succeeds, unwraps
* the contained value and assigns it to `target`, which can be either an l-value expression or a
* variable declaration. If it fails the return code is returned from the current function. Thus it
* can be used to cascade errors out, achieving something akin to exception handling.
*/
#define CASCADE_RESULT(target, source) \
auto CONCAT2(check_result_L, __LINE__) = source; \
if (CONCAT2(check_result_L, __LINE__).Failed()) { \
return CONCAT2(check_result_L, __LINE__).Code(); \
} \
target = std::move(*CONCAT2(check_result_L, __LINE__))
/**
* Analogous to CASCADE_RESULT, but for a bare Result. The code will be propagated if
* non-success, or discarded otherwise.
*/
#define CASCADE_CODE(source) \
do { \
auto CONCAT2(check_result_L, __LINE__) = source; \
if (CONCAT2(check_result_L, __LINE__).IsError()) { \
return CONCAT2(check_result_L, __LINE__); \
} \
} while (false)
#define R_SUCCEEDED(res) (static_cast<Result>(res).IsSuccess())
#define R_FAILED(res) (static_cast<Result>(res).IsFailure())

View File

@ -765,15 +765,16 @@ Result Module::Interface::InitializeApplicationInfoBase() {
// TODO(ogniK): This should be changed to reflect the target process for when we have multiple
// processes emulated. As we don't actually have pid support we should assume we're just using
// our own process
const auto launch_property =
system.GetARPManager().GetLaunchProperty(system.GetApplicationProcessProgramID());
Glue::ApplicationLaunchProperty launch_property{};
const auto result = system.GetARPManager().GetLaunchProperty(
&launch_property, system.GetApplicationProcessProgramID());
if (launch_property.Failed()) {
if (result != ResultSuccess) {
LOG_ERROR(Service_ACC, "Failed to get launch property");
return Account::ResultInvalidApplication;
}
switch (launch_property->base_game_storage_id) {
switch (launch_property.base_game_storage_id) {
case FileSys::StorageId::GameCard:
application_info.application_type = ApplicationType::GameCard;
break;
@ -785,7 +786,7 @@ Result Module::Interface::InitializeApplicationInfoBase() {
break;
default:
LOG_ERROR(Service_ACC, "Invalid game storage ID! storage_id={}",
launch_property->base_game_storage_id);
launch_property.base_game_storage_id);
return Account::ResultInvalidApplication;
}

View File

@ -1317,6 +1317,50 @@ void ILibraryAppletCreator::CreateHandleStorage(HLERequestContext& ctx) {
rb.PushIpcInterface<IStorage>(system, std::move(memory));
}
ILibraryAppletSelfAccessor::ILibraryAppletSelfAccessor(Core::System& system_)
: ServiceFramework{system_, "ILibraryAppletSelfAccessor"} {
static const FunctionInfo functions[] = {
{0, nullptr, "PopInData"},
{1, nullptr, "PushOutData"},
{2, nullptr, "PopInteractiveInData"},
{3, nullptr, "PushInteractiveOutData"},
{5, nullptr, "GetPopInDataEvent"},
{6, nullptr, "GetPopInteractiveInDataEvent"},
{10, nullptr, "ExitProcessAndReturn"},
{11, nullptr, "GetLibraryAppletInfo"},
{12, nullptr, "GetMainAppletIdentityInfo"},
{13, nullptr, "CanUseApplicationCore"},
{14, nullptr, "GetCallerAppletIdentityInfo"},
{15, nullptr, "GetMainAppletApplicationControlProperty"},
{16, nullptr, "GetMainAppletStorageId"},
{17, nullptr, "GetCallerAppletIdentityInfoStack"},
{18, nullptr, "GetNextReturnDestinationAppletIdentityInfo"},
{19, nullptr, "GetDesirableKeyboardLayout"},
{20, nullptr, "PopExtraStorage"},
{25, nullptr, "GetPopExtraStorageEvent"},
{30, nullptr, "UnpopInData"},
{31, nullptr, "UnpopExtraStorage"},
{40, nullptr, "GetIndirectLayerProducerHandle"},
{50, nullptr, "ReportVisibleError"},
{51, nullptr, "ReportVisibleErrorWithErrorContext"},
{60, nullptr, "GetMainAppletApplicationDesiredLanguage"},
{70, nullptr, "GetCurrentApplicationId"},
{80, nullptr, "RequestExitToSelf"},
{90, nullptr, "CreateApplicationAndPushAndRequestToLaunch"},
{100, nullptr, "CreateGameMovieTrimmer"},
{101, nullptr, "ReserveResourceForMovieOperation"},
{102, nullptr, "UnreserveResourceForMovieOperation"},
{110, nullptr, "GetMainAppletAvailableUsers"},
{120, nullptr, "GetLaunchStorageInfoForDebug"},
{130, nullptr, "GetGpuErrorDetectedSystemEvent"},
{140, nullptr, "SetApplicationMemoryReservation"},
{150, nullptr, "ShouldSetGpuTimeSliceManually"},
};
RegisterHandlers(functions);
}
ILibraryAppletSelfAccessor::~ILibraryAppletSelfAccessor() = default;
IApplicationFunctions::IApplicationFunctions(Core::System& system_)
: ServiceFramework{system_, "IApplicationFunctions"}, service_context{system,
"IApplicationFunctions"} {
@ -1534,11 +1578,13 @@ void IApplicationFunctions::EnsureSaveData(HLERequestContext& ctx) {
attribute.title_id = system.GetApplicationProcessProgramID();
attribute.user_id = user_id;
attribute.type = FileSys::SaveDataType::SaveData;
FileSys::VirtualDir save_data{};
const auto res = system.GetFileSystemController().CreateSaveData(
FileSys::SaveDataSpaceId::NandUser, attribute);
&save_data, FileSys::SaveDataSpaceId::NandUser, attribute);
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(res.Code());
rb.Push(res);
rb.Push<u64>(0);
}
@ -1623,26 +1669,30 @@ void IApplicationFunctions::GetDesiredLanguage(HLERequestContext& ctx) {
auto app_man = ns_am2->GetApplicationManagerInterface();
// Get desired application language
const auto res_lang = app_man->GetApplicationDesiredLanguage(supported_languages);
if (res_lang.Failed()) {
u8 desired_language{};
const auto res_lang =
app_man->GetApplicationDesiredLanguage(&desired_language, supported_languages);
if (res_lang != ResultSuccess) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(res_lang.Code());
rb.Push(res_lang);
return;
}
// Convert to settings language code.
const auto res_code = app_man->ConvertApplicationLanguageToLanguageCode(*res_lang);
if (res_code.Failed()) {
u64 language_code{};
const auto res_code =
app_man->ConvertApplicationLanguageToLanguageCode(&language_code, desired_language);
if (res_code != ResultSuccess) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(res_code.Code());
rb.Push(res_code);
return;
}
LOG_DEBUG(Service_AM, "got desired_language={:016X}", *res_code);
LOG_DEBUG(Service_AM, "got desired_language={:016X}", language_code);
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.Push(*res_code);
rb.Push(language_code);
}
void IApplicationFunctions::IsGamePlayRecordingSupported(HLERequestContext& ctx) {

View File

@ -22,30 +22,6 @@ class Nvnflinger;
namespace Service::AM {
// This is nn::settings::Language
enum SystemLanguage {
Japanese = 0,
English = 1, // en-US
French = 2,
German = 3,
Italian = 4,
Spanish = 5,
Chinese = 6,
Korean = 7,
Dutch = 8,
Portuguese = 9,
Russian = 10,
Taiwanese = 11,
BritishEnglish = 12, // en-GB
CanadianFrench = 13,
LatinAmericanSpanish = 14, // es-419
// 4.0.0+
SimplifiedChinese = 15,
TraditionalChinese = 16,
// 10.1.0+
BrazilianPortuguese = 17,
};
class AppletMessageQueue {
public:
// This is nn::am::AppletMessage
@ -314,6 +290,12 @@ private:
void CreateHandleStorage(HLERequestContext& ctx);
};
class ILibraryAppletSelfAccessor final : public ServiceFramework<ILibraryAppletSelfAccessor> {
public:
explicit ILibraryAppletSelfAccessor(Core::System& system_);
~ILibraryAppletSelfAccessor() override;
};
class IApplicationFunctions final : public ServiceFramework<IApplicationFunctions> {
public:
explicit IApplicationFunctions(Core::System& system_);

View File

@ -26,8 +26,10 @@ public:
{4, &ILibraryAppletProxy::GetDisplayController, "GetDisplayController"},
{10, &ILibraryAppletProxy::GetProcessWindingController, "GetProcessWindingController"},
{11, &ILibraryAppletProxy::GetLibraryAppletCreator, "GetLibraryAppletCreator"},
{20, &ILibraryAppletProxy::GetApplicationFunctions, "GetApplicationFunctions"},
{20, &ILibraryAppletProxy::OpenLibraryAppletSelfAccessor, "OpenLibraryAppletSelfAccessor"},
{21, nullptr, "GetAppletCommonFunctions"},
{22, nullptr, "GetHomeMenuFunctions"},
{23, nullptr, "GetGlobalStateController"},
{1000, &ILibraryAppletProxy::GetDebugFunctions, "GetDebugFunctions"},
};
// clang-format on
@ -100,12 +102,12 @@ private:
rb.PushIpcInterface<ILibraryAppletCreator>(system);
}
void GetApplicationFunctions(HLERequestContext& ctx) {
void OpenLibraryAppletSelfAccessor(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IApplicationFunctions>(system);
rb.PushIpcInterface<ILibraryAppletSelfAccessor>(system);
}
Nvnflinger::Nvnflinger& nvnflinger;

View File

@ -22,13 +22,13 @@ AudCtl::AudCtl(Core::System& system_) : ServiceFramework{system_, "audctl"} {
{9, nullptr, "GetAudioOutputMode"},
{10, nullptr, "SetAudioOutputMode"},
{11, nullptr, "SetForceMutePolicy"},
{12, nullptr, "GetForceMutePolicy"},
{13, nullptr, "GetOutputModeSetting"},
{12, &AudCtl::GetForceMutePolicy, "GetForceMutePolicy"},
{13, &AudCtl::GetOutputModeSetting, "GetOutputModeSetting"},
{14, nullptr, "SetOutputModeSetting"},
{15, nullptr, "SetOutputTarget"},
{16, nullptr, "SetInputTargetForceEnabled"},
{17, nullptr, "SetHeadphoneOutputLevelMode"},
{18, nullptr, "GetHeadphoneOutputLevelMode"},
{18, &AudCtl::GetHeadphoneOutputLevelMode, "GetHeadphoneOutputLevelMode"},
{19, nullptr, "AcquireAudioVolumeUpdateEventForPlayReport"},
{20, nullptr, "AcquireAudioOutputDeviceUpdateEventForPlayReport"},
{21, nullptr, "GetAudioOutputTargetForPlayReport"},
@ -41,7 +41,7 @@ AudCtl::AudCtl(Core::System& system_) : ServiceFramework{system_, "audctl"} {
{28, nullptr, "GetAudioOutputChannelCountForPlayReport"},
{29, nullptr, "BindAudioOutputChannelCountUpdateEventForPlayReport"},
{30, nullptr, "SetSpeakerAutoMuteEnabled"},
{31, nullptr, "IsSpeakerAutoMuteEnabled"},
{31, &AudCtl::IsSpeakerAutoMuteEnabled, "IsSpeakerAutoMuteEnabled"},
{32, nullptr, "GetActiveOutputTarget"},
{33, nullptr, "GetTargetDeviceInfo"},
{34, nullptr, "AcquireTargetNotification"},
@ -96,4 +96,42 @@ void AudCtl::GetTargetVolumeMax(HLERequestContext& ctx) {
rb.Push(target_max_volume);
}
void AudCtl::GetForceMutePolicy(HLERequestContext& ctx) {
LOG_WARNING(Audio, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.PushEnum(ForceMutePolicy::Disable);
}
void AudCtl::GetOutputModeSetting(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto value = rp.Pop<u32>();
LOG_WARNING(Audio, "(STUBBED) called, value={}", value);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.PushEnum(AudioOutputMode::PcmAuto);
}
void AudCtl::GetHeadphoneOutputLevelMode(HLERequestContext& ctx) {
LOG_WARNING(Audio, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.PushEnum(HeadphoneOutputLevelMode::Normal);
}
void AudCtl::IsSpeakerAutoMuteEnabled(HLERequestContext& ctx) {
const bool is_speaker_auto_mute_enabled = false;
LOG_WARNING(Audio, "(STUBBED) called, is_speaker_auto_mute_enabled={}",
is_speaker_auto_mute_enabled);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push<u8>(is_speaker_auto_mute_enabled);
}
} // namespace Service::Audio

View File

@ -17,8 +17,30 @@ public:
~AudCtl() override;
private:
enum class AudioOutputMode {
Invalid,
Pcm1ch,
Pcm2ch,
Pcm6ch,
PcmAuto,
};
enum class ForceMutePolicy {
Disable,
SpeakerMuteOnHeadphoneUnplugged,
};
enum class HeadphoneOutputLevelMode {
Normal,
HighPower,
};
void GetTargetVolumeMin(HLERequestContext& ctx);
void GetTargetVolumeMax(HLERequestContext& ctx);
void GetForceMutePolicy(HLERequestContext& ctx);
void GetOutputModeSetting(HLERequestContext& ctx);
void GetHeadphoneOutputLevelMode(HLERequestContext& ctx);
void IsSpeakerAutoMuteEnabled(HLERequestContext& ctx);
};
} // namespace Service::Audio

View File

@ -57,8 +57,8 @@ Result VfsDirectoryServiceWrapper::CreateFile(const std::string& path_, u64 size
return FileSys::ERROR_PATH_NOT_FOUND;
}
const auto entry_type = GetEntryType(path);
if (entry_type.Code() == ResultSuccess) {
FileSys::EntryType entry_type{};
if (GetEntryType(&entry_type, path) == ResultSuccess) {
return FileSys::ERROR_PATH_ALREADY_EXISTS;
}
@ -210,8 +210,8 @@ Result VfsDirectoryServiceWrapper::RenameDirectory(const std::string& src_path_,
return ResultUnknown;
}
ResultVal<FileSys::VirtualFile> VfsDirectoryServiceWrapper::OpenFile(const std::string& path_,
FileSys::Mode mode) const {
Result VfsDirectoryServiceWrapper::OpenFile(FileSys::VirtualFile* out_file,
const std::string& path_, FileSys::Mode mode) const {
const std::string path(Common::FS::SanitizePath(path_));
std::string_view npath = path;
while (!npath.empty() && (npath[0] == '/' || npath[0] == '\\')) {
@ -224,50 +224,68 @@ ResultVal<FileSys::VirtualFile> VfsDirectoryServiceWrapper::OpenFile(const std::
}
if (mode == FileSys::Mode::Append) {
return std::make_shared<FileSys::OffsetVfsFile>(file, 0, file->GetSize());
*out_file = std::make_shared<FileSys::OffsetVfsFile>(file, 0, file->GetSize());
} else {
*out_file = file;
}
return file;
return ResultSuccess;
}
ResultVal<FileSys::VirtualDir> VfsDirectoryServiceWrapper::OpenDirectory(const std::string& path_) {
Result VfsDirectoryServiceWrapper::OpenDirectory(FileSys::VirtualDir* out_directory,
const std::string& path_) {
std::string path(Common::FS::SanitizePath(path_));
auto dir = GetDirectoryRelativeWrapped(backing, path);
if (dir == nullptr) {
// TODO(DarkLordZach): Find a better error code for this
return FileSys::ERROR_PATH_NOT_FOUND;
}
return dir;
*out_directory = dir;
return ResultSuccess;
}
ResultVal<FileSys::EntryType> VfsDirectoryServiceWrapper::GetEntryType(
const std::string& path_) const {
Result VfsDirectoryServiceWrapper::GetEntryType(FileSys::EntryType* out_entry_type,
const std::string& path_) const {
std::string path(Common::FS::SanitizePath(path_));
auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path));
if (dir == nullptr)
return FileSys::ERROR_PATH_NOT_FOUND;
auto filename = Common::FS::GetFilename(path);
// TODO(Subv): Some games use the '/' path, find out what this means.
if (filename.empty())
return FileSys::EntryType::Directory;
if (dir->GetFile(filename) != nullptr)
return FileSys::EntryType::File;
if (dir->GetSubdirectory(filename) != nullptr)
return FileSys::EntryType::Directory;
return FileSys::ERROR_PATH_NOT_FOUND;
}
ResultVal<FileSys::FileTimeStampRaw> VfsDirectoryServiceWrapper::GetFileTimeStampRaw(
const std::string& path) const {
auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path));
if (dir == nullptr) {
return FileSys::ERROR_PATH_NOT_FOUND;
}
if (GetEntryType(path).Failed()) {
auto filename = Common::FS::GetFilename(path);
// TODO(Subv): Some games use the '/' path, find out what this means.
if (filename.empty()) {
*out_entry_type = FileSys::EntryType::Directory;
return ResultSuccess;
}
if (dir->GetFile(filename) != nullptr) {
*out_entry_type = FileSys::EntryType::File;
return ResultSuccess;
}
if (dir->GetSubdirectory(filename) != nullptr) {
*out_entry_type = FileSys::EntryType::Directory;
return ResultSuccess;
}
return FileSys::ERROR_PATH_NOT_FOUND;
}
Result VfsDirectoryServiceWrapper::GetFileTimeStampRaw(
FileSys::FileTimeStampRaw* out_file_time_stamp_raw, const std::string& path) const {
auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path));
if (dir == nullptr) {
return FileSys::ERROR_PATH_NOT_FOUND;
}
return dir->GetFileTimeStamp(Common::FS::GetFilename(path));
FileSys::EntryType entry_type;
if (GetEntryType(&entry_type, path) != ResultSuccess) {
return FileSys::ERROR_PATH_NOT_FOUND;
}
*out_file_time_stamp_raw = dir->GetFileTimeStamp(Common::FS::GetFilename(path));
return ResultSuccess;
}
FileSystemController::FileSystemController(Core::System& system_) : system{system_} {}
@ -310,57 +328,54 @@ void FileSystemController::SetPackedUpdate(FileSys::VirtualFile update_raw) {
romfs_factory->SetPackedUpdate(std::move(update_raw));
}
ResultVal<FileSys::VirtualFile> FileSystemController::OpenRomFSCurrentProcess() const {
FileSys::VirtualFile FileSystemController::OpenRomFSCurrentProcess() const {
LOG_TRACE(Service_FS, "Opening RomFS for current process");
if (romfs_factory == nullptr) {
// TODO(bunnei): Find a better error code for this
return ResultUnknown;
return nullptr;
}
return romfs_factory->OpenCurrentProcess(system.GetApplicationProcessProgramID());
}
ResultVal<FileSys::VirtualFile> FileSystemController::OpenPatchedRomFS(
u64 title_id, FileSys::ContentRecordType type) const {
FileSys::VirtualFile FileSystemController::OpenPatchedRomFS(u64 title_id,
FileSys::ContentRecordType type) const {
LOG_TRACE(Service_FS, "Opening patched RomFS for title_id={:016X}", title_id);
if (romfs_factory == nullptr) {
// TODO: Find a better error code for this
return ResultUnknown;
return nullptr;
}
return romfs_factory->OpenPatchedRomFS(title_id, type);
}
ResultVal<FileSys::VirtualFile> FileSystemController::OpenPatchedRomFSWithProgramIndex(
FileSys::VirtualFile FileSystemController::OpenPatchedRomFSWithProgramIndex(
u64 title_id, u8 program_index, FileSys::ContentRecordType type) const {
LOG_TRACE(Service_FS, "Opening patched RomFS for title_id={:016X}, program_index={}", title_id,
program_index);
if (romfs_factory == nullptr) {
// TODO: Find a better error code for this
return ResultUnknown;
return nullptr;
}
return romfs_factory->OpenPatchedRomFSWithProgramIndex(title_id, program_index, type);
}
ResultVal<FileSys::VirtualFile> FileSystemController::OpenRomFS(
u64 title_id, FileSys::StorageId storage_id, FileSys::ContentRecordType type) const {
FileSys::VirtualFile FileSystemController::OpenRomFS(u64 title_id, FileSys::StorageId storage_id,
FileSys::ContentRecordType type) const {
LOG_TRACE(Service_FS, "Opening RomFS for title_id={:016X}, storage_id={:02X}, type={:02X}",
title_id, storage_id, type);
if (romfs_factory == nullptr) {
// TODO(bunnei): Find a better error code for this
return ResultUnknown;
return nullptr;
}
return romfs_factory->Open(title_id, storage_id, type);
}
ResultVal<FileSys::VirtualDir> FileSystemController::CreateSaveData(
FileSys::SaveDataSpaceId space, const FileSys::SaveDataAttribute& save_struct) const {
Result FileSystemController::CreateSaveData(FileSys::VirtualDir* out_save_data,
FileSys::SaveDataSpaceId space,
const FileSys::SaveDataAttribute& save_struct) const {
LOG_TRACE(Service_FS, "Creating Save Data for space_id={:01X}, save_struct={}", space,
save_struct.DebugInfo());
@ -368,11 +383,18 @@ ResultVal<FileSys::VirtualDir> FileSystemController::CreateSaveData(
return FileSys::ERROR_ENTITY_NOT_FOUND;
}
return save_data_factory->Create(space, save_struct);
auto save_data = save_data_factory->Create(space, save_struct);
if (save_data == nullptr) {
return FileSys::ERROR_ENTITY_NOT_FOUND;
}
*out_save_data = save_data;
return ResultSuccess;
}
ResultVal<FileSys::VirtualDir> FileSystemController::OpenSaveData(
FileSys::SaveDataSpaceId space, const FileSys::SaveDataAttribute& attribute) const {
Result FileSystemController::OpenSaveData(FileSys::VirtualDir* out_save_data,
FileSys::SaveDataSpaceId space,
const FileSys::SaveDataAttribute& attribute) const {
LOG_TRACE(Service_FS, "Opening Save Data for space_id={:01X}, save_struct={}", space,
attribute.DebugInfo());
@ -380,32 +402,50 @@ ResultVal<FileSys::VirtualDir> FileSystemController::OpenSaveData(
return FileSys::ERROR_ENTITY_NOT_FOUND;
}
return save_data_factory->Open(space, attribute);
auto save_data = save_data_factory->Open(space, attribute);
if (save_data == nullptr) {
return FileSys::ERROR_ENTITY_NOT_FOUND;
}
*out_save_data = save_data;
return ResultSuccess;
}
ResultVal<FileSys::VirtualDir> FileSystemController::OpenSaveDataSpace(
FileSys::SaveDataSpaceId space) const {
Result FileSystemController::OpenSaveDataSpace(FileSys::VirtualDir* out_save_data_space,
FileSys::SaveDataSpaceId space) const {
LOG_TRACE(Service_FS, "Opening Save Data Space for space_id={:01X}", space);
if (save_data_factory == nullptr) {
return FileSys::ERROR_ENTITY_NOT_FOUND;
}
return save_data_factory->GetSaveDataSpaceDirectory(space);
auto save_data_space = save_data_factory->GetSaveDataSpaceDirectory(space);
if (save_data_space == nullptr) {
return FileSys::ERROR_ENTITY_NOT_FOUND;
}
*out_save_data_space = save_data_space;
return ResultSuccess;
}
ResultVal<FileSys::VirtualDir> FileSystemController::OpenSDMC() const {
Result FileSystemController::OpenSDMC(FileSys::VirtualDir* out_sdmc) const {
LOG_TRACE(Service_FS, "Opening SDMC");
if (sdmc_factory == nullptr) {
return FileSys::ERROR_SD_CARD_NOT_FOUND;
}
return sdmc_factory->Open();
auto sdmc = sdmc_factory->Open();
if (sdmc == nullptr) {
return FileSys::ERROR_SD_CARD_NOT_FOUND;
}
*out_sdmc = sdmc;
return ResultSuccess;
}
ResultVal<FileSys::VirtualDir> FileSystemController::OpenBISPartition(
FileSys::BisPartitionId id) const {
Result FileSystemController::OpenBISPartition(FileSys::VirtualDir* out_bis_partition,
FileSys::BisPartitionId id) const {
LOG_TRACE(Service_FS, "Opening BIS Partition with id={:08X}", id);
if (bis_factory == nullptr) {
@ -417,11 +457,12 @@ ResultVal<FileSys::VirtualDir> FileSystemController::OpenBISPartition(
return FileSys::ERROR_INVALID_ARGUMENT;
}
return part;
*out_bis_partition = part;
return ResultSuccess;
}
ResultVal<FileSys::VirtualFile> FileSystemController::OpenBISPartitionStorage(
FileSys::BisPartitionId id) const {
Result FileSystemController::OpenBISPartitionStorage(
FileSys::VirtualFile* out_bis_partition_storage, FileSys::BisPartitionId id) const {
LOG_TRACE(Service_FS, "Opening BIS Partition Storage with id={:08X}", id);
if (bis_factory == nullptr) {
@ -433,7 +474,8 @@ ResultVal<FileSys::VirtualFile> FileSystemController::OpenBISPartitionStorage(
return FileSys::ERROR_INVALID_ARGUMENT;
}
return part;
*out_bis_partition_storage = part;
return ResultSuccess;
}
u64 FileSystemController::GetFreeSpaceSize(FileSys::StorageId id) const {

View File

@ -64,21 +64,24 @@ public:
Result RegisterBIS(std::unique_ptr<FileSys::BISFactory>&& factory);
void SetPackedUpdate(FileSys::VirtualFile update_raw);
ResultVal<FileSys::VirtualFile> OpenRomFSCurrentProcess() const;
ResultVal<FileSys::VirtualFile> OpenPatchedRomFS(u64 title_id,
FileSys::ContentRecordType type) const;
ResultVal<FileSys::VirtualFile> OpenPatchedRomFSWithProgramIndex(
u64 title_id, u8 program_index, FileSys::ContentRecordType type) const;
ResultVal<FileSys::VirtualFile> OpenRomFS(u64 title_id, FileSys::StorageId storage_id,
FileSys::ContentRecordType type) const;
ResultVal<FileSys::VirtualDir> CreateSaveData(
FileSys::SaveDataSpaceId space, const FileSys::SaveDataAttribute& save_struct) const;
ResultVal<FileSys::VirtualDir> OpenSaveData(
FileSys::SaveDataSpaceId space, const FileSys::SaveDataAttribute& save_struct) const;
ResultVal<FileSys::VirtualDir> OpenSaveDataSpace(FileSys::SaveDataSpaceId space) const;
ResultVal<FileSys::VirtualDir> OpenSDMC() const;
ResultVal<FileSys::VirtualDir> OpenBISPartition(FileSys::BisPartitionId id) const;
ResultVal<FileSys::VirtualFile> OpenBISPartitionStorage(FileSys::BisPartitionId id) const;
FileSys::VirtualFile OpenRomFSCurrentProcess() const;
FileSys::VirtualFile OpenPatchedRomFS(u64 title_id, FileSys::ContentRecordType type) const;
FileSys::VirtualFile OpenPatchedRomFSWithProgramIndex(u64 title_id, u8 program_index,
FileSys::ContentRecordType type) const;
FileSys::VirtualFile OpenRomFS(u64 title_id, FileSys::StorageId storage_id,
FileSys::ContentRecordType type) const;
Result CreateSaveData(FileSys::VirtualDir* out_save_data, FileSys::SaveDataSpaceId space,
const FileSys::SaveDataAttribute& save_struct) const;
Result OpenSaveData(FileSys::VirtualDir* out_save_data, FileSys::SaveDataSpaceId space,
const FileSys::SaveDataAttribute& save_struct) const;
Result OpenSaveDataSpace(FileSys::VirtualDir* out_save_data_space,
FileSys::SaveDataSpaceId space) const;
Result OpenSDMC(FileSys::VirtualDir* out_sdmc) const;
Result OpenBISPartition(FileSys::VirtualDir* out_bis_partition,
FileSys::BisPartitionId id) const;
Result OpenBISPartitionStorage(FileSys::VirtualFile* out_bis_partition_storage,
FileSys::BisPartitionId id) const;
u64 GetFreeSpaceSize(FileSys::StorageId id) const;
u64 GetTotalSpaceSize(FileSys::StorageId id) const;
@ -224,26 +227,28 @@ public:
* @param mode Mode to open the file with
* @return Opened file, or error code
*/
ResultVal<FileSys::VirtualFile> OpenFile(const std::string& path, FileSys::Mode mode) const;
Result OpenFile(FileSys::VirtualFile* out_file, const std::string& path,
FileSys::Mode mode) const;
/**
* Open a directory specified by its path
* @param path Path relative to the archive
* @return Opened directory, or error code
*/
ResultVal<FileSys::VirtualDir> OpenDirectory(const std::string& path);
Result OpenDirectory(FileSys::VirtualDir* out_directory, const std::string& path);
/**
* Get the type of the specified path
* @return The type of the specified path or error code
*/
ResultVal<FileSys::EntryType> GetEntryType(const std::string& path) const;
Result GetEntryType(FileSys::EntryType* out_entry_type, const std::string& path) const;
/**
* Get the timestamp of the specified path
* @return The timestamp of the specified path or error code
*/
ResultVal<FileSys::FileTimeStampRaw> GetFileTimeStampRaw(const std::string& path) const;
Result GetFileTimeStampRaw(FileSys::FileTimeStampRaw* out_time_stamp_raw,
const std::string& path) const;
private:
FileSys::VirtualDir backing;

View File

@ -419,14 +419,15 @@ public:
LOG_DEBUG(Service_FS, "called. file={}, mode={}", name, mode);
auto result = backend.OpenFile(name, mode);
if (result.Failed()) {
FileSys::VirtualFile vfs_file{};
auto result = backend.OpenFile(&vfs_file, name, mode);
if (result != ResultSuccess) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result.Code());
rb.Push(result);
return;
}
auto file = std::make_shared<IFile>(system, result.Unwrap());
auto file = std::make_shared<IFile>(system, vfs_file);
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
@ -444,14 +445,15 @@ public:
LOG_DEBUG(Service_FS, "called. directory={}, filter={}", name, filter_flags);
auto result = backend.OpenDirectory(name);
if (result.Failed()) {
FileSys::VirtualDir vfs_dir{};
auto result = backend.OpenDirectory(&vfs_dir, name);
if (result != ResultSuccess) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result.Code());
rb.Push(result);
return;
}
auto directory = std::make_shared<IDirectory>(system, result.Unwrap());
auto directory = std::make_shared<IDirectory>(system, vfs_dir);
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
@ -464,16 +466,17 @@ public:
LOG_DEBUG(Service_FS, "called. file={}", name);
auto result = backend.GetEntryType(name);
if (result.Failed()) {
FileSys::EntryType vfs_entry_type{};
auto result = backend.GetEntryType(&vfs_entry_type, name);
if (result != ResultSuccess) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result.Code());
rb.Push(result);
return;
}
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push<u32>(static_cast<u32>(*result));
rb.Push<u32>(static_cast<u32>(vfs_entry_type));
}
void Commit(HLERequestContext& ctx) {
@ -505,16 +508,17 @@ public:
LOG_WARNING(Service_FS, "(Partial Implementation) called. file={}", name);
auto result = backend.GetFileTimeStampRaw(name);
if (result.Failed()) {
FileSys::FileTimeStampRaw vfs_timestamp{};
auto result = backend.GetFileTimeStampRaw(&vfs_timestamp, name);
if (result != ResultSuccess) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result.Code());
rb.Push(result);
return;
}
IPC::ResponseBuilder rb{ctx, 10};
rb.Push(ResultSuccess);
rb.PushRaw(*result);
rb.PushRaw(vfs_timestamp);
}
private:
@ -572,14 +576,15 @@ private:
}
void FindAllSaves(FileSys::SaveDataSpaceId space) {
const auto save_root = fsc.OpenSaveDataSpace(space);
FileSys::VirtualDir save_root{};
const auto result = fsc.OpenSaveDataSpace(&save_root, space);
if (save_root.Failed() || *save_root == nullptr) {
if (result != ResultSuccess || save_root == nullptr) {
LOG_ERROR(Service_FS, "The save root for the space_id={:02X} was invalid!", space);
return;
}
for (const auto& type : (*save_root)->GetSubdirectories()) {
for (const auto& type : save_root->GetSubdirectories()) {
if (type->GetName() == "save") {
for (const auto& save_id : type->GetSubdirectories()) {
for (const auto& user_id : save_id->GetSubdirectories()) {
@ -837,9 +842,11 @@ void FSP_SRV::OpenFileSystemWithPatch(HLERequestContext& ctx) {
void FSP_SRV::OpenSdCardFileSystem(HLERequestContext& ctx) {
LOG_DEBUG(Service_FS, "called");
auto filesystem =
std::make_shared<IFileSystem>(system, fsc.OpenSDMC().Unwrap(),
SizeGetter::FromStorageId(fsc, FileSys::StorageId::SdCard));
FileSys::VirtualDir sdmc_dir{};
fsc.OpenSDMC(&sdmc_dir);
auto filesystem = std::make_shared<IFileSystem>(
system, sdmc_dir, SizeGetter::FromStorageId(fsc, FileSys::StorageId::SdCard));
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
@ -856,7 +863,8 @@ void FSP_SRV::CreateSaveDataFileSystem(HLERequestContext& ctx) {
LOG_DEBUG(Service_FS, "called save_struct = {}, uid = {:016X}{:016X}", save_struct.DebugInfo(),
uid[1], uid[0]);
fsc.CreateSaveData(FileSys::SaveDataSpaceId::NandUser, save_struct);
FileSys::VirtualDir save_data_dir{};
fsc.CreateSaveData(&save_data_dir, FileSys::SaveDataSpaceId::NandUser, save_struct);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
@ -874,8 +882,9 @@ void FSP_SRV::OpenSaveDataFileSystem(HLERequestContext& ctx) {
LOG_INFO(Service_FS, "called.");
auto dir = fsc.OpenSaveData(parameters.space_id, parameters.attribute);
if (dir.Failed()) {
FileSys::VirtualDir dir{};
auto result = fsc.OpenSaveData(&dir, parameters.space_id, parameters.attribute);
if (result != ResultSuccess) {
IPC::ResponseBuilder rb{ctx, 2, 0, 0};
rb.Push(FileSys::ERROR_ENTITY_NOT_FOUND);
return;
@ -899,8 +908,8 @@ void FSP_SRV::OpenSaveDataFileSystem(HLERequestContext& ctx) {
ASSERT(false);
}
auto filesystem = std::make_shared<IFileSystem>(system, std::move(dir.Unwrap()),
SizeGetter::FromStorageId(fsc, id));
auto filesystem =
std::make_shared<IFileSystem>(system, std::move(dir), SizeGetter::FromStorageId(fsc, id));
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
@ -970,7 +979,7 @@ void FSP_SRV::OpenDataStorageByCurrentProcess(HLERequestContext& ctx) {
if (!romfs) {
auto current_romfs = fsc.OpenRomFSCurrentProcess();
if (current_romfs.Failed()) {
if (!current_romfs) {
// TODO (bunnei): Find the right error code to use here
LOG_CRITICAL(Service_FS, "no file system interface available!");
IPC::ResponseBuilder rb{ctx, 2};
@ -978,7 +987,7 @@ void FSP_SRV::OpenDataStorageByCurrentProcess(HLERequestContext& ctx) {
return;
}
romfs = current_romfs.Unwrap();
romfs = current_romfs;
}
auto storage = std::make_shared<IStorage>(system, romfs);
@ -999,7 +1008,7 @@ void FSP_SRV::OpenDataStorageByDataId(HLERequestContext& ctx) {
auto data = fsc.OpenRomFS(title_id, storage_id, FileSys::ContentRecordType::Data);
if (data.Failed()) {
if (!data) {
const auto archive = FileSys::SystemArchive::SynthesizeSystemArchive(title_id);
if (archive != nullptr) {
@ -1021,7 +1030,7 @@ void FSP_SRV::OpenDataStorageByDataId(HLERequestContext& ctx) {
const FileSys::PatchManager pm{title_id, fsc, content_provider};
auto storage = std::make_shared<IStorage>(
system, pm.PatchRomFS(std::move(data.Unwrap()), 0, FileSys::ContentRecordType::Data));
system, pm.PatchRomFS(std::move(data), 0, FileSys::ContentRecordType::Data));
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
@ -1051,7 +1060,7 @@ void FSP_SRV::OpenDataStorageWithProgramIndex(HLERequestContext& ctx) {
fsc.OpenPatchedRomFSWithProgramIndex(system.GetApplicationProcessProgramID(), program_index,
FileSys::ContentRecordType::Program);
if (patched_romfs.Failed()) {
if (!patched_romfs) {
// TODO: Find the right error code to use here
LOG_ERROR(Service_FS, "could not open storage with program_index={}", program_index);
@ -1060,7 +1069,7 @@ void FSP_SRV::OpenDataStorageWithProgramIndex(HLERequestContext& ctx) {
return;
}
auto storage = std::make_shared<IStorage>(system, std::move(patched_romfs.Unwrap()));
auto storage = std::make_shared<IStorage>(system, std::move(patched_romfs));
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);

View File

@ -65,18 +65,19 @@ void ARP_R::GetApplicationLaunchProperty(HLERequestContext& ctx) {
return;
}
const auto res = manager.GetLaunchProperty(*title_id);
ApplicationLaunchProperty launch_property{};
const auto res = manager.GetLaunchProperty(&launch_property, *title_id);
if (res.Failed()) {
if (res != ResultSuccess) {
LOG_ERROR(Service_ARP, "Failed to get launch property!");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(res.Code());
rb.Push(res);
return;
}
IPC::ResponseBuilder rb{ctx, 6};
rb.Push(ResultSuccess);
rb.PushRaw(*res);
rb.PushRaw(launch_property);
}
void ARP_R::GetApplicationLaunchPropertyWithApplicationId(HLERequestContext& ctx) {
@ -85,18 +86,19 @@ void ARP_R::GetApplicationLaunchPropertyWithApplicationId(HLERequestContext& ctx
LOG_DEBUG(Service_ARP, "called, title_id={:016X}", title_id);
const auto res = manager.GetLaunchProperty(title_id);
ApplicationLaunchProperty launch_property{};
const auto res = manager.GetLaunchProperty(&launch_property, title_id);
if (res.Failed()) {
if (res != ResultSuccess) {
LOG_ERROR(Service_ARP, "Failed to get launch property!");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(res.Code());
rb.Push(res);
return;
}
IPC::ResponseBuilder rb{ctx, 6};
rb.Push(ResultSuccess);
rb.PushRaw(*res);
rb.PushRaw(launch_property);
}
void ARP_R::GetApplicationControlProperty(HLERequestContext& ctx) {
@ -113,16 +115,17 @@ void ARP_R::GetApplicationControlProperty(HLERequestContext& ctx) {
return;
}
const auto res = manager.GetControlProperty(*title_id);
std::vector<u8> nacp_data;
const auto res = manager.GetControlProperty(&nacp_data, *title_id);
if (res.Failed()) {
if (res != ResultSuccess) {
LOG_ERROR(Service_ARP, "Failed to get control property!");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(res.Code());
rb.Push(res);
return;
}
ctx.WriteBuffer(*res);
ctx.WriteBuffer(nacp_data);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
@ -134,16 +137,17 @@ void ARP_R::GetApplicationControlPropertyWithApplicationId(HLERequestContext& ct
LOG_DEBUG(Service_ARP, "called, title_id={:016X}", title_id);
const auto res = manager.GetControlProperty(title_id);
std::vector<u8> nacp_data;
const auto res = manager.GetControlProperty(&nacp_data, title_id);
if (res.Failed()) {
if (res != ResultSuccess) {
LOG_ERROR(Service_ARP, "Failed to get control property!");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(res.Code());
rb.Push(res);
return;
}
ctx.WriteBuffer(*res);
ctx.WriteBuffer(nacp_data);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);

View File

@ -15,7 +15,8 @@ ARPManager::ARPManager() = default;
ARPManager::~ARPManager() = default;
ResultVal<ApplicationLaunchProperty> ARPManager::GetLaunchProperty(u64 title_id) const {
Result ARPManager::GetLaunchProperty(ApplicationLaunchProperty* out_launch_property,
u64 title_id) const {
if (title_id == 0) {
return Glue::ResultInvalidProcessId;
}
@ -25,10 +26,11 @@ ResultVal<ApplicationLaunchProperty> ARPManager::GetLaunchProperty(u64 title_id)
return Glue::ResultProcessIdNotRegistered;
}
return iter->second.launch;
*out_launch_property = iter->second.launch;
return ResultSuccess;
}
ResultVal<std::vector<u8>> ARPManager::GetControlProperty(u64 title_id) const {
Result ARPManager::GetControlProperty(std::vector<u8>* out_control_property, u64 title_id) const {
if (title_id == 0) {
return Glue::ResultInvalidProcessId;
}
@ -38,7 +40,8 @@ ResultVal<std::vector<u8>> ARPManager::GetControlProperty(u64 title_id) const {
return Glue::ResultProcessIdNotRegistered;
}
return iter->second.control;
*out_control_property = iter->second.control;
return ResultSuccess;
}
Result ARPManager::Register(u64 title_id, ApplicationLaunchProperty launch,

View File

@ -32,12 +32,12 @@ public:
// Returns the ApplicationLaunchProperty corresponding to the provided title ID if it was
// previously registered, otherwise ResultProcessIdNotRegistered if it was never registered or
// ResultInvalidProcessId if the title ID is 0.
ResultVal<ApplicationLaunchProperty> GetLaunchProperty(u64 title_id) const;
Result GetLaunchProperty(ApplicationLaunchProperty* out_launch_property, u64 title_id) const;
// Returns a vector of the raw bytes of NACP data (necessarily 0x4000 in size) corresponding to
// the provided title ID if it was previously registered, otherwise ResultProcessIdNotRegistered
// if it was never registered or ResultInvalidProcessId if the title ID is 0.
ResultVal<std::vector<u8>> GetControlProperty(u64 title_id) const;
Result GetControlProperty(std::vector<u8>* out_control_property, u64 title_id) const;
// Adds a new entry to the internal database with the provided parameters, returning
// ResultProcessIdNotRegistered if attempting to re-register a title ID without an intermediate

View File

@ -16,22 +16,6 @@ class EmulatedConsole;
namespace Service::HID {
class Controller_Touchscreen final : public ControllerBase {
public:
// This is nn::hid::TouchScreenModeForNx
enum class TouchScreenModeForNx : u8 {
UseSystemSetting,
Finger,
Heat2,
};
// This is nn::hid::TouchScreenConfigurationForNx
struct TouchScreenConfigurationForNx {
TouchScreenModeForNx mode{TouchScreenModeForNx::UseSystemSetting};
INSERT_PADDING_BYTES_NOINIT(0x7);
INSERT_PADDING_BYTES_NOINIT(0xF); // Reserved
};
static_assert(sizeof(TouchScreenConfigurationForNx) == 0x17,
"TouchScreenConfigurationForNx is an invalid size");
explicit Controller_Touchscreen(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_);
~Controller_Touchscreen() override;

View File

@ -2368,7 +2368,7 @@ void Hid::GetNpadCommunicationMode(HLERequestContext& ctx) {
void Hid::SetTouchScreenConfiguration(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto touchscreen_mode{rp.PopRaw<Controller_Touchscreen::TouchScreenConfigurationForNx>()};
const auto touchscreen_mode{rp.PopRaw<Core::HID::TouchScreenConfigurationForNx>()};
const auto applet_resource_user_id{rp.Pop<u64>()};
LOG_WARNING(Service_HID, "(STUBBED) called, touchscreen_mode={}, applet_resource_user_id={}",
@ -2543,7 +2543,8 @@ public:
class HidSys final : public ServiceFramework<HidSys> {
public:
explicit HidSys(Core::System& system_) : ServiceFramework{system_, "hid:sys"} {
explicit HidSys(Core::System& system_)
: ServiceFramework{system_, "hid:sys"}, service_context{system_, "hid:sys"} {
// clang-format off
static const FunctionInfo functions[] = {
{31, nullptr, "SendKeyboardLockKeyEvent"},
@ -2568,7 +2569,7 @@ public:
{303, &HidSys::ApplyNpadSystemCommonPolicy, "ApplyNpadSystemCommonPolicy"},
{304, nullptr, "EnableAssigningSingleOnSlSrPress"},
{305, nullptr, "DisableAssigningSingleOnSlSrPress"},
{306, nullptr, "GetLastActiveNpad"},
{306, &HidSys::GetLastActiveNpad, "GetLastActiveNpad"},
{307, nullptr, "GetNpadSystemExtStyle"},
{308, nullptr, "ApplyNpadSystemCommonPolicyFull"},
{309, nullptr, "GetNpadFullKeyGripColor"},
@ -2624,7 +2625,7 @@ public:
{700, nullptr, "ActivateUniquePad"},
{702, nullptr, "AcquireUniquePadConnectionEventHandle"},
{703, nullptr, "GetUniquePadIds"},
{751, nullptr, "AcquireJoyDetachOnBluetoothOffEventHandle"},
{751, &HidSys::AcquireJoyDetachOnBluetoothOffEventHandle, "AcquireJoyDetachOnBluetoothOffEventHandle"},
{800, nullptr, "ListSixAxisSensorHandles"},
{801, nullptr, "IsSixAxisSensorUserCalibrationSupported"},
{802, nullptr, "ResetSixAxisSensorCalibrationValues"},
@ -2650,7 +2651,7 @@ public:
{830, nullptr, "SetNotificationLedPattern"},
{831, nullptr, "SetNotificationLedPatternWithTimeout"},
{832, nullptr, "PrepareHidsForNotificationWake"},
{850, nullptr, "IsUsbFullKeyControllerEnabled"},
{850, &HidSys::IsUsbFullKeyControllerEnabled, "IsUsbFullKeyControllerEnabled"},
{851, nullptr, "EnableUsbFullKeyController"},
{852, nullptr, "IsUsbConnected"},
{870, nullptr, "IsHandheldButtonPressedOnConsoleMode"},
@ -2682,7 +2683,7 @@ public:
{1150, nullptr, "SetTouchScreenMagnification"},
{1151, nullptr, "GetTouchScreenFirmwareVersion"},
{1152, nullptr, "SetTouchScreenDefaultConfiguration"},
{1153, nullptr, "GetTouchScreenDefaultConfiguration"},
{1153, &HidSys::GetTouchScreenDefaultConfiguration, "GetTouchScreenDefaultConfiguration"},
{1154, nullptr, "IsFirmwareAvailableForNotification"},
{1155, nullptr, "SetForceHandheldStyleVibration"},
{1156, nullptr, "SendConnectionTriggerWithoutTimeoutEvent"},
@ -2749,6 +2750,8 @@ public:
// clang-format on
RegisterHandlers(functions);
joy_detach_event = service_context.CreateEvent("HidSys::JoyDetachEvent");
}
private:
@ -2760,17 +2763,66 @@ private:
rb.Push(ResultSuccess);
}
void GetLastActiveNpad(HLERequestContext& ctx) {
LOG_DEBUG(Service_HID, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.PushEnum(Core::HID::NpadIdType::Handheld);
}
void GetUniquePadsFromNpad(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto npad_id_type{rp.PopEnum<Core::HID::NpadIdType>()};
const s64 total_entries = 0;
LOG_WARNING(Service_HID, "(STUBBED) called, npad_id_type={}", npad_id_type);
const std::vector<Core::HID::UniquePadId> unique_pads{};
ctx.WriteBuffer(unique_pads);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(total_entries);
rb.Push(static_cast<u32>(unique_pads.size()));
}
void AcquireJoyDetachOnBluetoothOffEventHandle(HLERequestContext& ctx) {
LOG_INFO(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(ResultSuccess);
rb.PushCopyObjects(joy_detach_event->GetReadableEvent());
}
void IsUsbFullKeyControllerEnabled(HLERequestContext& ctx) {
const bool is_enabled = false;
LOG_WARNING(Service_HID, "(STUBBED) called, is_enabled={}", is_enabled);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(is_enabled);
}
void GetTouchScreenDefaultConfiguration(HLERequestContext& ctx) {
LOG_WARNING(Service_HID, "(STUBBED) called");
Core::HID::TouchScreenConfigurationForNx touchscreen_config{
.mode = Core::HID::TouchScreenModeForNx::Finger,
};
if (touchscreen_config.mode != Core::HID::TouchScreenModeForNx::Heat2 &&
touchscreen_config.mode != Core::HID::TouchScreenModeForNx::Finger) {
touchscreen_config.mode = Core::HID::TouchScreenModeForNx::UseSystemSetting;
}
IPC::ResponseBuilder rb{ctx, 6};
rb.Push(ResultSuccess);
rb.PushRaw(touchscreen_config);
}
Kernel::KEvent* joy_detach_event;
KernelHelpers::ServiceContext service_context;
};
void LoopProcess(Core::System& system) {

View File

@ -357,7 +357,8 @@ public:
return ResultSuccess;
}
ResultVal<VAddr> MapProcessCodeMemory(Kernel::KProcess* process, VAddr base_addr, u64 size) {
Result MapProcessCodeMemory(VAddr* out_map_location, Kernel::KProcess* process, VAddr base_addr,
u64 size) {
auto& page_table{process->GetPageTable()};
VAddr addr{};
@ -372,20 +373,21 @@ public:
R_TRY(result);
if (ValidateRegionForMap(page_table, addr, size)) {
return addr;
*out_map_location = addr;
return ResultSuccess;
}
}
return ERROR_INSUFFICIENT_ADDRESS_SPACE;
}
ResultVal<VAddr> MapNro(Kernel::KProcess* process, VAddr nro_addr, std::size_t nro_size,
VAddr bss_addr, std::size_t bss_size, std::size_t size) {
Result MapNro(VAddr* out_map_location, Kernel::KProcess* process, VAddr nro_addr,
std::size_t nro_size, VAddr bss_addr, std::size_t bss_size, std::size_t size) {
for (std::size_t retry = 0; retry < MAXIMUM_MAP_RETRIES; retry++) {
auto& page_table{process->GetPageTable()};
VAddr addr{};
CASCADE_RESULT(addr, MapProcessCodeMemory(process, nro_addr, nro_size));
R_TRY(MapProcessCodeMemory(&addr, process, nro_addr, nro_size));
if (bss_size) {
auto block_guard = detail::ScopeExit([&] {
@ -411,7 +413,8 @@ public:
}
if (ValidateRegionForMap(page_table, addr, size)) {
return addr;
*out_map_location = addr;
return ResultSuccess;
}
}
@ -437,9 +440,9 @@ public:
CopyCode(nro_addr + nro_header.segment_headers[DATA_INDEX].memory_offset, data_start,
nro_header.segment_headers[DATA_INDEX].memory_size);
CASCADE_CODE(process->GetPageTable().SetProcessMemoryPermission(
R_TRY(process->GetPageTable().SetProcessMemoryPermission(
text_start, ro_start - text_start, Kernel::Svc::MemoryPermission::ReadExecute));
CASCADE_CODE(process->GetPageTable().SetProcessMemoryPermission(
R_TRY(process->GetPageTable().SetProcessMemoryPermission(
ro_start, data_start - ro_start, Kernel::Svc::MemoryPermission::Read));
return process->GetPageTable().SetProcessMemoryPermission(
@ -542,31 +545,32 @@ public:
}
// Map memory for the NRO
const auto map_result{MapNro(system.ApplicationProcess(), nro_address, nro_size,
bss_address, bss_size, nro_size + bss_size)};
if (map_result.Failed()) {
VAddr map_location{};
const auto map_result{MapNro(&map_location, system.ApplicationProcess(), nro_address,
nro_size, bss_address, bss_size, nro_size + bss_size)};
if (map_result != ResultSuccess) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(map_result.Code());
rb.Push(map_result);
}
// Load the NRO into the mapped memory
if (const auto result{
LoadNro(system.ApplicationProcess(), header, nro_address, *map_result)};
LoadNro(system.ApplicationProcess(), header, nro_address, map_location)};
result.IsError()) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(map_result.Code());
rb.Push(result);
}
// Track the loaded NRO
nro.insert_or_assign(*map_result,
NROInfo{hash, *map_result, nro_size, bss_address, bss_size,
nro.insert_or_assign(map_location,
NROInfo{hash, map_location, nro_size, bss_address, bss_size,
header.segment_headers[TEXT_INDEX].memory_size,
header.segment_headers[RO_INDEX].memory_size,
header.segment_headers[DATA_INDEX].memory_size, nro_address});
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.Push(*map_result);
rb.Push(map_location);
}
Result UnmapNro(const NROInfo& info) {
@ -574,19 +578,19 @@ public:
auto& page_table{system.ApplicationProcess()->GetPageTable()};
if (info.bss_size != 0) {
CASCADE_CODE(page_table.UnmapCodeMemory(
R_TRY(page_table.UnmapCodeMemory(
info.nro_address + info.text_size + info.ro_size + info.data_size, info.bss_address,
info.bss_size, Kernel::KPageTable::ICacheInvalidationStrategy::InvalidateRange));
}
CASCADE_CODE(page_table.UnmapCodeMemory(
R_TRY(page_table.UnmapCodeMemory(
info.nro_address + info.text_size + info.ro_size,
info.src_addr + info.text_size + info.ro_size, info.data_size,
Kernel::KPageTable::ICacheInvalidationStrategy::InvalidateRange));
CASCADE_CODE(page_table.UnmapCodeMemory(
R_TRY(page_table.UnmapCodeMemory(
info.nro_address + info.text_size, info.src_addr + info.text_size, info.ro_size,
Kernel::KPageTable::ICacheInvalidationStrategy::InvalidateRange));
CASCADE_CODE(page_table.UnmapCodeMemory(
R_TRY(page_table.UnmapCodeMemory(
info.nro_address, info.src_addr, info.text_size,
Kernel::KPageTable::ICacheInvalidationStrategy::InvalidateRange));
return ResultSuccess;

View File

@ -101,20 +101,14 @@ private:
LOG_DEBUG(Service_Mii, "called with source_flag={}", source_flag);
const auto result{manager.GetDefault(source_flag)};
if (result.Failed()) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result.Code());
return;
}
if (result->size() > 0) {
ctx.WriteBuffer(SerializeArray(*result));
const auto default_miis{manager.GetDefault(source_flag)};
if (default_miis.size() > 0) {
ctx.WriteBuffer(SerializeArray(default_miis));
}
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push<u32>(static_cast<u32>(result->size()));
rb.Push<u32>(static_cast<u32>(default_miis.size()));
}
void Get1(HLERequestContext& ctx) {
@ -123,15 +117,10 @@ private:
LOG_DEBUG(Service_Mii, "called with source_flag={}", source_flag);
const auto result{manager.GetDefault(source_flag)};
if (result.Failed()) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result.Code());
return;
}
const auto default_miis{manager.GetDefault(source_flag)};
std::vector<CharInfo> values;
for (const auto& element : *result) {
for (const auto& element : default_miis) {
values.emplace_back(element.info);
}
@ -139,7 +128,7 @@ private:
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push<u32>(static_cast<u32>(result->size()));
rb.Push<u32>(static_cast<u32>(default_miis.size()));
}
void UpdateLatest(HLERequestContext& ctx) {
@ -149,16 +138,17 @@ private:
LOG_DEBUG(Service_Mii, "called with source_flag={}", source_flag);
const auto result{manager.UpdateLatest(info, source_flag)};
if (result.Failed()) {
CharInfo new_char_info{};
const auto result{manager.UpdateLatest(&new_char_info, info, source_flag)};
if (result != ResultSuccess) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result.Code());
rb.Push(result);
return;
}
IPC::ResponseBuilder rb{ctx, 2 + sizeof(CharInfo) / sizeof(u32)};
rb.Push(ResultSuccess);
rb.PushRaw<CharInfo>(*result);
rb.PushRaw<CharInfo>(new_char_info);
}
void BuildRandom(HLERequestContext& ctx) {

View File

@ -409,8 +409,7 @@ u32 MiiManager::GetCount(SourceFlag source_flag) const {
return static_cast<u32>(count);
}
ResultVal<CharInfo> MiiManager::UpdateLatest([[maybe_unused]] const CharInfo& info,
SourceFlag source_flag) {
Result MiiManager::UpdateLatest(CharInfo* out_info, const CharInfo& info, SourceFlag source_flag) {
if ((source_flag & SourceFlag::Database) == SourceFlag::None) {
return ERROR_CANNOT_FIND_ENTRY;
}
@ -672,7 +671,7 @@ bool MiiManager::ValidateV3Info(const Ver3StoreData& mii_v3) const {
return is_valid;
}
ResultVal<std::vector<MiiInfoElement>> MiiManager::GetDefault(SourceFlag source_flag) {
std::vector<MiiInfoElement> MiiManager::GetDefault(SourceFlag source_flag) {
std::vector<MiiInfoElement> result;
if ((source_flag & SourceFlag::Default) == SourceFlag::None) {

View File

@ -19,12 +19,12 @@ public:
bool CheckAndResetUpdateCounter(SourceFlag source_flag, u64& current_update_counter);
bool IsFullDatabase() const;
u32 GetCount(SourceFlag source_flag) const;
ResultVal<CharInfo> UpdateLatest(const CharInfo& info, SourceFlag source_flag);
Result UpdateLatest(CharInfo* out_info, const CharInfo& info, SourceFlag source_flag);
CharInfo BuildRandom(Age age, Gender gender, Race race);
CharInfo BuildDefault(std::size_t index);
CharInfo ConvertV3ToCharInfo(const Ver3StoreData& mii_v3) const;
bool ValidateV3Info(const Ver3StoreData& mii_v3) const;
ResultVal<std::vector<MiiInfoElement>> GetDefault(SourceFlag source_flag);
std::vector<MiiInfoElement> GetDefault(SourceFlag source_flag);
Result GetIndex(const CharInfo& info, u32& index);
// This is nn::mii::detail::Ver::StoreDataRaw::BuildFromStoreData

View File

@ -392,24 +392,25 @@ void IApplicationManagerInterface::GetApplicationDesiredLanguage(HLERequestConte
IPC::RequestParser rp{ctx};
const auto supported_languages = rp.Pop<u32>();
const auto res = GetApplicationDesiredLanguage(supported_languages);
if (res.Succeeded()) {
u8 desired_language{};
const auto res = GetApplicationDesiredLanguage(&desired_language, supported_languages);
if (res == ResultSuccess) {
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push<u32>(*res);
rb.Push<u32>(desired_language);
} else {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(res.Code());
rb.Push(res);
}
}
ResultVal<u8> IApplicationManagerInterface::GetApplicationDesiredLanguage(
const u32 supported_languages) {
Result IApplicationManagerInterface::GetApplicationDesiredLanguage(u8* out_desired_language,
const u32 supported_languages) {
LOG_DEBUG(Service_NS, "called with supported_languages={:08X}", supported_languages);
// Get language code from settings
const auto language_code =
Set::GetLanguageCodeFromIndex(Settings::values.language_index.GetValue());
Set::GetLanguageCodeFromIndex(static_cast<s32>(Settings::values.language_index.GetValue()));
// Convert to application language, get priority list
const auto application_language = ConvertToApplicationLanguage(language_code);
@ -430,7 +431,8 @@ ResultVal<u8> IApplicationManagerInterface::GetApplicationDesiredLanguage(
for (const auto lang : *priority_list) {
const auto supported_flag = GetSupportedLanguageFlag(lang);
if (supported_languages == 0 || (supported_languages & supported_flag) == supported_flag) {
return static_cast<u8>(lang);
*out_desired_language = static_cast<u8>(lang);
return ResultSuccess;
}
}
@ -444,19 +446,20 @@ void IApplicationManagerInterface::ConvertApplicationLanguageToLanguageCode(
IPC::RequestParser rp{ctx};
const auto application_language = rp.Pop<u8>();
const auto res = ConvertApplicationLanguageToLanguageCode(application_language);
if (res.Succeeded()) {
u64 language_code{};
const auto res = ConvertApplicationLanguageToLanguageCode(&language_code, application_language);
if (res == ResultSuccess) {
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.Push(*res);
rb.Push(language_code);
} else {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(res.Code());
rb.Push(res);
}
}
ResultVal<u64> IApplicationManagerInterface::ConvertApplicationLanguageToLanguageCode(
u8 application_language) {
Result IApplicationManagerInterface::ConvertApplicationLanguageToLanguageCode(
u64* out_language_code, u8 application_language) {
const auto language_code =
ConvertToLanguageCode(static_cast<ApplicationLanguage>(application_language));
if (language_code == std::nullopt) {
@ -464,7 +467,8 @@ ResultVal<u64> IApplicationManagerInterface::ConvertApplicationLanguageToLanguag
return Service::NS::ResultApplicationLanguageNotFound;
}
return static_cast<u64>(*language_code);
*out_language_code = static_cast<u64>(*language_code);
return ResultSuccess;
}
IApplicationVersionInterface::IApplicationVersionInterface(Core::System& system_)
@ -618,12 +622,13 @@ void IReadOnlyApplicationControlDataInterface::GetApplicationControlData(HLERequ
static_assert(sizeof(RequestParameters) == 0x10, "RequestParameters has incorrect size.");
IPC::RequestParser rp{ctx};
std::vector<u8> nacp_data{};
const auto parameters{rp.PopRaw<RequestParameters>()};
const auto nacp_data{system.GetARPManager().GetControlProperty(parameters.application_id)};
const auto result = nacp_data ? ResultSuccess : ResultUnknown;
const auto result =
system.GetARPManager().GetControlProperty(&nacp_data, parameters.application_id);
if (nacp_data) {
ctx.WriteBuffer(nacp_data->data(), nacp_data->size());
if (result == ResultSuccess) {
ctx.WriteBuffer(nacp_data.data(), nacp_data.size());
}
IPC::ResponseBuilder rb{ctx, 2};

View File

@ -28,8 +28,9 @@ public:
explicit IApplicationManagerInterface(Core::System& system_);
~IApplicationManagerInterface() override;
ResultVal<u8> GetApplicationDesiredLanguage(u32 supported_languages);
ResultVal<u64> ConvertApplicationLanguageToLanguageCode(u8 application_language);
Result GetApplicationDesiredLanguage(u8* out_desired_language, u32 supported_languages);
Result ConvertApplicationLanguageToLanguageCode(u64* out_language_code,
u8 application_language);
private:
void GetApplicationControlData(HLERequestContext& ctx);

View File

@ -449,6 +449,7 @@ Status BufferQueueProducer::QueueBuffer(s32 slot, const QueueBufferInput& input,
case NativeWindowScalingMode::ScaleToWindow:
case NativeWindowScalingMode::ScaleCrop:
case NativeWindowScalingMode::NoScaleCrop:
case NativeWindowScalingMode::PreserveAspectRatio:
break;
default:
LOG_ERROR(Service_Nvnflinger, "unknown scaling mode {}", scaling_mode);

View File

@ -183,7 +183,7 @@ std::optional<u32> Nvnflinger::FindBufferQueueId(u64 display_id, u64 layer_id) {
return layer->GetBinderId();
}
ResultVal<Kernel::KReadableEvent*> Nvnflinger::FindVsyncEvent(u64 display_id) {
Result Nvnflinger::FindVsyncEvent(Kernel::KReadableEvent** out_vsync_event, u64 display_id) {
const auto lock_guard = Lock();
auto* const display = FindDisplay(display_id);
@ -191,7 +191,7 @@ ResultVal<Kernel::KReadableEvent*> Nvnflinger::FindVsyncEvent(u64 display_id) {
return VI::ResultNotFound;
}
return display->GetVSyncEvent();
return display->GetVSyncEvent(out_vsync_event);
}
VI::Display* Nvnflinger::FindDisplay(u64 display_id) {

View File

@ -82,7 +82,7 @@ public:
///
/// If an invalid display ID is provided, then VI::ResultNotFound is returned.
/// If the vsync event has already been retrieved, then VI::ResultPermissionDenied is returned.
[[nodiscard]] ResultVal<Kernel::KReadableEvent*> FindVsyncEvent(u64 display_id);
[[nodiscard]] Result FindVsyncEvent(Kernel::KReadableEvent** out_vsync_event, u64 display_id);
/// Performs a composition request to the emulated nvidia GPU and triggers the vsync events when
/// finished.

View File

@ -41,6 +41,7 @@ enum class NativeWindowScalingMode : s32 {
ScaleToWindow = 1,
ScaleCrop = 2,
NoScaleCrop = 3,
PreserveAspectRatio = 4,
};
/// Transform parameter for QueueBuffer

View File

@ -8,15 +8,16 @@
namespace Service::OLSC {
class OLSC final : public ServiceFramework<OLSC> {
class IOlscServiceForApplication final : public ServiceFramework<IOlscServiceForApplication> {
public:
explicit OLSC(Core::System& system_) : ServiceFramework{system_, "olsc:u"} {
explicit IOlscServiceForApplication(Core::System& system_)
: ServiceFramework{system_, "olsc:u"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &OLSC::Initialize, "Initialize"},
{0, &IOlscServiceForApplication::Initialize, "Initialize"},
{10, nullptr, "VerifySaveDataBackupLicenseAsync"},
{13, &OLSC::GetSaveDataBackupSetting, "GetSaveDataBackupSetting"},
{14, &OLSC::SetSaveDataBackupSettingEnabled, "SetSaveDataBackupSettingEnabled"},
{13, &IOlscServiceForApplication::GetSaveDataBackupSetting, "GetSaveDataBackupSetting"},
{14, &IOlscServiceForApplication::SetSaveDataBackupSettingEnabled, "SetSaveDataBackupSettingEnabled"},
{15, nullptr, "SetCustomData"},
{16, nullptr, "DeleteSaveDataBackupSetting"},
{18, nullptr, "GetSaveDataBackupInfoCache"},
@ -72,10 +73,155 @@ private:
bool initialized{};
};
class INativeHandleHolder final : public ServiceFramework<INativeHandleHolder> {
public:
explicit INativeHandleHolder(Core::System& system_)
: ServiceFramework{system_, "INativeHandleHolder"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "GetNativeHandle"},
};
// clang-format on
RegisterHandlers(functions);
}
};
class ITransferTaskListController final : public ServiceFramework<ITransferTaskListController> {
public:
explicit ITransferTaskListController(Core::System& system_)
: ServiceFramework{system_, "ITransferTaskListController"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "Unknown0"},
{1, nullptr, "Unknown1"},
{2, nullptr, "Unknown2"},
{3, nullptr, "Unknown3"},
{4, nullptr, "Unknown4"},
{5, &ITransferTaskListController::GetNativeHandleHolder , "GetNativeHandleHolder"},
{6, nullptr, "Unknown6"},
{7, nullptr, "Unknown7"},
{8, nullptr, "GetRemoteStorageController"},
{9, &ITransferTaskListController::GetNativeHandleHolder, "GetNativeHandleHolder2"},
{10, nullptr, "Unknown10"},
{11, nullptr, "Unknown11"},
{12, nullptr, "Unknown12"},
{13, nullptr, "Unknown13"},
{14, nullptr, "Unknown14"},
{15, nullptr, "Unknown15"},
{16, nullptr, "Unknown16"},
{17, nullptr, "Unknown17"},
{18, nullptr, "Unknown18"},
{19, nullptr, "Unknown19"},
{20, nullptr, "Unknown20"},
{21, nullptr, "Unknown21"},
{22, nullptr, "Unknown22"},
{23, nullptr, "Unknown23"},
{24, nullptr, "Unknown24"},
{25, nullptr, "Unknown25"},
};
// clang-format on
RegisterHandlers(functions);
}
private:
void GetNativeHandleHolder(HLERequestContext& ctx) {
LOG_INFO(Service_OLSC, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<INativeHandleHolder>(system);
}
};
class IOlscServiceForSystemService final : public ServiceFramework<IOlscServiceForSystemService> {
public:
explicit IOlscServiceForSystemService(Core::System& system_)
: ServiceFramework{system_, "olsc:s"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &IOlscServiceForSystemService::OpenTransferTaskListController, "OpenTransferTaskListController"},
{1, nullptr, "OpenRemoteStorageController"},
{2, nullptr, "OpenDaemonController"},
{10, nullptr, "Unknown10"},
{11, nullptr, "Unknown11"},
{12, nullptr, "Unknown12"},
{13, nullptr, "Unknown13"},
{100, nullptr, "ListLastTransferTaskErrorInfo"},
{101, nullptr, "GetLastErrorInfoCount"},
{102, nullptr, "RemoveLastErrorInfoOld"},
{103, nullptr, "GetLastErrorInfo"},
{104, nullptr, "GetLastErrorEventHolder"},
{105, nullptr, "GetLastTransferTaskErrorInfo"},
{200, nullptr, "GetDataTransferPolicyInfo"},
{201, nullptr, "RemoveDataTransferPolicyInfo"},
{202, nullptr, "UpdateDataTransferPolicyOld"},
{203, nullptr, "UpdateDataTransferPolicy"},
{204, nullptr, "CleanupDataTransferPolicyInfo"},
{205, nullptr, "RequestDataTransferPolicy"},
{300, nullptr, "GetAutoTransferSeriesInfo"},
{301, nullptr, "UpdateAutoTransferSeriesInfo"},
{400, nullptr, "CleanupSaveDataArchiveInfoType1"},
{900, nullptr, "CleanupTransferTask"},
{902, nullptr, "CleanupSeriesInfoType0"},
{903, nullptr, "CleanupSaveDataArchiveInfoType0"},
{904, nullptr, "CleanupApplicationAutoTransferSetting"},
{905, nullptr, "CleanupErrorHistory"},
{906, nullptr, "SetLastError"},
{907, nullptr, "AddSaveDataArchiveInfoType0"},
{908, nullptr, "RemoveSeriesInfoType0"},
{909, nullptr, "GetSeriesInfoType0"},
{910, nullptr, "RemoveLastErrorInfo"},
{911, nullptr, "CleanupSeriesInfoType1"},
{912, nullptr, "RemoveSeriesInfoType1"},
{913, nullptr, "GetSeriesInfoType1"},
{1000, nullptr, "UpdateIssueOld"},
{1010, nullptr, "Unknown1010"},
{1011, nullptr, "ListIssueInfoOld"},
{1012, nullptr, "GetIssueOld"},
{1013, nullptr, "GetIssue2Old"},
{1014, nullptr, "GetIssue3Old"},
{1020, nullptr, "RepairIssueOld"},
{1021, nullptr, "RepairIssueWithUserIdOld"},
{1022, nullptr, "RepairIssue2Old"},
{1023, nullptr, "RepairIssue3Old"},
{1024, nullptr, "Unknown1024"},
{1100, nullptr, "UpdateIssue"},
{1110, nullptr, "Unknown1110"},
{1111, nullptr, "ListIssueInfo"},
{1112, nullptr, "GetIssue"},
{1113, nullptr, "GetIssue2"},
{1114, nullptr, "GetIssue3"},
{1120, nullptr, "RepairIssue"},
{1121, nullptr, "RepairIssueWithUserId"},
{1122, nullptr, "RepairIssue2"},
{1123, nullptr, "RepairIssue3"},
{1124, nullptr, "Unknown1124"},
};
// clang-format on
RegisterHandlers(functions);
}
private:
void OpenTransferTaskListController(HLERequestContext& ctx) {
LOG_INFO(Service_OLSC, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<ITransferTaskListController>(system);
}
};
void LoopProcess(Core::System& system) {
auto server_manager = std::make_unique<ServerManager>(system);
server_manager->RegisterNamedService("olsc:u", std::make_shared<OLSC>(system));
server_manager->RegisterNamedService("olsc:u",
std::make_shared<IOlscServiceForApplication>(system));
server_manager->RegisterNamedService("olsc:s",
std::make_shared<IOlscServiceForSystemService>(system));
ServerManager::RunServer(std::move(server_manager));
}

View File

@ -6,6 +6,7 @@
#include "core/file_sys/control_metadata.h"
#include "core/file_sys/patch_manager.h"
#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/pctl/pctl.h"
#include "core/hle/service/pctl/pctl_module.h"
#include "core/hle/service/server_manager.h"
@ -24,7 +25,8 @@ constexpr Result ResultNoRestrictionEnabled{ErrorModule::PCTL, 181};
class IParentalControlService final : public ServiceFramework<IParentalControlService> {
public:
explicit IParentalControlService(Core::System& system_, Capability capability_)
: ServiceFramework{system_, "IParentalControlService"}, capability{capability_} {
: ServiceFramework{system_, "IParentalControlService"}, capability{capability_},
service_context{system_, "IParentalControlService"} {
// clang-format off
static const FunctionInfo functions[] = {
{1, &IParentalControlService::Initialize, "Initialize"},
@ -33,7 +35,7 @@ public:
{1003, nullptr, "ConfirmResumeApplicationPermission"},
{1004, nullptr, "ConfirmSnsPostPermission"},
{1005, nullptr, "ConfirmSystemSettingsPermission"},
{1006, nullptr, "IsRestrictionTemporaryUnlocked"},
{1006, &IParentalControlService::IsRestrictionTemporaryUnlocked, "IsRestrictionTemporaryUnlocked"},
{1007, nullptr, "RevertRestrictionTemporaryUnlocked"},
{1008, nullptr, "EnterRestrictedSystemSettings"},
{1009, nullptr, "LeaveRestrictedSystemSettings"},
@ -47,14 +49,14 @@ public:
{1017, &IParentalControlService::EndFreeCommunication, "EndFreeCommunication"},
{1018, &IParentalControlService::IsFreeCommunicationAvailable, "IsFreeCommunicationAvailable"},
{1031, &IParentalControlService::IsRestrictionEnabled, "IsRestrictionEnabled"},
{1032, nullptr, "GetSafetyLevel"},
{1032, &IParentalControlService::GetSafetyLevel, "GetSafetyLevel"},
{1033, nullptr, "SetSafetyLevel"},
{1034, nullptr, "GetSafetyLevelSettings"},
{1035, nullptr, "GetCurrentSettings"},
{1035, &IParentalControlService::GetCurrentSettings, "GetCurrentSettings"},
{1036, nullptr, "SetCustomSafetyLevelSettings"},
{1037, nullptr, "GetDefaultRatingOrganization"},
{1038, nullptr, "SetDefaultRatingOrganization"},
{1039, nullptr, "GetFreeCommunicationApplicationListCount"},
{1039, &IParentalControlService::GetFreeCommunicationApplicationListCount, "GetFreeCommunicationApplicationListCount"},
{1042, nullptr, "AddToFreeCommunicationApplicationList"},
{1043, nullptr, "DeleteSettings"},
{1044, nullptr, "GetFreeCommunicationApplicationList"},
@ -76,7 +78,7 @@ public:
{1206, nullptr, "GetPinCodeLength"},
{1207, nullptr, "GetPinCodeChangedEvent"},
{1208, nullptr, "GetPinCode"},
{1403, nullptr, "IsPairingActive"},
{1403, &IParentalControlService::IsPairingActive, "IsPairingActive"},
{1406, nullptr, "GetSettingsLastUpdated"},
{1411, nullptr, "GetPairingAccountInfo"},
{1421, nullptr, "GetAccountNickname"},
@ -84,18 +86,18 @@ public:
{1425, nullptr, "RequestPostEvents"},
{1426, nullptr, "GetPostEventInterval"},
{1427, nullptr, "SetPostEventInterval"},
{1432, nullptr, "GetSynchronizationEvent"},
{1432, &IParentalControlService::GetSynchronizationEvent, "GetSynchronizationEvent"},
{1451, nullptr, "StartPlayTimer"},
{1452, nullptr, "StopPlayTimer"},
{1453, nullptr, "IsPlayTimerEnabled"},
{1454, nullptr, "GetPlayTimerRemainingTime"},
{1455, nullptr, "IsRestrictedByPlayTimer"},
{1456, nullptr, "GetPlayTimerSettings"},
{1457, nullptr, "GetPlayTimerEventToRequestSuspension"},
{1458, nullptr, "IsPlayTimerAlarmDisabled"},
{1456, &IParentalControlService::GetPlayTimerSettings, "GetPlayTimerSettings"},
{1457, &IParentalControlService::GetPlayTimerEventToRequestSuspension, "GetPlayTimerEventToRequestSuspension"},
{1458, &IParentalControlService::IsPlayTimerAlarmDisabled, "IsPlayTimerAlarmDisabled"},
{1471, nullptr, "NotifyWrongPinCodeInputManyTimes"},
{1472, nullptr, "CancelNetworkRequest"},
{1473, nullptr, "GetUnlinkedEvent"},
{1473, &IParentalControlService::GetUnlinkedEvent, "GetUnlinkedEvent"},
{1474, nullptr, "ClearUnlinkedEvent"},
{1601, nullptr, "DisableAllFeatures"},
{1602, nullptr, "PostEnableAllFeatures"},
@ -131,6 +133,12 @@ public:
};
// clang-format on
RegisterHandlers(functions);
synchronization_event =
service_context.CreateEvent("IParentalControlService::SynchronizationEvent");
unlinked_event = service_context.CreateEvent("IParentalControlService::UnlinkedEvent");
request_suspension_event =
service_context.CreateEvent("IParentalControlService::RequestSuspensionEvent");
}
private:
@ -228,6 +236,17 @@ private:
states.free_communication = true;
}
void IsRestrictionTemporaryUnlocked(HLERequestContext& ctx) {
const bool is_temporary_unlocked = false;
LOG_WARNING(Service_PCTL, "(STUBBED) called, is_temporary_unlocked={}",
is_temporary_unlocked);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push<u8>(is_temporary_unlocked);
}
void ConfirmStereoVisionPermission(HLERequestContext& ctx) {
LOG_DEBUG(Service_PCTL, "called");
states.stereo_vision = true;
@ -268,6 +287,34 @@ private:
rb.Push(pin_code[0] != '\0');
}
void GetSafetyLevel(HLERequestContext& ctx) {
const u32 safety_level = 0;
LOG_WARNING(Service_PCTL, "(STUBBED) called, safety_level={}", safety_level);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(safety_level);
}
void GetCurrentSettings(HLERequestContext& ctx) {
LOG_INFO(Service_PCTL, "called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.PushRaw(restriction_settings);
}
void GetFreeCommunicationApplicationListCount(HLERequestContext& ctx) {
const u32 count = 4;
LOG_WARNING(Service_PCTL, "(STUBBED) called, count={}", count);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(count);
}
void ConfirmStereoVisionRestrictionConfigurable(HLERequestContext& ctx) {
LOG_DEBUG(Service_PCTL, "called");
@ -300,6 +347,61 @@ private:
}
}
void IsPairingActive(HLERequestContext& ctx) {
const bool is_pairing_active = false;
LOG_WARNING(Service_PCTL, "(STUBBED) called, is_pairing_active={}", is_pairing_active);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push<u8>(is_pairing_active);
}
void GetSynchronizationEvent(HLERequestContext& ctx) {
LOG_INFO(Service_PCTL, "called");
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(ResultSuccess);
rb.PushCopyObjects(synchronization_event->GetReadableEvent());
}
void GetPlayTimerSettings(HLERequestContext& ctx) {
LOG_WARNING(Service_PCTL, "(STUBBED) called");
const PlayTimerSettings timer_settings{};
IPC::ResponseBuilder rb{ctx, 15};
rb.Push(ResultSuccess);
rb.PushRaw(timer_settings);
}
void GetPlayTimerEventToRequestSuspension(HLERequestContext& ctx) {
LOG_INFO(Service_PCTL, "called");
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(ResultSuccess);
rb.PushCopyObjects(request_suspension_event->GetReadableEvent());
}
void IsPlayTimerAlarmDisabled(HLERequestContext& ctx) {
const bool is_play_timer_alarm_disabled = false;
LOG_INFO(Service_PCTL, "called, is_play_timer_alarm_disabled={}",
is_play_timer_alarm_disabled);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push<u8>(is_play_timer_alarm_disabled);
}
void GetUnlinkedEvent(HLERequestContext& ctx) {
LOG_INFO(Service_PCTL, "called");
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(ResultSuccess);
rb.PushCopyObjects(unlinked_event->GetReadableEvent());
}
void SetStereoVisionRestriction(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto can_use = rp.Pop<bool>();
@ -364,10 +466,30 @@ private:
bool disabled{};
};
// This is nn::pctl::RestrictionSettings
struct RestrictionSettings {
u8 rating_age;
bool sns_post_restriction;
bool free_communication_restriction;
};
static_assert(sizeof(RestrictionSettings) == 0x3, "RestrictionSettings has incorrect size.");
// This is nn::pctl::PlayTimerSettings
struct PlayTimerSettings {
std::array<u32, 13> settings;
};
static_assert(sizeof(PlayTimerSettings) == 0x34, "PlayTimerSettings has incorrect size.");
States states{};
ParentalControlSettings settings{};
RestrictionSettings restriction_settings{};
std::array<char, 8> pin_code{};
Capability capability{};
Kernel::KEvent* synchronization_event;
Kernel::KEvent* unlinked_event;
Kernel::KEvent* request_suspension_event;
KernelHelpers::ServiceContext service_context;
};
void Module::Interface::CreateService(HLERequestContext& ctx) {

View File

@ -102,16 +102,17 @@ Result ServerManager::RegisterNamedService(const std::string& service_name,
m_system.ServiceManager().RegisterService(service_name, max_sessions, handler)));
// Get the registered port.
auto port = m_system.ServiceManager().GetServicePort(service_name);
ASSERT(port.Succeeded());
Kernel::KPort* port{};
ASSERT(
R_SUCCEEDED(m_system.ServiceManager().GetServicePort(std::addressof(port), service_name)));
// Open a new reference to the server port.
(*port)->GetServerPort().Open();
port->GetServerPort().Open();
// Begin tracking the server port.
{
std::scoped_lock ll{m_list_mutex};
m_ports.emplace(std::addressof((*port)->GetServerPort()), std::move(handler));
m_ports.emplace(std::addressof(port->GetServerPort()), std::move(handler));
}
// Signal the wakeup event.

View File

@ -11,66 +11,6 @@
namespace Service::Set {
namespace {
constexpr std::array<LanguageCode, 18> available_language_codes = {{
LanguageCode::JA,
LanguageCode::EN_US,
LanguageCode::FR,
LanguageCode::DE,
LanguageCode::IT,
LanguageCode::ES,
LanguageCode::ZH_CN,
LanguageCode::KO,
LanguageCode::NL,
LanguageCode::PT,
LanguageCode::RU,
LanguageCode::ZH_TW,
LanguageCode::EN_GB,
LanguageCode::FR_CA,
LanguageCode::ES_419,
LanguageCode::ZH_HANS,
LanguageCode::ZH_HANT,
LanguageCode::PT_BR,
}};
enum class KeyboardLayout : u64 {
Japanese = 0,
EnglishUs = 1,
EnglishUsInternational = 2,
EnglishUk = 3,
French = 4,
FrenchCa = 5,
Spanish = 6,
SpanishLatin = 7,
German = 8,
Italian = 9,
Portuguese = 10,
Russian = 11,
Korean = 12,
ChineseSimplified = 13,
ChineseTraditional = 14,
};
constexpr std::array<std::pair<LanguageCode, KeyboardLayout>, 18> language_to_layout{{
{LanguageCode::JA, KeyboardLayout::Japanese},
{LanguageCode::EN_US, KeyboardLayout::EnglishUs},
{LanguageCode::FR, KeyboardLayout::French},
{LanguageCode::DE, KeyboardLayout::German},
{LanguageCode::IT, KeyboardLayout::Italian},
{LanguageCode::ES, KeyboardLayout::Spanish},
{LanguageCode::ZH_CN, KeyboardLayout::ChineseSimplified},
{LanguageCode::KO, KeyboardLayout::Korean},
{LanguageCode::NL, KeyboardLayout::EnglishUsInternational},
{LanguageCode::PT, KeyboardLayout::Portuguese},
{LanguageCode::RU, KeyboardLayout::Russian},
{LanguageCode::ZH_TW, KeyboardLayout::ChineseTraditional},
{LanguageCode::EN_GB, KeyboardLayout::EnglishUk},
{LanguageCode::FR_CA, KeyboardLayout::FrenchCa},
{LanguageCode::ES_419, KeyboardLayout::SpanishLatin},
{LanguageCode::ZH_HANS, KeyboardLayout::ChineseSimplified},
{LanguageCode::ZH_HANT, KeyboardLayout::ChineseTraditional},
{LanguageCode::PT_BR, KeyboardLayout::Portuguese},
}};
constexpr std::size_t PRE_4_0_0_MAX_ENTRIES = 0xF;
constexpr std::size_t POST_4_0_0_MAX_ENTRIES = 0x40;
@ -93,7 +33,8 @@ void GetAvailableLanguageCodesImpl(HLERequestContext& ctx, std::size_t max_entri
}
void GetKeyCodeMapImpl(HLERequestContext& ctx) {
const auto language_code = available_language_codes[Settings::values.language_index.GetValue()];
const auto language_code =
available_language_codes[static_cast<s32>(Settings::values.language_index.GetValue())];
const auto key_code =
std::find_if(language_to_layout.cbegin(), language_to_layout.cend(),
[=](const auto& element) { return element.first == language_code; });
@ -162,7 +103,7 @@ void SET::GetQuestFlag(HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(static_cast<u32>(Settings::values.quest_flag.GetValue()));
rb.Push(static_cast<s32>(Settings::values.quest_flag.GetValue()));
}
void SET::GetLanguageCode(HLERequestContext& ctx) {
@ -170,7 +111,8 @@ void SET::GetLanguageCode(HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.PushEnum(available_language_codes[Settings::values.language_index.GetValue()]);
rb.PushEnum(
available_language_codes[static_cast<s32>(Settings::values.language_index.GetValue())]);
}
void SET::GetRegionCode(HLERequestContext& ctx) {
@ -178,7 +120,7 @@ void SET::GetRegionCode(HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(Settings::values.region_index.GetValue());
rb.Push(static_cast<u32>(Settings::values.region_index.GetValue()));
}
void SET::GetKeyCodeMap(HLERequestContext& ctx) {

View File

@ -32,6 +32,67 @@ enum class LanguageCode : u64 {
ZH_HANT = 0x00746E61482D687A,
PT_BR = 0x00000052422D7470,
};
enum class KeyboardLayout : u64 {
Japanese = 0,
EnglishUs = 1,
EnglishUsInternational = 2,
EnglishUk = 3,
French = 4,
FrenchCa = 5,
Spanish = 6,
SpanishLatin = 7,
German = 8,
Italian = 9,
Portuguese = 10,
Russian = 11,
Korean = 12,
ChineseSimplified = 13,
ChineseTraditional = 14,
};
constexpr std::array<LanguageCode, 18> available_language_codes = {{
LanguageCode::JA,
LanguageCode::EN_US,
LanguageCode::FR,
LanguageCode::DE,
LanguageCode::IT,
LanguageCode::ES,
LanguageCode::ZH_CN,
LanguageCode::KO,
LanguageCode::NL,
LanguageCode::PT,
LanguageCode::RU,
LanguageCode::ZH_TW,
LanguageCode::EN_GB,
LanguageCode::FR_CA,
LanguageCode::ES_419,
LanguageCode::ZH_HANS,
LanguageCode::ZH_HANT,
LanguageCode::PT_BR,
}};
static constexpr std::array<std::pair<LanguageCode, KeyboardLayout>, 18> language_to_layout{{
{LanguageCode::JA, KeyboardLayout::Japanese},
{LanguageCode::EN_US, KeyboardLayout::EnglishUs},
{LanguageCode::FR, KeyboardLayout::French},
{LanguageCode::DE, KeyboardLayout::German},
{LanguageCode::IT, KeyboardLayout::Italian},
{LanguageCode::ES, KeyboardLayout::Spanish},
{LanguageCode::ZH_CN, KeyboardLayout::ChineseSimplified},
{LanguageCode::KO, KeyboardLayout::Korean},
{LanguageCode::NL, KeyboardLayout::EnglishUsInternational},
{LanguageCode::PT, KeyboardLayout::Portuguese},
{LanguageCode::RU, KeyboardLayout::Russian},
{LanguageCode::ZH_TW, KeyboardLayout::ChineseTraditional},
{LanguageCode::EN_GB, KeyboardLayout::EnglishUk},
{LanguageCode::FR_CA, KeyboardLayout::FrenchCa},
{LanguageCode::ES_419, KeyboardLayout::SpanishLatin},
{LanguageCode::ZH_HANS, KeyboardLayout::ChineseSimplified},
{LanguageCode::ZH_HANT, KeyboardLayout::ChineseTraditional},
{LanguageCode::PT_BR, KeyboardLayout::Portuguese},
}};
LanguageCode GetLanguageCodeFromIndex(std::size_t idx);
class SET final : public ServiceFramework<SET> {

View File

@ -4,10 +4,12 @@
#include "common/assert.h"
#include "common/logging/log.h"
#include "common/settings.h"
#include "common/string_util.h"
#include "core/file_sys/errors.h"
#include "core/file_sys/system_archive/system_version.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/set/set.h"
#include "core/hle/service/set/set_sys.h"
namespace Service::Set {
@ -73,6 +75,16 @@ void GetFirmwareVersionImpl(HLERequestContext& ctx, GetFirmwareVersionType type)
}
} // Anonymous namespace
void SET_SYS::SetLanguageCode(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
language_code_setting = rp.PopEnum<LanguageCode>();
LOG_INFO(Service_SET, "called, language_code={}", language_code_setting);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void SET_SYS::GetFirmwareVersion(HLERequestContext& ctx) {
LOG_DEBUG(Service_SET, "called");
GetFirmwareVersionImpl(ctx, GetFirmwareVersionType::Version1);
@ -83,21 +95,113 @@ void SET_SYS::GetFirmwareVersion2(HLERequestContext& ctx) {
GetFirmwareVersionImpl(ctx, GetFirmwareVersionType::Version2);
}
void SET_SYS::GetAccountSettings(HLERequestContext& ctx) {
LOG_INFO(Service_SET, "called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.PushRaw(account_settings);
}
void SET_SYS::SetAccountSettings(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
account_settings = rp.PopRaw<AccountSettings>();
LOG_INFO(Service_SET, "called, account_settings_flags={}", account_settings.flags);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void SET_SYS::GetEulaVersions(HLERequestContext& ctx) {
LOG_INFO(Service_SET, "called");
ctx.WriteBuffer(eula_versions);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(static_cast<u32>(eula_versions.size()));
}
void SET_SYS::SetEulaVersions(HLERequestContext& ctx) {
const auto elements = ctx.GetReadBufferNumElements<EulaVersion>();
const auto buffer_data = ctx.ReadBuffer();
LOG_INFO(Service_SET, "called, elements={}", elements);
eula_versions.resize(elements);
for (std::size_t index = 0; index < elements; index++) {
const std::size_t start_index = index * sizeof(EulaVersion);
memcpy(eula_versions.data() + start_index, buffer_data.data() + start_index,
sizeof(EulaVersion));
}
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void SET_SYS::GetColorSetId(HLERequestContext& ctx) {
LOG_DEBUG(Service_SET, "called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.PushEnum(color_set);
}
void SET_SYS::SetColorSetId(HLERequestContext& ctx) {
LOG_DEBUG(Service_SET, "called");
IPC::RequestParser rp{ctx};
color_set = rp.PopEnum<ColorSet>();
LOG_DEBUG(Service_SET, "called, color_set={}", color_set);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void SET_SYS::GetNotificationSettings(HLERequestContext& ctx) {
LOG_INFO(Service_SET, "called");
IPC::ResponseBuilder rb{ctx, 8};
rb.Push(ResultSuccess);
rb.PushRaw(notification_settings);
}
void SET_SYS::SetNotificationSettings(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
notification_settings = rp.PopRaw<NotificationSettings>();
LOG_INFO(Service_SET, "called, flags={}, volume={}, head_time={}:{}, tailt_time={}:{}",
notification_settings.flags.raw, notification_settings.volume,
notification_settings.start_time.hour, notification_settings.start_time.minute,
notification_settings.stop_time.hour, notification_settings.stop_time.minute);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void SET_SYS::GetAccountNotificationSettings(HLERequestContext& ctx) {
LOG_INFO(Service_SET, "called");
ctx.WriteBuffer(account_notifications);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(static_cast<u32>(account_notifications.size()));
}
void SET_SYS::SetAccountNotificationSettings(HLERequestContext& ctx) {
const auto elements = ctx.GetReadBufferNumElements<AccountNotificationSettings>();
const auto buffer_data = ctx.ReadBuffer();
LOG_INFO(Service_SET, "called, elements={}", elements);
account_notifications.resize(elements);
for (std::size_t index = 0; index < elements; index++) {
const std::size_t start_index = index * sizeof(AccountNotificationSettings);
memcpy(account_notifications.data() + start_index, buffer_data.data() + start_index,
sizeof(AccountNotificationSettings));
}
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
@ -177,17 +281,218 @@ void SET_SYS::GetSettingsItemValue(HLERequestContext& ctx) {
rb.Push(response);
}
void SET_SYS::GetDeviceNickName(HLERequestContext& ctx) {
LOG_DEBUG(Service_SET, "called");
void SET_SYS::GetTvSettings(HLERequestContext& ctx) {
LOG_INFO(Service_SET, "called");
IPC::ResponseBuilder rb{ctx, 10};
rb.Push(ResultSuccess);
rb.PushRaw(tv_settings);
}
void SET_SYS::SetTvSettings(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
tv_settings = rp.PopRaw<TvSettings>();
LOG_INFO(Service_SET,
"called, flags={}, cmu_mode={}, constrast_ratio={}, hdmi_content_type={}, "
"rgb_range={}, tv_gama={}, tv_resolution={}, tv_underscan={}",
tv_settings.flags.raw, tv_settings.cmu_mode, tv_settings.constrast_ratio,
tv_settings.hdmi_content_type, tv_settings.rgb_range, tv_settings.tv_gama,
tv_settings.tv_resolution, tv_settings.tv_underscan);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void SET_SYS::GetQuestFlag(HLERequestContext& ctx) {
LOG_WARNING(Service_SET, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.PushEnum(QuestFlag::Retail);
}
void SET_SYS::SetRegionCode(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
region_code = rp.PopEnum<RegionCode>();
LOG_INFO(Service_SET, "called, region_code={}", region_code);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void SET_SYS::GetPrimaryAlbumStorage(HLERequestContext& ctx) {
LOG_WARNING(Service_SET, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.PushEnum(PrimaryAlbumStorage::SdCard);
}
void SET_SYS::GetSleepSettings(HLERequestContext& ctx) {
LOG_INFO(Service_SET, "called");
IPC::ResponseBuilder rb{ctx, 5};
rb.Push(ResultSuccess);
rb.PushRaw(sleep_settings);
}
void SET_SYS::SetSleepSettings(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
sleep_settings = rp.PopRaw<SleepSettings>();
LOG_INFO(Service_SET, "called, flags={}, handheld_sleep_plan={}, console_sleep_plan={}",
sleep_settings.flags.raw, sleep_settings.handheld_sleep_plan,
sleep_settings.console_sleep_plan);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void SET_SYS::GetInitialLaunchSettings(HLERequestContext& ctx) {
LOG_INFO(Service_SET, "called");
IPC::ResponseBuilder rb{ctx, 10};
rb.Push(ResultSuccess);
rb.PushRaw(launch_settings);
}
void SET_SYS::SetInitialLaunchSettings(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
launch_settings = rp.PopRaw<InitialLaunchSettings>();
LOG_INFO(Service_SET, "called, flags={}, timestamp={}", launch_settings.flags.raw,
launch_settings.timestamp.time_point);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void SET_SYS::GetDeviceNickName(HLERequestContext& ctx) {
LOG_DEBUG(Service_SET, "called");
ctx.WriteBuffer(::Settings::values.device_name.GetValue());
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void SET_SYS::SetDeviceNickName(HLERequestContext& ctx) {
const std::string device_name = Common::StringFromBuffer(ctx.ReadBuffer());
LOG_INFO(Service_SET, "called, device_name={}", device_name);
::Settings::values.device_name = device_name;
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void SET_SYS::GetProductModel(HLERequestContext& ctx) {
const u32 product_model = 1;
LOG_WARNING(Service_SET, "(STUBBED) called, product_model={}", product_model);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(product_model);
}
void SET_SYS::GetMiiAuthorId(HLERequestContext& ctx) {
const auto author_id = Common::UUID::MakeDefault();
LOG_WARNING(Service_SET, "(STUBBED) called, author_id={}", author_id.FormattedString());
IPC::ResponseBuilder rb{ctx, 6};
rb.Push(ResultSuccess);
rb.PushRaw(author_id);
}
void SET_SYS::GetAutoUpdateEnableFlag(HLERequestContext& ctx) {
u8 auto_update_flag{};
LOG_WARNING(Service_SET, "(STUBBED) called, auto_update_flag={}", auto_update_flag);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(auto_update_flag);
}
void SET_SYS::GetBatteryPercentageFlag(HLERequestContext& ctx) {
u8 battery_percentage_flag{1};
LOG_WARNING(Service_SET, "(STUBBED) called, battery_percentage_flag={}",
battery_percentage_flag);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(battery_percentage_flag);
}
void SET_SYS::GetErrorReportSharePermission(HLERequestContext& ctx) {
LOG_WARNING(Service_SET, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.PushEnum(ErrorReportSharePermission::Denied);
}
void SET_SYS::GetAppletLaunchFlags(HLERequestContext& ctx) {
LOG_INFO(Service_SET, "called, applet_launch_flag={}", applet_launch_flag);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(applet_launch_flag);
}
void SET_SYS::SetAppletLaunchFlags(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
applet_launch_flag = rp.Pop<u32>();
LOG_INFO(Service_SET, "called, applet_launch_flag={}", applet_launch_flag);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void SET_SYS::GetKeyboardLayout(HLERequestContext& ctx) {
const auto language_code =
available_language_codes[static_cast<s32>(::Settings::values.language_index.GetValue())];
const auto key_code =
std::find_if(language_to_layout.cbegin(), language_to_layout.cend(),
[=](const auto& element) { return element.first == language_code; });
KeyboardLayout selected_keyboard_layout = KeyboardLayout::EnglishUs;
if (key_code != language_to_layout.end()) {
selected_keyboard_layout = key_code->second;
}
LOG_INFO(Service_SET, "called, selected_keyboard_layout={}", selected_keyboard_layout);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(static_cast<u32>(selected_keyboard_layout));
}
void SET_SYS::GetChineseTraditionalInputMethod(HLERequestContext& ctx) {
LOG_WARNING(Service_SET, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.PushEnum(ChineseTraditionalInputMethod::Unknown0);
}
void SET_SYS::GetFieldTestingFlag(HLERequestContext& ctx) {
LOG_WARNING(Service_SET, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push<u8>(false);
}
SET_SYS::SET_SYS(Core::System& system_) : ServiceFramework{system_, "set:sys"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "SetLanguageCode"},
{0, &SET_SYS::SetLanguageCode, "SetLanguageCode"},
{1, nullptr, "SetNetworkSettings"},
{2, nullptr, "GetNetworkSettings"},
{3, &SET_SYS::GetFirmwareVersion, "GetFirmwareVersion"},
@ -203,35 +508,35 @@ SET_SYS::SET_SYS(Core::System& system_) : ServiceFramework{system_, "set:sys"} {
{14, nullptr, "SetExternalSteadyClockSourceId"},
{15, nullptr, "GetUserSystemClockContext"},
{16, nullptr, "SetUserSystemClockContext"},
{17, nullptr, "GetAccountSettings"},
{18, nullptr, "SetAccountSettings"},
{17, &SET_SYS::GetAccountSettings, "GetAccountSettings"},
{18, &SET_SYS::SetAccountSettings, "SetAccountSettings"},
{19, nullptr, "GetAudioVolume"},
{20, nullptr, "SetAudioVolume"},
{21, nullptr, "GetEulaVersions"},
{22, nullptr, "SetEulaVersions"},
{21, &SET_SYS::GetEulaVersions, "GetEulaVersions"},
{22, &SET_SYS::SetEulaVersions, "SetEulaVersions"},
{23, &SET_SYS::GetColorSetId, "GetColorSetId"},
{24, &SET_SYS::SetColorSetId, "SetColorSetId"},
{25, nullptr, "GetConsoleInformationUploadFlag"},
{26, nullptr, "SetConsoleInformationUploadFlag"},
{27, nullptr, "GetAutomaticApplicationDownloadFlag"},
{28, nullptr, "SetAutomaticApplicationDownloadFlag"},
{29, nullptr, "GetNotificationSettings"},
{30, nullptr, "SetNotificationSettings"},
{31, nullptr, "GetAccountNotificationSettings"},
{32, nullptr, "SetAccountNotificationSettings"},
{29, &SET_SYS::GetNotificationSettings, "GetNotificationSettings"},
{30, &SET_SYS::SetNotificationSettings, "SetNotificationSettings"},
{31, &SET_SYS::GetAccountNotificationSettings, "GetAccountNotificationSettings"},
{32, &SET_SYS::SetAccountNotificationSettings, "SetAccountNotificationSettings"},
{35, nullptr, "GetVibrationMasterVolume"},
{36, nullptr, "SetVibrationMasterVolume"},
{37, &SET_SYS::GetSettingsItemValueSize, "GetSettingsItemValueSize"},
{38, &SET_SYS::GetSettingsItemValue, "GetSettingsItemValue"},
{39, nullptr, "GetTvSettings"},
{40, nullptr, "SetTvSettings"},
{39, &SET_SYS::GetTvSettings, "GetTvSettings"},
{40, &SET_SYS::SetTvSettings, "SetTvSettings"},
{41, nullptr, "GetEdid"},
{42, nullptr, "SetEdid"},
{43, nullptr, "GetAudioOutputMode"},
{44, nullptr, "SetAudioOutputMode"},
{45, nullptr, "IsForceMuteOnHeadphoneRemoved"},
{46, nullptr, "SetForceMuteOnHeadphoneRemoved"},
{47, nullptr, "GetQuestFlag"},
{47, &SET_SYS::GetQuestFlag, "GetQuestFlag"},
{48, nullptr, "SetQuestFlag"},
{49, nullptr, "GetDataDeletionSettings"},
{50, nullptr, "SetDataDeletionSettings"},
@ -241,13 +546,13 @@ SET_SYS::SET_SYS(Core::System& system_) : ServiceFramework{system_, "set:sys"} {
{54, nullptr, "SetDeviceTimeZoneLocationName"},
{55, nullptr, "GetWirelessCertificationFileSize"},
{56, nullptr, "GetWirelessCertificationFile"},
{57, nullptr, "SetRegionCode"},
{57, &SET_SYS::SetRegionCode, "SetRegionCode"},
{58, nullptr, "GetNetworkSystemClockContext"},
{59, nullptr, "SetNetworkSystemClockContext"},
{60, nullptr, "IsUserSystemClockAutomaticCorrectionEnabled"},
{61, nullptr, "SetUserSystemClockAutomaticCorrectionEnabled"},
{62, nullptr, "GetDebugModeFlag"},
{63, nullptr, "GetPrimaryAlbumStorage"},
{63, &SET_SYS::GetPrimaryAlbumStorage, "GetPrimaryAlbumStorage"},
{64, nullptr, "SetPrimaryAlbumStorage"},
{65, nullptr, "GetUsb30EnableFlag"},
{66, nullptr, "SetUsb30EnableFlag"},
@ -255,15 +560,15 @@ SET_SYS::SET_SYS(Core::System& system_) : ServiceFramework{system_, "set:sys"} {
{68, nullptr, "GetSerialNumber"},
{69, nullptr, "GetNfcEnableFlag"},
{70, nullptr, "SetNfcEnableFlag"},
{71, nullptr, "GetSleepSettings"},
{72, nullptr, "SetSleepSettings"},
{71, &SET_SYS::GetSleepSettings, "GetSleepSettings"},
{72, &SET_SYS::SetSleepSettings, "SetSleepSettings"},
{73, nullptr, "GetWirelessLanEnableFlag"},
{74, nullptr, "SetWirelessLanEnableFlag"},
{75, nullptr, "GetInitialLaunchSettings"},
{76, nullptr, "SetInitialLaunchSettings"},
{75, &SET_SYS::GetInitialLaunchSettings, "GetInitialLaunchSettings"},
{76, &SET_SYS::SetInitialLaunchSettings, "SetInitialLaunchSettings"},
{77, &SET_SYS::GetDeviceNickName, "GetDeviceNickName"},
{78, nullptr, "SetDeviceNickName"},
{79, nullptr, "GetProductModel"},
{78, &SET_SYS::SetDeviceNickName, "SetDeviceNickName"},
{79, &SET_SYS::GetProductModel, "GetProductModel"},
{80, nullptr, "GetLdnChannel"},
{81, nullptr, "SetLdnChannel"},
{82, nullptr, "AcquireTelemetryDirtyFlagEventHandle"},
@ -274,16 +579,16 @@ SET_SYS::SET_SYS(Core::System& system_) : ServiceFramework{system_, "set:sys"} {
{87, nullptr, "SetPtmFuelGaugeParameter"},
{88, nullptr, "GetBluetoothEnableFlag"},
{89, nullptr, "SetBluetoothEnableFlag"},
{90, nullptr, "GetMiiAuthorId"},
{90, &SET_SYS::GetMiiAuthorId, "GetMiiAuthorId"},
{91, nullptr, "SetShutdownRtcValue"},
{92, nullptr, "GetShutdownRtcValue"},
{93, nullptr, "AcquireFatalDirtyFlagEventHandle"},
{94, nullptr, "GetFatalDirtyFlags"},
{95, nullptr, "GetAutoUpdateEnableFlag"},
{95, &SET_SYS::GetAutoUpdateEnableFlag, "GetAutoUpdateEnableFlag"},
{96, nullptr, "SetAutoUpdateEnableFlag"},
{97, nullptr, "GetNxControllerSettings"},
{98, nullptr, "SetNxControllerSettings"},
{99, nullptr, "GetBatteryPercentageFlag"},
{99, &SET_SYS::GetBatteryPercentageFlag, "GetBatteryPercentageFlag"},
{100, nullptr, "SetBatteryPercentageFlag"},
{101, nullptr, "GetExternalRtcResetFlag"},
{102, nullptr, "SetExternalRtcResetFlag"},
@ -308,10 +613,10 @@ SET_SYS::SET_SYS(Core::System& system_) : ServiceFramework{system_, "set:sys"} {
{121, nullptr, "SetPushNotificationActivityModeOnSleep"},
{122, nullptr, "GetServiceDiscoveryControlSettings"},
{123, nullptr, "SetServiceDiscoveryControlSettings"},
{124, nullptr, "GetErrorReportSharePermission"},
{124, &SET_SYS::GetErrorReportSharePermission, "GetErrorReportSharePermission"},
{125, nullptr, "SetErrorReportSharePermission"},
{126, nullptr, "GetAppletLaunchFlags"},
{127, nullptr, "SetAppletLaunchFlags"},
{126, &SET_SYS::GetAppletLaunchFlags, "GetAppletLaunchFlags"},
{127, &SET_SYS::SetAppletLaunchFlags, "SetAppletLaunchFlags"},
{128, nullptr, "GetConsoleSixAxisSensorAccelerationBias"},
{129, nullptr, "SetConsoleSixAxisSensorAccelerationBias"},
{130, nullptr, "GetConsoleSixAxisSensorAngularVelocityBias"},
@ -320,7 +625,7 @@ SET_SYS::SET_SYS(Core::System& system_) : ServiceFramework{system_, "set:sys"} {
{133, nullptr, "SetConsoleSixAxisSensorAccelerationGain"},
{134, nullptr, "GetConsoleSixAxisSensorAngularVelocityGain"},
{135, nullptr, "SetConsoleSixAxisSensorAngularVelocityGain"},
{136, nullptr, "GetKeyboardLayout"},
{136, &SET_SYS::GetKeyboardLayout, "GetKeyboardLayout"},
{137, nullptr, "SetKeyboardLayout"},
{138, nullptr, "GetWebInspectorFlag"},
{139, nullptr, "GetAllowedSslHosts"},
@ -354,7 +659,7 @@ SET_SYS::SET_SYS(Core::System& system_) : ServiceFramework{system_, "set:sys"} {
{167, nullptr, "SetUsb30DeviceEnableFlag"},
{168, nullptr, "GetThemeId"},
{169, nullptr, "SetThemeId"},
{170, nullptr, "GetChineseTraditionalInputMethod"},
{170, &SET_SYS::GetChineseTraditionalInputMethod, "GetChineseTraditionalInputMethod"},
{171, nullptr, "SetChineseTraditionalInputMethod"},
{172, nullptr, "GetPtmCycleCountReliability"},
{173, nullptr, "SetPtmCycleCountReliability"},
@ -385,12 +690,16 @@ SET_SYS::SET_SYS(Core::System& system_) : ServiceFramework{system_, "set:sys"} {
{198, nullptr, "SetButtonConfigRegisteredSettingsEmbedded"},
{199, nullptr, "GetButtonConfigRegisteredSettings"},
{200, nullptr, "SetButtonConfigRegisteredSettings"},
{201, nullptr, "GetFieldTestingFlag"},
{201, &SET_SYS::GetFieldTestingFlag, "GetFieldTestingFlag"},
{202, nullptr, "SetFieldTestingFlag"},
{203, nullptr, "GetPanelCrcMode"},
{204, nullptr, "SetPanelCrcMode"},
{205, nullptr, "GetNxControllerSettingsEx"},
{206, nullptr, "SetNxControllerSettingsEx"},
{207, nullptr, "GetHearingProtectionSafeguardFlag"},
{208, nullptr, "SetHearingProtectionSafeguardFlag"},
{209, nullptr, "GetHearingProtectionSafeguardRemainingTime"},
{210, nullptr, "SetHearingProtectionSafeguardRemainingTime"},
};
// clang-format on

View File

@ -3,7 +3,9 @@
#pragma once
#include "common/uuid.h"
#include "core/hle/service/service.h"
#include "core/hle/service/time/clock_types.h"
namespace Core {
class System;
@ -23,15 +25,331 @@ private:
BasicBlack = 1,
};
void GetSettingsItemValueSize(HLERequestContext& ctx);
void GetSettingsItemValue(HLERequestContext& ctx);
/// Indicates the current console is a retail or kiosk unit
enum class QuestFlag : u8 {
Retail = 0,
Kiosk = 1,
};
/// This is nn::settings::system::TvResolution
enum class TvResolution : u32 {
Auto,
Resolution1080p,
Resolution720p,
Resolution480p,
};
/// This is nn::settings::system::HdmiContentType
enum class HdmiContentType : u32 {
None,
Graphics,
Cinema,
Photo,
Game,
};
/// This is nn::settings::system::RgbRange
enum class RgbRange : u32 {
Auto,
Full,
Limited,
};
/// This is nn::settings::system::CmuMode
enum class CmuMode : u32 {
None,
ColorInvert,
HighContrast,
GrayScale,
};
/// This is nn::settings::system::PrimaryAlbumStorage
enum class PrimaryAlbumStorage : u32 {
Nand,
SdCard,
};
/// This is nn::settings::system::NotificationVolume
enum class NotificationVolume : u32 {
Mute,
Low,
High,
};
/// This is nn::settings::system::ChineseTraditionalInputMethod
enum class ChineseTraditionalInputMethod : u32 {
Unknown0 = 0,
Unknown1 = 1,
Unknown2 = 2,
};
/// This is nn::settings::system::ErrorReportSharePermission
enum class ErrorReportSharePermission : u32 {
NotConfirmed,
Granted,
Denied,
};
/// This is nn::settings::system::FriendPresenceOverlayPermission
enum class FriendPresenceOverlayPermission : u8 {
NotConfirmed,
NoDisplay,
FavoriteFriends,
Friends,
};
/// This is nn::settings::system::HandheldSleepPlan
enum class HandheldSleepPlan : u32 {
Sleep1Min,
Sleep3Min,
Sleep5Min,
Sleep10Min,
Sleep30Min,
Never,
};
/// This is nn::settings::system::ConsoleSleepPlan
enum class ConsoleSleepPlan : u32 {
Sleep1Hour,
Sleep2Hour,
Sleep3Hour,
Sleep6Hour,
Sleep12Hour,
Never,
};
/// This is nn::settings::system::RegionCode
enum class RegionCode : u32 {
Japan,
Usa,
Europe,
Australia,
HongKongTaiwanKorea,
China,
};
/// This is nn::settings::system::EulaVersionClockType
enum class EulaVersionClockType : u32 {
NetworkSystemClock,
SteadyClock,
};
/// This is nn::settings::system::SleepFlag
struct SleepFlag {
union {
u32 raw{};
BitField<0, 1, u32> SleepsWhilePlayingMedia;
BitField<1, 1, u32> WakesAtPowerStateChange;
};
};
static_assert(sizeof(SleepFlag) == 4, "TvFlag is an invalid size");
/// This is nn::settings::system::TvFlag
struct TvFlag {
union {
u32 raw{};
BitField<0, 1, u32> Allows4k;
BitField<1, 1, u32> Allows3d;
BitField<2, 1, u32> AllowsCec;
BitField<3, 1, u32> PreventsScreenBurnIn;
};
};
static_assert(sizeof(TvFlag) == 4, "TvFlag is an invalid size");
/// This is nn::settings::system::InitialLaunchFlag
struct InitialLaunchFlag {
union {
u32 raw{};
BitField<0, 1, u32> InitialLaunchCompletionFlag;
BitField<8, 1, u32> InitialLaunchUserAdditionFlag;
BitField<16, 1, u32> InitialLaunchTimestampFlag;
};
};
static_assert(sizeof(InitialLaunchFlag) == 4, "InitialLaunchFlag is an invalid size");
/// This is nn::settings::system::NotificationFlag
struct NotificationFlag {
union {
u32 raw{};
BitField<0, 1, u32> RingtoneFlag;
BitField<1, 1, u32> DownloadCompletionFlag;
BitField<8, 1, u32> EnablesNews;
BitField<9, 1, u32> IncomingLampFlag;
};
};
static_assert(sizeof(NotificationFlag) == 4, "NotificationFlag is an invalid size");
/// This is nn::settings::system::AccountNotificationFlag
struct AccountNotificationFlag {
union {
u32 raw{};
BitField<0, 1, u32> FriendOnlineFlag;
BitField<1, 1, u32> FriendRequestFlag;
BitField<8, 1, u32> CoralInvitationFlag;
};
};
static_assert(sizeof(AccountNotificationFlag) == 4,
"AccountNotificationFlag is an invalid size");
/// This is nn::settings::system::TvSettings
struct TvSettings {
TvFlag flags;
TvResolution tv_resolution;
HdmiContentType hdmi_content_type;
RgbRange rgb_range;
CmuMode cmu_mode;
u32 tv_underscan;
f32 tv_gama;
f32 constrast_ratio;
};
static_assert(sizeof(TvSettings) == 0x20, "TvSettings is an invalid size");
/// This is nn::settings::system::NotificationTime
struct NotificationTime {
u32 hour;
u32 minute;
};
static_assert(sizeof(NotificationTime) == 0x8, "NotificationTime is an invalid size");
/// This is nn::settings::system::NotificationSettings
struct NotificationSettings {
NotificationFlag flags;
NotificationVolume volume;
NotificationTime start_time;
NotificationTime stop_time;
};
static_assert(sizeof(NotificationSettings) == 0x18, "NotificationSettings is an invalid size");
/// This is nn::settings::system::AccountSettings
struct AccountSettings {
u32 flags;
};
static_assert(sizeof(AccountSettings) == 0x4, "AccountSettings is an invalid size");
/// This is nn::settings::system::AccountNotificationSettings
struct AccountNotificationSettings {
Common::UUID uid;
AccountNotificationFlag flags;
FriendPresenceOverlayPermission friend_presence_permission;
FriendPresenceOverlayPermission friend_invitation_permission;
INSERT_PADDING_BYTES(0x2);
};
static_assert(sizeof(AccountNotificationSettings) == 0x18,
"AccountNotificationSettings is an invalid size");
/// This is nn::settings::system::InitialLaunchSettings
struct SleepSettings {
SleepFlag flags;
HandheldSleepPlan handheld_sleep_plan;
ConsoleSleepPlan console_sleep_plan;
};
static_assert(sizeof(SleepSettings) == 0xc, "SleepSettings is incorrect size");
/// This is nn::settings::system::InitialLaunchSettings
struct InitialLaunchSettings {
InitialLaunchFlag flags;
INSERT_PADDING_BYTES(0x4);
Time::Clock::SteadyClockTimePoint timestamp;
};
static_assert(sizeof(InitialLaunchSettings) == 0x20, "InitialLaunchSettings is incorrect size");
/// This is nn::settings::system::InitialLaunchSettings
struct EulaVersion {
u32 version;
RegionCode region_code;
EulaVersionClockType clock_type;
INSERT_PADDING_BYTES(0x4);
s64 posix_time;
Time::Clock::SteadyClockTimePoint timestamp;
};
static_assert(sizeof(EulaVersion) == 0x30, "EulaVersion is incorrect size");
void SetLanguageCode(HLERequestContext& ctx);
void GetFirmwareVersion(HLERequestContext& ctx);
void GetFirmwareVersion2(HLERequestContext& ctx);
void GetAccountSettings(HLERequestContext& ctx);
void SetAccountSettings(HLERequestContext& ctx);
void GetEulaVersions(HLERequestContext& ctx);
void SetEulaVersions(HLERequestContext& ctx);
void GetColorSetId(HLERequestContext& ctx);
void SetColorSetId(HLERequestContext& ctx);
void GetNotificationSettings(HLERequestContext& ctx);
void SetNotificationSettings(HLERequestContext& ctx);
void GetAccountNotificationSettings(HLERequestContext& ctx);
void SetAccountNotificationSettings(HLERequestContext& ctx);
void GetSettingsItemValueSize(HLERequestContext& ctx);
void GetSettingsItemValue(HLERequestContext& ctx);
void GetTvSettings(HLERequestContext& ctx);
void SetTvSettings(HLERequestContext& ctx);
void GetQuestFlag(HLERequestContext& ctx);
void SetRegionCode(HLERequestContext& ctx);
void GetPrimaryAlbumStorage(HLERequestContext& ctx);
void GetSleepSettings(HLERequestContext& ctx);
void SetSleepSettings(HLERequestContext& ctx);
void GetInitialLaunchSettings(HLERequestContext& ctx);
void SetInitialLaunchSettings(HLERequestContext& ctx);
void GetDeviceNickName(HLERequestContext& ctx);
void SetDeviceNickName(HLERequestContext& ctx);
void GetProductModel(HLERequestContext& ctx);
void GetMiiAuthorId(HLERequestContext& ctx);
void GetAutoUpdateEnableFlag(HLERequestContext& ctx);
void GetBatteryPercentageFlag(HLERequestContext& ctx);
void GetErrorReportSharePermission(HLERequestContext& ctx);
void GetAppletLaunchFlags(HLERequestContext& ctx);
void SetAppletLaunchFlags(HLERequestContext& ctx);
void GetKeyboardLayout(HLERequestContext& ctx);
void GetChineseTraditionalInputMethod(HLERequestContext& ctx);
void GetFieldTestingFlag(HLERequestContext& ctx);
AccountSettings account_settings{
.flags = {},
};
ColorSet color_set = ColorSet::BasicWhite;
NotificationSettings notification_settings{
.flags = {0x300},
.volume = NotificationVolume::High,
.start_time = {.hour = 9, .minute = 0},
.stop_time = {.hour = 21, .minute = 0},
};
std::vector<AccountNotificationSettings> account_notifications{};
TvSettings tv_settings{
.flags = {0xc},
.tv_resolution = TvResolution::Auto,
.hdmi_content_type = HdmiContentType::Game,
.rgb_range = RgbRange::Auto,
.cmu_mode = CmuMode::None,
.tv_underscan = {},
.tv_gama = 1.0f,
.constrast_ratio = 0.5f,
};
InitialLaunchSettings launch_settings{
.flags = {0x10001},
.timestamp = {},
};
SleepSettings sleep_settings{
.flags = {0x3},
.handheld_sleep_plan = HandheldSleepPlan::Sleep10Min,
.console_sleep_plan = ConsoleSleepPlan::Sleep1Hour,
};
u32 applet_launch_flag{};
std::vector<EulaVersion> eula_versions{};
RegionCode region_code;
LanguageCode language_code_setting;
};
} // namespace Service::Set

View File

@ -52,8 +52,7 @@ static Result ValidateServiceName(const std::string& name) {
Result ServiceManager::RegisterService(std::string name, u32 max_sessions,
SessionRequestHandlerPtr handler) {
CASCADE_CODE(ValidateServiceName(name));
R_TRY(ValidateServiceName(name));
std::scoped_lock lk{lock};
if (registered_services.find(name) != registered_services.end()) {
@ -77,7 +76,7 @@ Result ServiceManager::RegisterService(std::string name, u32 max_sessions,
}
Result ServiceManager::UnregisterService(const std::string& name) {
CASCADE_CODE(ValidateServiceName(name));
R_TRY(ValidateServiceName(name));
std::scoped_lock lk{lock};
const auto iter = registered_services.find(name);
@ -92,8 +91,8 @@ Result ServiceManager::UnregisterService(const std::string& name) {
return ResultSuccess;
}
ResultVal<Kernel::KPort*> ServiceManager::GetServicePort(const std::string& name) {
CASCADE_CODE(ValidateServiceName(name));
Result ServiceManager::GetServicePort(Kernel::KPort** out_port, const std::string& name) {
R_TRY(ValidateServiceName(name));
std::scoped_lock lk{lock};
auto it = service_ports.find(name);
@ -102,7 +101,8 @@ ResultVal<Kernel::KPort*> ServiceManager::GetServicePort(const std::string& name
return Service::SM::ResultNotRegistered;
}
return it->second;
*out_port = it->second;
return ResultSuccess;
}
/**
@ -122,32 +122,34 @@ void SM::Initialize(HLERequestContext& ctx) {
}
void SM::GetService(HLERequestContext& ctx) {
auto result = GetServiceImpl(ctx);
Kernel::KClientSession* client_session{};
auto result = GetServiceImpl(&client_session, ctx);
if (ctx.GetIsDeferred()) {
// Don't overwrite the command buffer.
return;
}
if (result.Succeeded()) {
if (result == ResultSuccess) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
rb.Push(result.Code());
rb.PushMoveObjects(result.Unwrap());
rb.Push(result);
rb.PushMoveObjects(client_session);
} else {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result.Code());
rb.Push(result);
}
}
void SM::GetServiceTipc(HLERequestContext& ctx) {
auto result = GetServiceImpl(ctx);
Kernel::KClientSession* client_session{};
auto result = GetServiceImpl(&client_session, ctx);
if (ctx.GetIsDeferred()) {
// Don't overwrite the command buffer.
return;
}
IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
rb.Push(result.Code());
rb.PushMoveObjects(result.Succeeded() ? result.Unwrap() : nullptr);
rb.Push(result);
rb.PushMoveObjects(result == ResultSuccess ? client_session : nullptr);
}
static std::string PopServiceName(IPC::RequestParser& rp) {
@ -161,7 +163,7 @@ static std::string PopServiceName(IPC::RequestParser& rp) {
return result;
}
ResultVal<Kernel::KClientSession*> SM::GetServiceImpl(HLERequestContext& ctx) {
Result SM::GetServiceImpl(Kernel::KClientSession** out_client_session, HLERequestContext& ctx) {
if (!ctx.GetManager()->GetIsInitializedForSm()) {
return Service::SM::ResultInvalidClient;
}
@ -170,18 +172,18 @@ ResultVal<Kernel::KClientSession*> SM::GetServiceImpl(HLERequestContext& ctx) {
std::string name(PopServiceName(rp));
// Find the named port.
auto port_result = service_manager.GetServicePort(name);
if (port_result.Code() == Service::SM::ResultInvalidServiceName) {
Kernel::KPort* port{};
auto port_result = service_manager.GetServicePort(&port, name);
if (port_result == Service::SM::ResultInvalidServiceName) {
LOG_ERROR(Service_SM, "Invalid service name '{}'", name);
return Service::SM::ResultInvalidServiceName;
}
if (port_result.Failed()) {
if (port_result != ResultSuccess) {
LOG_INFO(Service_SM, "Waiting for service {} to become available", name);
ctx.SetIsDeferred();
return Service::SM::ResultNotRegistered;
}
auto& port = port_result.Unwrap();
// Create a new session.
Kernel::KClientSession* session{};
@ -192,7 +194,8 @@ ResultVal<Kernel::KClientSession*> SM::GetServiceImpl(HLERequestContext& ctx) {
LOG_DEBUG(Service_SM, "called service={} -> session={}", name, session->GetId());
return session;
*out_client_session = session;
return ResultSuccess;
}
void SM::RegisterService(HLERequestContext& ctx) {

View File

@ -42,7 +42,7 @@ private:
void RegisterService(HLERequestContext& ctx);
void UnregisterService(HLERequestContext& ctx);
ResultVal<Kernel::KClientSession*> GetServiceImpl(HLERequestContext& ctx);
Result GetServiceImpl(Kernel::KClientSession** out_client_session, HLERequestContext& ctx);
ServiceManager& service_manager;
Kernel::KernelCore& kernel;
@ -55,7 +55,7 @@ public:
Result RegisterService(std::string name, u32 max_sessions, SessionRequestHandlerPtr handler);
Result UnregisterService(const std::string& name);
ResultVal<Kernel::KPort*> GetServicePort(const std::string& name);
Result GetServicePort(Kernel::KPort** out_port, const std::string& name);
template <Common::DerivedFrom<SessionRequestHandler> T>
std::shared_ptr<T> GetService(const std::string& service_name) const {

View File

@ -54,7 +54,7 @@ NSD::NSD(Core::System& system_, const char* name) : ServiceFramework{system_, na
RegisterHandlers(functions);
}
static ResultVal<std::string> ResolveImpl(const std::string& fqdn_in) {
static std::string ResolveImpl(const std::string& fqdn_in) {
// The real implementation makes various substitutions.
// For now we just return the string as-is, which is good enough when not
// connecting to real Nintendo servers.
@ -64,13 +64,10 @@ static ResultVal<std::string> ResolveImpl(const std::string& fqdn_in) {
static Result ResolveCommon(const std::string& fqdn_in, std::array<char, 0x100>& fqdn_out) {
const auto res = ResolveImpl(fqdn_in);
if (res.Failed()) {
return res.Code();
}
if (res->size() >= fqdn_out.size()) {
if (res.size() >= fqdn_out.size()) {
return ResultOverflow;
}
std::memcpy(fqdn_out.data(), res->c_str(), res->size() + 1);
std::memcpy(fqdn_out.data(), res.c_str(), res.size() + 1);
return ResultSuccess;
}

View File

@ -19,7 +19,8 @@ namespace Service::SPL {
Module::Interface::Interface(Core::System& system_, std::shared_ptr<Module> module_,
const char* name)
: ServiceFramework{system_, name}, module{std::move(module_)},
rng(Settings::values.rng_seed.GetValue().value_or(std::time(nullptr))) {}
rng(Settings::values.rng_seed_enabled ? Settings::values.rng_seed.GetValue()
: static_cast<u32>(std::time(nullptr))) {}
Module::Interface::~Interface() = default;
@ -29,10 +30,10 @@ void Module::Interface::GetConfig(HLERequestContext& ctx) {
// This should call svcCallSecureMonitor with the appropriate args.
// Since we do not have it implemented yet, we will use this for now.
const auto smc_result = GetConfigImpl(config_item);
const auto result_code = smc_result.Code();
u64 smc_result{};
const auto result_code = GetConfigImpl(&smc_result, config_item);
if (smc_result.Failed()) {
if (result_code != ResultSuccess) {
LOG_ERROR(Service_SPL, "called, config_item={}, result_code={}", config_item,
result_code.raw);
@ -41,11 +42,11 @@ void Module::Interface::GetConfig(HLERequestContext& ctx) {
}
LOG_DEBUG(Service_SPL, "called, config_item={}, result_code={}, smc_result={}", config_item,
result_code.raw, *smc_result);
result_code.raw, smc_result);
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(result_code);
rb.Push(*smc_result);
rb.Push(smc_result);
}
void Module::Interface::ModularExponentiate(HLERequestContext& ctx) {
@ -98,7 +99,7 @@ void Module::Interface::GetBootReason(HLERequestContext& ctx) {
rb.Push(ResultSecureMonitorNotImplemented);
}
ResultVal<u64> Module::Interface::GetConfigImpl(ConfigItem config_item) const {
Result Module::Interface::GetConfigImpl(u64* out_config, ConfigItem config_item) const {
switch (config_item) {
case ConfigItem::DisableProgramVerification:
case ConfigItem::DramId:
@ -120,40 +121,50 @@ ResultVal<u64> Module::Interface::GetConfigImpl(ConfigItem config_item) const {
return ResultSecureMonitorNotImplemented;
case ConfigItem::ExosphereApiVersion:
// Get information about the current exosphere version.
return (u64{HLE::ApiVersion::ATMOSPHERE_RELEASE_VERSION_MAJOR} << 56) |
(u64{HLE::ApiVersion::ATMOSPHERE_RELEASE_VERSION_MINOR} << 48) |
(u64{HLE::ApiVersion::ATMOSPHERE_RELEASE_VERSION_MICRO} << 40) |
(static_cast<u64>(HLE::ApiVersion::GetTargetFirmware()));
*out_config = (u64{HLE::ApiVersion::ATMOSPHERE_RELEASE_VERSION_MAJOR} << 56) |
(u64{HLE::ApiVersion::ATMOSPHERE_RELEASE_VERSION_MINOR} << 48) |
(u64{HLE::ApiVersion::ATMOSPHERE_RELEASE_VERSION_MICRO} << 40) |
(static_cast<u64>(HLE::ApiVersion::GetTargetFirmware()));
return ResultSuccess;
case ConfigItem::ExosphereNeedsReboot:
// We are executing, so we aren't in the process of rebooting.
return u64{0};
*out_config = u64{0};
return ResultSuccess;
case ConfigItem::ExosphereNeedsShutdown:
// We are executing, so we aren't in the process of shutting down.
return u64{0};
*out_config = u64{0};
return ResultSuccess;
case ConfigItem::ExosphereGitCommitHash:
// Get information about the current exosphere git commit hash.
return u64{0};
*out_config = u64{0};
return ResultSuccess;
case ConfigItem::ExosphereHasRcmBugPatch:
// Get information about whether this unit has the RCM bug patched.
return u64{0};
*out_config = u64{0};
return ResultSuccess;
case ConfigItem::ExosphereBlankProdInfo:
// Get whether this unit should simulate a "blanked" PRODINFO.
return u64{0};
*out_config = u64{0};
return ResultSuccess;
case ConfigItem::ExosphereAllowCalWrites:
// Get whether this unit should allow writing to the calibration partition.
return u64{0};
*out_config = u64{0};
return ResultSuccess;
case ConfigItem::ExosphereEmummcType:
// Get what kind of emummc this unit has active.
return u64{0};
*out_config = u64{0};
return ResultSuccess;
case ConfigItem::ExospherePayloadAddress:
// Gets the physical address of the reboot payload buffer, if one exists.
return ResultSecureMonitorNotInitialized;
case ConfigItem::ExosphereLogConfiguration:
// Get the log configuration.
return u64{0};
*out_config = u64{0};
return ResultSuccess;
case ConfigItem::ExosphereForceEnableUsb30:
// Get whether usb 3.0 should be force-enabled.
return u64{0};
*out_config = u64{0};
return ResultSuccess;
default:
return ResultSecureMonitorInvalidArgument;
}

View File

@ -35,7 +35,7 @@ public:
std::shared_ptr<Module> module;
private:
ResultVal<u64> GetConfigImpl(ConfigItem config_item) const;
Result GetConfigImpl(u64* out_config, ConfigItem config_item) const;
std::mt19937 rng;
};

View File

@ -4,6 +4,7 @@
#include "common/string_util.h"
#include "core/core.h"
#include "core/hle/result.h"
#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/server_manager.h"
#include "core/hle/service/service.h"
@ -141,12 +142,12 @@ private:
bool did_set_host_name = false;
bool did_handshake = false;
ResultVal<s32> SetSocketDescriptorImpl(s32 fd) {
Result SetSocketDescriptorImpl(s32* out_fd, s32 fd) {
LOG_DEBUG(Service_SSL, "called, fd={}", fd);
ASSERT(!did_handshake);
auto bsd = system.ServiceManager().GetService<Service::Sockets::BSD>("bsd:u");
ASSERT_OR_EXECUTE(bsd, { return ResultInternalError; });
s32 ret_fd;
// Based on https://switchbrew.org/wiki/SSL_services#SetSocketDescriptor
if (do_not_close_socket) {
auto res = bsd->DuplicateSocketImpl(fd);
@ -156,9 +157,9 @@ private:
}
fd = *res;
fd_to_close = fd;
ret_fd = fd;
*out_fd = fd;
} else {
ret_fd = -1;
*out_fd = -1;
}
std::optional<std::shared_ptr<Network::SocketBase>> sock = bsd->GetSocket(fd);
if (!sock.has_value()) {
@ -167,7 +168,7 @@ private:
}
socket = std::move(*sock);
backend->SetSocket(socket);
return ret_fd;
return ResultSuccess;
}
Result SetHostNameImpl(const std::string& hostname) {
@ -247,34 +248,36 @@ private:
return ret;
}
ResultVal<std::vector<u8>> ReadImpl(size_t size) {
Result ReadImpl(std::vector<u8>* out_data, size_t size) {
ASSERT_OR_EXECUTE(did_handshake, { return ResultInternalError; });
std::vector<u8> res(size);
ResultVal<size_t> actual = backend->Read(res);
if (actual.Failed()) {
return actual.Code();
size_t actual_size{};
Result res = backend->Read(&actual_size, *out_data);
if (res != ResultSuccess) {
return res;
}
res.resize(*actual);
out_data->resize(actual_size);
return res;
}
ResultVal<size_t> WriteImpl(std::span<const u8> data) {
Result WriteImpl(size_t* out_size, std::span<const u8> data) {
ASSERT_OR_EXECUTE(did_handshake, { return ResultInternalError; });
return backend->Write(data);
return backend->Write(out_size, data);
}
ResultVal<s32> PendingImpl() {
Result PendingImpl(s32* out_pending) {
LOG_WARNING(Service_SSL, "(STUBBED) called.");
return 0;
*out_pending = 0;
return ResultSuccess;
}
void SetSocketDescriptor(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const s32 fd = rp.Pop<s32>();
const ResultVal<s32> res = SetSocketDescriptorImpl(fd);
const s32 in_fd = rp.Pop<s32>();
s32 out_fd{-1};
const Result res = SetSocketDescriptorImpl(&out_fd, in_fd);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(res.Code());
rb.Push<s32>(res.ValueOr(-1));
rb.Push(res);
rb.Push<s32>(out_fd);
}
void SetHostName(HLERequestContext& ctx) {
@ -313,14 +316,15 @@ private:
};
static_assert(sizeof(OutputParameters) == 0x8);
const Result res = DoHandshakeImpl();
Result res = DoHandshakeImpl();
OutputParameters out{};
if (res == ResultSuccess) {
auto certs = backend->GetServerCerts();
if (certs.Succeeded()) {
const std::vector<u8> certs_buf = SerializeServerCerts(*certs);
std::vector<std::vector<u8>> certs;
res = backend->GetServerCerts(&certs);
if (res == ResultSuccess) {
const std::vector<u8> certs_buf = SerializeServerCerts(certs);
ctx.WriteBuffer(certs_buf);
out.certs_count = static_cast<u32>(certs->size());
out.certs_count = static_cast<u32>(certs.size());
out.certs_size = static_cast<u32>(certs_buf.size());
}
}
@ -330,29 +334,32 @@ private:
}
void Read(HLERequestContext& ctx) {
const ResultVal<std::vector<u8>> res = ReadImpl(ctx.GetWriteBufferSize());
std::vector<u8> output_bytes;
const Result res = ReadImpl(&output_bytes, ctx.GetWriteBufferSize());
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(res.Code());
if (res.Succeeded()) {
rb.Push(static_cast<u32>(res->size()));
ctx.WriteBuffer(*res);
rb.Push(res);
if (res == ResultSuccess) {
rb.Push(static_cast<u32>(output_bytes.size()));
ctx.WriteBuffer(output_bytes);
} else {
rb.Push(static_cast<u32>(0));
}
}
void Write(HLERequestContext& ctx) {
const ResultVal<size_t> res = WriteImpl(ctx.ReadBuffer());
size_t write_size{0};
const Result res = WriteImpl(&write_size, ctx.ReadBuffer());
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(res.Code());
rb.Push(static_cast<u32>(res.ValueOr(0)));
rb.Push(res);
rb.Push(static_cast<u32>(write_size));
}
void Pending(HLERequestContext& ctx) {
const ResultVal<s32> res = PendingImpl();
s32 pending_size{0};
const Result res = PendingImpl(&pending_size);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(res.Code());
rb.Push<s32>(res.ValueOr(0));
rb.Push(res);
rb.Push<s32>(pending_size);
}
void SetSessionCacheMode(HLERequestContext& ctx) {
@ -438,13 +445,14 @@ private:
void CreateConnection(HLERequestContext& ctx) {
LOG_WARNING(Service_SSL, "called");
auto backend_res = CreateSSLConnectionBackend();
std::unique_ptr<SSLConnectionBackend> backend;
const Result res = CreateSSLConnectionBackend(&backend);
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(backend_res.Code());
if (backend_res.Succeeded()) {
rb.Push(res);
if (res == ResultSuccess) {
rb.PushIpcInterface<ISslConnection>(system, ssl_version, shared_data,
std::move(*backend_res));
std::move(backend));
}
}

View File

@ -35,11 +35,11 @@ public:
virtual void SetSocket(std::shared_ptr<Network::SocketBase> socket) = 0;
virtual Result SetHostName(const std::string& hostname) = 0;
virtual Result DoHandshake() = 0;
virtual ResultVal<size_t> Read(std::span<u8> data) = 0;
virtual ResultVal<size_t> Write(std::span<const u8> data) = 0;
virtual ResultVal<std::vector<std::vector<u8>>> GetServerCerts() = 0;
virtual Result Read(size_t* out_size, std::span<u8> data) = 0;
virtual Result Write(size_t* out_size, std::span<const u8> data) = 0;
virtual Result GetServerCerts(std::vector<std::vector<u8>>* out_certs) = 0;
};
ResultVal<std::unique_ptr<SSLConnectionBackend>> CreateSSLConnectionBackend();
Result CreateSSLConnectionBackend(std::unique_ptr<SSLConnectionBackend>* out_backend);
} // namespace Service::SSL

View File

@ -7,7 +7,7 @@
namespace Service::SSL {
ResultVal<std::unique_ptr<SSLConnectionBackend>> CreateSSLConnectionBackend() {
Result CreateSSLConnectionBackend(std::unique_ptr<SSLConnectionBackend>* out_backend) {
LOG_ERROR(Service_SSL,
"Can't create SSL connection because no SSL backend is available on this platform");
return ResultInternalError;

View File

@ -105,31 +105,30 @@ public:
return ResultInternalError;
}
}
return HandleReturn("SSL_do_handshake", 0, ret).Code();
return HandleReturn("SSL_do_handshake", 0, ret);
}
ResultVal<size_t> Read(std::span<u8> data) override {
size_t actual;
const int ret = SSL_read_ex(ssl, data.data(), data.size(), &actual);
return HandleReturn("SSL_read_ex", actual, ret);
Result Read(size_t* out_size, std::span<u8> data) override {
const int ret = SSL_read_ex(ssl, data.data(), data.size(), out_size);
return HandleReturn("SSL_read_ex", out_size, ret);
}
ResultVal<size_t> Write(std::span<const u8> data) override {
size_t actual;
const int ret = SSL_write_ex(ssl, data.data(), data.size(), &actual);
return HandleReturn("SSL_write_ex", actual, ret);
Result Write(size_t* out_size, std::span<const u8> data) override {
const int ret = SSL_write_ex(ssl, data.data(), data.size(), out_size);
return HandleReturn("SSL_write_ex", out_size, ret);
}
ResultVal<size_t> HandleReturn(const char* what, size_t actual, int ret) {
Result HandleReturn(const char* what, size_t* actual, int ret) {
const int ssl_err = SSL_get_error(ssl, ret);
CheckOpenSSLErrors();
switch (ssl_err) {
case SSL_ERROR_NONE:
return actual;
return ResultSuccess;
case SSL_ERROR_ZERO_RETURN:
LOG_DEBUG(Service_SSL, "{} => SSL_ERROR_ZERO_RETURN", what);
// DoHandshake special-cases this, but for Read and Write:
return size_t(0);
*actual = 0;
return ResultSuccess;
case SSL_ERROR_WANT_READ:
LOG_DEBUG(Service_SSL, "{} => SSL_ERROR_WANT_READ", what);
return ResultWouldBlock;
@ -139,20 +138,20 @@ public:
default:
if (ssl_err == SSL_ERROR_SYSCALL && got_read_eof) {
LOG_DEBUG(Service_SSL, "{} => SSL_ERROR_SYSCALL because server hung up", what);
return size_t(0);
*actual = 0;
return ResultSuccess;
}
LOG_ERROR(Service_SSL, "{} => other SSL_get_error return value {}", what, ssl_err);
return ResultInternalError;
}
}
ResultVal<std::vector<std::vector<u8>>> GetServerCerts() override {
Result GetServerCerts(std::vector<std::vector<u8>>* out_certs) override {
STACK_OF(X509)* chain = SSL_get_peer_cert_chain(ssl);
if (!chain) {
LOG_ERROR(Service_SSL, "SSL_get_peer_cert_chain returned nullptr");
return ResultInternalError;
}
std::vector<std::vector<u8>> ret;
int count = sk_X509_num(chain);
ASSERT(count >= 0);
for (int i = 0; i < count; i++) {
@ -161,10 +160,10 @@ public:
unsigned char* buf = nullptr;
int len = i2d_X509(x509, &buf);
ASSERT_OR_EXECUTE(len >= 0 && buf, { continue; });
ret.emplace_back(buf, buf + len);
out_certs->emplace_back(buf, buf + len);
OPENSSL_free(buf);
}
return ret;
return ResultSuccess;
}
~SSLConnectionBackendOpenSSL() {
@ -253,13 +252,13 @@ public:
std::shared_ptr<Network::SocketBase> socket;
};
ResultVal<std::unique_ptr<SSLConnectionBackend>> CreateSSLConnectionBackend() {
Result CreateSSLConnectionBackend(std::unique_ptr<SSLConnectionBackend>* out_backend) {
auto conn = std::make_unique<SSLConnectionBackendOpenSSL>();
const Result res = conn->Init();
if (res.IsFailure()) {
return res;
}
return conn;
R_TRY(conn->Init());
*out_backend = std::move(conn);
return ResultSuccess;
}
namespace {

View File

@ -299,21 +299,22 @@ public:
return ResultSuccess;
}
ResultVal<size_t> Read(std::span<u8> data) override {
Result Read(size_t* out_size, std::span<u8> data) override {
*out_size = 0;
if (handshake_state != HandshakeState::Connected) {
LOG_ERROR(Service_SSL, "Called Read but we did not successfully handshake");
return ResultInternalError;
}
if (data.size() == 0 || got_read_eof) {
return size_t(0);
return ResultSuccess;
}
while (1) {
if (!cleartext_read_buf.empty()) {
const size_t read_size = std::min(cleartext_read_buf.size(), data.size());
std::memcpy(data.data(), cleartext_read_buf.data(), read_size);
*out_size = std::min(cleartext_read_buf.size(), data.size());
std::memcpy(data.data(), cleartext_read_buf.data(), *out_size);
cleartext_read_buf.erase(cleartext_read_buf.begin(),
cleartext_read_buf.begin() + read_size);
return read_size;
cleartext_read_buf.begin() + *out_size);
return ResultSuccess;
}
if (!ciphertext_read_buf.empty()) {
SecBuffer empty{
@ -366,7 +367,8 @@ public:
case SEC_I_CONTEXT_EXPIRED:
// Server hung up by sending close_notify.
got_read_eof = true;
return size_t(0);
*out_size = 0;
return ResultSuccess;
default:
LOG_ERROR(Service_SSL, "DecryptMessage failed: {}",
Common::NativeErrorToString(ret));
@ -379,18 +381,21 @@ public:
}
if (ciphertext_read_buf.empty()) {
got_read_eof = true;
return size_t(0);
*out_size = 0;
return ResultSuccess;
}
}
}
ResultVal<size_t> Write(std::span<const u8> data) override {
Result Write(size_t* out_size, std::span<const u8> data) override {
*out_size = 0;
if (handshake_state != HandshakeState::Connected) {
LOG_ERROR(Service_SSL, "Called Write but we did not successfully handshake");
return ResultInternalError;
}
if (data.size() == 0) {
return size_t(0);
return ResultSuccess;
}
data = data.subspan(0, std::min<size_t>(data.size(), stream_sizes.cbMaximumMessage));
if (!cleartext_write_buf.empty()) {
@ -402,7 +407,7 @@ public:
LOG_ERROR(Service_SSL, "Called Write but buffer does not match previous buffer");
return ResultInternalError;
}
return WriteAlreadyEncryptedData();
return WriteAlreadyEncryptedData(out_size);
} else {
cleartext_write_buf.assign(data.begin(), data.end());
}
@ -448,21 +453,21 @@ public:
tmp_data_buf.end());
ciphertext_write_buf.insert(ciphertext_write_buf.end(), trailer_buf.begin(),
trailer_buf.end());
return WriteAlreadyEncryptedData();
return WriteAlreadyEncryptedData(out_size);
}
ResultVal<size_t> WriteAlreadyEncryptedData() {
Result WriteAlreadyEncryptedData(size_t* out_size) {
const Result r = FlushCiphertextWriteBuf();
if (r != ResultSuccess) {
return r;
}
// write buf is empty
const size_t cleartext_bytes_written = cleartext_write_buf.size();
*out_size = cleartext_write_buf.size();
cleartext_write_buf.clear();
return cleartext_bytes_written;
return ResultSuccess;
}
ResultVal<std::vector<std::vector<u8>>> GetServerCerts() override {
Result GetServerCerts(std::vector<std::vector<u8>>* out_certs) override {
PCCERT_CONTEXT returned_cert = nullptr;
const SECURITY_STATUS ret =
QueryContextAttributes(&ctxt, SECPKG_ATTR_REMOTE_CERT_CONTEXT, &returned_cert);
@ -473,16 +478,15 @@ public:
return ResultInternalError;
}
PCCERT_CONTEXT some_cert = nullptr;
std::vector<std::vector<u8>> certs;
while ((some_cert = CertEnumCertificatesInStore(returned_cert->hCertStore, some_cert))) {
certs.emplace_back(static_cast<u8*>(some_cert->pbCertEncoded),
static_cast<u8*>(some_cert->pbCertEncoded) +
some_cert->cbCertEncoded);
out_certs->emplace_back(static_cast<u8*>(some_cert->pbCertEncoded),
static_cast<u8*>(some_cert->pbCertEncoded) +
some_cert->cbCertEncoded);
}
std::reverse(certs.begin(),
certs.end()); // Windows returns certs in reverse order from what we want
std::reverse(out_certs->begin(),
out_certs->end()); // Windows returns certs in reverse order from what we want
CertFreeCertificateContext(returned_cert);
return certs;
return ResultSuccess;
}
~SSLConnectionBackendSchannel() {
@ -532,13 +536,13 @@ public:
size_t read_buf_fill_size = 0;
};
ResultVal<std::unique_ptr<SSLConnectionBackend>> CreateSSLConnectionBackend() {
Result CreateSSLConnectionBackend(std::unique_ptr<SSLConnectionBackend>* out_backend) {
auto conn = std::make_unique<SSLConnectionBackendSchannel>();
const Result res = conn->Init();
if (res.IsFailure()) {
return res;
}
return conn;
R_TRY(conn->Init());
*out_backend = std::move(conn);
return ResultSuccess;
}
} // namespace Service::SSL

View File

@ -100,27 +100,23 @@ public:
Result DoHandshake() override {
OSStatus status = SSLHandshake(context);
return HandleReturn("SSLHandshake", 0, status).Code();
return HandleReturn("SSLHandshake", 0, status);
}
ResultVal<size_t> Read(std::span<u8> data) override {
size_t actual;
OSStatus status = SSLRead(context, data.data(), data.size(), &actual);
;
return HandleReturn("SSLRead", actual, status);
Result Read(size_t* out_size, std::span<u8> data) override {
OSStatus status = SSLRead(context, data.data(), data.size(), out_size);
return HandleReturn("SSLRead", out_size, status);
}
ResultVal<size_t> Write(std::span<const u8> data) override {
size_t actual;
OSStatus status = SSLWrite(context, data.data(), data.size(), &actual);
;
return HandleReturn("SSLWrite", actual, status);
Result Write(size_t* out_size, std::span<const u8> data) override {
OSStatus status = SSLWrite(context, data.data(), data.size(), out_size);
return HandleReturn("SSLWrite", out_size, status);
}
ResultVal<size_t> HandleReturn(const char* what, size_t actual, OSStatus status) {
Result HandleReturn(const char* what, size_t* actual, OSStatus status) {
switch (status) {
case 0:
return actual;
return ResultSuccess;
case errSSLWouldBlock:
return ResultWouldBlock;
default: {
@ -136,22 +132,21 @@ public:
}
}
ResultVal<std::vector<std::vector<u8>>> GetServerCerts() override {
Result GetServerCerts(std::vector<std::vector<u8>>* out_certs) override {
CFReleaser<SecTrustRef> trust;
OSStatus status = SSLCopyPeerTrust(context, &trust.ptr);
if (status) {
LOG_ERROR(Service_SSL, "SSLCopyPeerTrust failed: {}", OSStatusToString(status));
return ResultInternalError;
}
std::vector<std::vector<u8>> ret;
for (CFIndex i = 0, count = SecTrustGetCertificateCount(trust); i < count; i++) {
SecCertificateRef cert = SecTrustGetCertificateAtIndex(trust, i);
CFReleaser<CFDataRef> data(SecCertificateCopyData(cert));
ASSERT_OR_EXECUTE(data, { return ResultInternalError; });
const u8* ptr = CFDataGetBytePtr(data);
ret.emplace_back(ptr, ptr + CFDataGetLength(data));
out_certs->emplace_back(ptr, ptr + CFDataGetLength(data));
}
return ret;
return ResultSuccess;
}
static OSStatus ReadCallback(SSLConnectionRef connection, void* data, size_t* dataLength) {
@ -210,13 +205,13 @@ private:
std::shared_ptr<Network::SocketBase> socket;
};
ResultVal<std::unique_ptr<SSLConnectionBackend>> CreateSSLConnectionBackend() {
Result CreateSSLConnectionBackend(std::unique_ptr<SSLConnectionBackend>* out_backend) {
auto conn = std::make_unique<SSLConnectionBackendSecureTransport>();
const Result res = conn->Init();
if (res.IsFailure()) {
return res;
}
return conn;
R_TRY(conn->Init());
*out_backend = std::move(conn);
return ResultSuccess;
}
} // namespace Service::SSL

View File

@ -78,7 +78,8 @@ TimeZoneContentManager::TimeZoneContentManager(Core::System& system_)
location_name_cache{BuildLocationNameCache(time_zone_binary)} {}
void TimeZoneContentManager::Initialize(TimeManager& time_manager) {
const auto timezone_setting = Settings::GetTimeZoneString();
const auto timezone_setting =
Settings::GetTimeZoneString(Settings::values.time_zone_index.GetValue());
if (FileSys::VirtualFile vfs_file;
GetTimeZoneInfoFile(timezone_setting, vfs_file) == ResultSuccess) {

View File

@ -58,14 +58,15 @@ const Layer& Display::GetLayer(std::size_t index) const {
return *layers.at(index);
}
ResultVal<Kernel::KReadableEvent*> Display::GetVSyncEvent() {
Result Display::GetVSyncEvent(Kernel::KReadableEvent** out_vsync_event) {
if (got_vsync_event) {
return ResultPermissionDenied;
}
got_vsync_event = true;
return GetVSyncEventUnchecked();
*out_vsync_event = GetVSyncEventUnchecked();
return ResultSuccess;
}
Kernel::KReadableEvent* Display::GetVSyncEventUnchecked() {

View File

@ -85,7 +85,7 @@ public:
* @returns The internal Vsync event if it has not yet been retrieved,
* VI::ResultPermissionDenied otherwise.
*/
[[nodiscard]] ResultVal<Kernel::KReadableEvent*> GetVSyncEvent();
[[nodiscard]] Result GetVSyncEvent(Kernel::KReadableEvent** out_vsync_event);
/// Gets the internal vsync event.
Kernel::KReadableEvent* GetVSyncEventUnchecked();

View File

@ -683,9 +683,9 @@ private:
LOG_DEBUG(Service_VI, "called. display_id={}", display_id);
const auto vsync_event = nv_flinger.FindVsyncEvent(display_id);
if (vsync_event.Failed()) {
const auto result = vsync_event.Code();
Kernel::KReadableEvent* vsync_event{};
const auto result = nv_flinger.FindVsyncEvent(&vsync_event, display_id);
if (result != ResultSuccess) {
if (result == ResultNotFound) {
LOG_ERROR(Service_VI, "Vsync event was not found for display_id={}", display_id);
}
@ -697,7 +697,7 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(ResultSuccess);
rb.PushCopyObjects(*vsync_event);
rb.PushCopyObjects(vsync_event);
}
void ConvertScalingMode(HLERequestContext& ctx) {
@ -705,15 +705,16 @@ private:
const auto mode = rp.PopEnum<NintendoScaleMode>();
LOG_DEBUG(Service_VI, "called mode={}", mode);
const auto converted_mode = ConvertScalingModeImpl(mode);
ConvertedScaleMode converted_mode{};
const auto result = ConvertScalingModeImpl(&converted_mode, mode);
if (converted_mode.Succeeded()) {
if (result == ResultSuccess) {
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.PushEnum(*converted_mode);
rb.PushEnum(converted_mode);
} else {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(converted_mode.Code());
rb.Push(result);
}
}
@ -760,18 +761,24 @@ private:
rb.Push(alignment);
}
static ResultVal<ConvertedScaleMode> ConvertScalingModeImpl(NintendoScaleMode mode) {
static Result ConvertScalingModeImpl(ConvertedScaleMode* out_scaling_mode,
NintendoScaleMode mode) {
switch (mode) {
case NintendoScaleMode::None:
return ConvertedScaleMode::None;
*out_scaling_mode = ConvertedScaleMode::None;
return ResultSuccess;
case NintendoScaleMode::Freeze:
return ConvertedScaleMode::Freeze;
*out_scaling_mode = ConvertedScaleMode::Freeze;
return ResultSuccess;
case NintendoScaleMode::ScaleToWindow:
return ConvertedScaleMode::ScaleToWindow;
*out_scaling_mode = ConvertedScaleMode::ScaleToWindow;
return ResultSuccess;
case NintendoScaleMode::ScaleAndCrop:
return ConvertedScaleMode::ScaleAndCrop;
*out_scaling_mode = ConvertedScaleMode::ScaleAndCrop;
return ResultSuccess;
case NintendoScaleMode::PreserveAspectRatio:
return ConvertedScaleMode::PreserveAspectRatio;
*out_scaling_mode = ConvertedScaleMode::PreserveAspectRatio;
return ResultSuccess;
default:
LOG_ERROR(Service_VI, "Invalid scaling mode specified, mode={}", mode);
return ResultOperationFailed;

View File

@ -476,7 +476,13 @@ NetworkInstance::~NetworkInstance() {
std::optional<IPv4Address> GetHostIPv4Address() {
const auto network_interface = Network::GetSelectedNetworkInterface();
if (!network_interface.has_value()) {
LOG_DEBUG(Network, "GetSelectedNetworkInterface returned no interface");
// Only print the error once to avoid log spam
static bool print_error = true;
if (print_error) {
LOG_ERROR(Network, "GetSelectedNetworkInterface returned no interface");
print_error = false;
}
return {};
}

View File

@ -200,7 +200,14 @@ std::optional<NetworkInterface> GetSelectedNetworkInterface() {
});
if (res == network_interfaces.end()) {
LOG_DEBUG(Network, "Couldn't find selected interface \"{}\"", selected_network_interface);
// Only print the error once to avoid log spam
static bool print_error = true;
if (print_error) {
LOG_ERROR(Network, "Couldn't find selected interface \"{}\"",
selected_network_interface);
print_error = false;
}
return std::nullopt;
}

Some files were not shown because too many files have changed in this diff Show More