summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
m---------externals/SDL0
m---------externals/dynarmic0
-rw-r--r--src/common/logging/filter.cpp2
-rw-r--r--src/common/logging/types.h2
-rw-r--r--src/common/settings.cpp1
-rw-r--r--src/common/settings.h67
-rw-r--r--src/common/wall_clock.cpp2
-rw-r--r--src/common/x64/cpu_detect.cpp16
-rw-r--r--src/common/x64/cpu_detect.h5
-rw-r--r--src/core/CMakeLists.txt4
-rw-r--r--src/core/arm/arm_interface.cpp1
-rw-r--r--src/core/arm/arm_interface.h2
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_32.cpp10
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_64.cpp10
-rw-r--r--src/core/hle/service/acc/acc.cpp20
-rw-r--r--src/core/hle/service/acc/profile_manager.cpp11
-rw-r--r--src/core/hle/service/acc/profile_manager.h15
-rw-r--r--src/core/hle/service/am/am.cpp7
-rw-r--r--src/core/hle/service/am/am.h1
-rw-r--r--src/core/hle/service/bcat/bcat_module.cpp4
-rw-r--r--src/core/hle/service/btdrv/btdrv.cpp5
-rw-r--r--src/core/hle/service/btm/btm.cpp8
-rw-r--r--src/core/hle/service/fatal/fatal_p.cpp8
-rw-r--r--src/core/hle/service/nifm/nifm.cpp42
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.cpp18
-rw-r--r--src/core/hle/service/ptm/psm.cpp122
-rw-r--r--src/core/hle/service/ptm/psm.h31
-rw-r--r--src/core/hle/service/ptm/ptm.cpp18
-rw-r--r--src/core/hle/service/ptm/ptm.h18
-rw-r--r--src/core/hle/service/ptm/ts.cpp41
-rw-r--r--src/core/hle/service/ptm/ts.h25
-rw-r--r--src/core/hle/service/service.cpp4
-rw-r--r--src/video_core/renderer_vulkan/vk_swapchain.cpp6
-rw-r--r--src/yuzu/configuration/config.cpp18
-rw-r--r--src/yuzu/configuration/config.h16
-rw-r--r--src/yuzu/configuration/configuration_shared.h10
-rw-r--r--src/yuzu/configuration/configure_general.cpp24
-rw-r--r--src/yuzu/configuration/configure_general.ui81
-rw-r--r--src/yuzu/configuration/configure_input.ui2
-rw-r--r--src/yuzu/main.cpp24
-rw-r--r--src/yuzu/main.h1
-rw-r--r--src/yuzu_cmd/config.cpp6
-rw-r--r--src/yuzu_cmd/config.h4
-rw-r--r--src/yuzu_cmd/default_ini.h7
44 files changed, 402 insertions, 317 deletions
diff --git a/externals/SDL b/externals/SDL
Subproject e2ade2bfc46d915cd306c63c830b81d800b2575 Subproject b424665e0899769b200231ba943353a5fee1b6b
diff --git a/externals/dynarmic b/externals/dynarmic
Subproject 9ebf6a8384836322ce58beb7ca10f5d4c66e921 Subproject 91d1f944e3870e0f3c505b48f5ec00ca9a82b95
diff --git a/src/common/logging/filter.cpp b/src/common/logging/filter.cpp
index 4acbff649..6de9bacbf 100644
--- a/src/common/logging/filter.cpp
+++ b/src/common/logging/filter.cpp
@@ -128,7 +128,7 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) {
128 SUB(Service, PM) \ 128 SUB(Service, PM) \
129 SUB(Service, PREPO) \ 129 SUB(Service, PREPO) \
130 SUB(Service, PSC) \ 130 SUB(Service, PSC) \
131 SUB(Service, PSM) \ 131 SUB(Service, PTM) \
132 SUB(Service, SET) \ 132 SUB(Service, SET) \
133 SUB(Service, SM) \ 133 SUB(Service, SM) \
134 SUB(Service, SPL) \ 134 SUB(Service, SPL) \
diff --git a/src/common/logging/types.h b/src/common/logging/types.h
index cabb4db8e..595c15ada 100644
--- a/src/common/logging/types.h
+++ b/src/common/logging/types.h
@@ -95,7 +95,7 @@ enum class Class : u8 {
95 Service_PM, ///< The PM service 95 Service_PM, ///< The PM service
96 Service_PREPO, ///< The PREPO (Play report) service 96 Service_PREPO, ///< The PREPO (Play report) service
97 Service_PSC, ///< The PSC service 97 Service_PSC, ///< The PSC service
98 Service_PSM, ///< The PSM service 98 Service_PTM, ///< The PTM service
99 Service_SET, ///< The SET (Settings) service 99 Service_SET, ///< The SET (Settings) service
100 Service_SM, ///< The SM (Service manager) service 100 Service_SM, ///< The SM (Service manager) service
101 Service_SPL, ///< The SPL service 101 Service_SPL, ///< The SPL service
diff --git a/src/common/settings.cpp b/src/common/settings.cpp
index 751549583..d4c52989a 100644
--- a/src/common/settings.cpp
+++ b/src/common/settings.cpp
@@ -185,7 +185,6 @@ void RestoreGlobalState(bool is_powered_on) {
185 values.max_anisotropy.SetGlobal(true); 185 values.max_anisotropy.SetGlobal(true);
186 values.use_speed_limit.SetGlobal(true); 186 values.use_speed_limit.SetGlobal(true);
187 values.speed_limit.SetGlobal(true); 187 values.speed_limit.SetGlobal(true);
188 values.fps_cap.SetGlobal(true);
189 values.use_disk_shader_cache.SetGlobal(true); 188 values.use_disk_shader_cache.SetGlobal(true);
190 values.gpu_accuracy.SetGlobal(true); 189 values.gpu_accuracy.SetGlobal(true);
191 values.use_asynchronous_gpu_emulation.SetGlobal(true); 190 values.use_asynchronous_gpu_emulation.SetGlobal(true);
diff --git a/src/common/settings.h b/src/common/settings.h
index 3583a2e70..2bccb8642 100644
--- a/src/common/settings.h
+++ b/src/common/settings.h
@@ -106,7 +106,7 @@ struct ResolutionScalingInfo {
106 * configurations. Specifying a default value and label is required. A minimum and maximum range can 106 * configurations. Specifying a default value and label is required. A minimum and maximum range can
107 * be specified for sanitization. 107 * be specified for sanitization.
108 */ 108 */
109template <typename Type> 109template <typename Type, bool ranged = false>
110class Setting { 110class Setting {
111protected: 111protected:
112 Setting() = default; 112 Setting() = default;
@@ -126,8 +126,8 @@ public:
126 * @param default_val Intial value of the setting, and default value of the setting 126 * @param default_val Intial value of the setting, and default value of the setting
127 * @param name Label for the setting 127 * @param name Label for the setting
128 */ 128 */
129 explicit Setting(const Type& default_val, const std::string& name) 129 explicit Setting(const Type& default_val, const std::string& name) requires(!ranged)
130 : value{default_val}, default_value{default_val}, ranged{false}, label{name} {} 130 : value{default_val}, default_value{default_val}, label{name} {}
131 virtual ~Setting() = default; 131 virtual ~Setting() = default;
132 132
133 /** 133 /**
@@ -139,9 +139,9 @@ public:
139 * @param name Label for the setting 139 * @param name Label for the setting
140 */ 140 */
141 explicit Setting(const Type& default_val, const Type& min_val, const Type& max_val, 141 explicit Setting(const Type& default_val, const Type& min_val, const Type& max_val,
142 const std::string& name) 142 const std::string& name) requires(ranged)
143 : value{default_val}, default_value{default_val}, maximum{max_val}, minimum{min_val}, 143 : value{default_val},
144 ranged{true}, label{name} {} 144 default_value{default_val}, maximum{max_val}, minimum{min_val}, label{name} {}
145 145
146 /** 146 /**
147 * Returns a reference to the setting's value. 147 * Returns a reference to the setting's value.
@@ -158,7 +158,7 @@ public:
158 * @param val The desired value 158 * @param val The desired value
159 */ 159 */
160 virtual void SetValue(const Type& val) { 160 virtual void SetValue(const Type& val) {
161 Type temp{(ranged) ? std::clamp(val, minimum, maximum) : val}; 161 Type temp{ranged ? std::clamp(val, minimum, maximum) : val};
162 std::swap(value, temp); 162 std::swap(value, temp);
163 } 163 }
164 164
@@ -188,7 +188,7 @@ public:
188 * @returns A reference to the setting 188 * @returns A reference to the setting
189 */ 189 */
190 virtual const Type& operator=(const Type& val) { 190 virtual const Type& operator=(const Type& val) {
191 Type temp{(ranged) ? std::clamp(val, minimum, maximum) : val}; 191 Type temp{ranged ? std::clamp(val, minimum, maximum) : val};
192 std::swap(value, temp); 192 std::swap(value, temp);
193 return value; 193 return value;
194 } 194 }
@@ -207,7 +207,6 @@ protected:
207 const Type default_value{}; ///< The default value 207 const Type default_value{}; ///< The default value
208 const Type maximum{}; ///< Maximum allowed value of the setting 208 const Type maximum{}; ///< Maximum allowed value of the setting
209 const Type minimum{}; ///< Minimum allowed value of the setting 209 const Type minimum{}; ///< Minimum allowed value of the setting
210 const bool ranged; ///< The setting has sanitization ranges
211 const std::string label{}; ///< The setting's label 210 const std::string label{}; ///< The setting's label
212}; 211};
213 212
@@ -219,8 +218,8 @@ protected:
219 * 218 *
220 * By default, the global setting is used. 219 * By default, the global setting is used.
221 */ 220 */
222template <typename Type> 221template <typename Type, bool ranged = false>
223class SwitchableSetting : virtual public Setting<Type> { 222class SwitchableSetting : virtual public Setting<Type, ranged> {
224public: 223public:
225 /** 224 /**
226 * Sets a default value, label, and setting value. 225 * Sets a default value, label, and setting value.
@@ -228,7 +227,7 @@ public:
228 * @param default_val Intial value of the setting, and default value of the setting 227 * @param default_val Intial value of the setting, and default value of the setting
229 * @param name Label for the setting 228 * @param name Label for the setting
230 */ 229 */
231 explicit SwitchableSetting(const Type& default_val, const std::string& name) 230 explicit SwitchableSetting(const Type& default_val, const std::string& name) requires(!ranged)
232 : Setting<Type>{default_val, name} {} 231 : Setting<Type>{default_val, name} {}
233 virtual ~SwitchableSetting() = default; 232 virtual ~SwitchableSetting() = default;
234 233
@@ -241,8 +240,8 @@ public:
241 * @param name Label for the setting 240 * @param name Label for the setting
242 */ 241 */
243 explicit SwitchableSetting(const Type& default_val, const Type& min_val, const Type& max_val, 242 explicit SwitchableSetting(const Type& default_val, const Type& min_val, const Type& max_val,
244 const std::string& name) 243 const std::string& name) requires(ranged)
245 : Setting<Type>{default_val, min_val, max_val, name} {} 244 : Setting<Type, true>{default_val, min_val, max_val, name} {}
246 245
247 /** 246 /**
248 * Tells this setting to represent either the global or custom setting when other member 247 * Tells this setting to represent either the global or custom setting when other member
@@ -290,7 +289,7 @@ public:
290 * @param val The new value 289 * @param val The new value
291 */ 290 */
292 void SetValue(const Type& val) override { 291 void SetValue(const Type& val) override {
293 Type temp{(this->ranged) ? std::clamp(val, this->minimum, this->maximum) : val}; 292 Type temp{ranged ? std::clamp(val, this->minimum, this->maximum) : val};
294 if (use_global) { 293 if (use_global) {
295 std::swap(this->value, temp); 294 std::swap(this->value, temp);
296 } else { 295 } else {
@@ -306,7 +305,7 @@ public:
306 * @returns A reference to the current setting value 305 * @returns A reference to the current setting value
307 */ 306 */
308 const Type& operator=(const Type& val) override { 307 const Type& operator=(const Type& val) override {
309 Type temp{(this->ranged) ? std::clamp(val, this->minimum, this->maximum) : val}; 308 Type temp{ranged ? std::clamp(val, this->minimum, this->maximum) : val};
310 if (use_global) { 309 if (use_global) {
311 std::swap(this->value, temp); 310 std::swap(this->value, temp);
312 return this->value; 311 return this->value;
@@ -374,15 +373,15 @@ struct Values {
374 Setting<std::string> audio_device_id{"auto", "output_device"}; 373 Setting<std::string> audio_device_id{"auto", "output_device"};
375 Setting<std::string> sink_id{"auto", "output_engine"}; 374 Setting<std::string> sink_id{"auto", "output_engine"};
376 Setting<bool> audio_muted{false, "audio_muted"}; 375 Setting<bool> audio_muted{false, "audio_muted"};
377 SwitchableSetting<u8> volume{100, 0, 100, "volume"}; 376 SwitchableSetting<u8, true> volume{100, 0, 100, "volume"};
378 377
379 // Core 378 // Core
380 SwitchableSetting<bool> use_multi_core{true, "use_multi_core"}; 379 SwitchableSetting<bool> use_multi_core{true, "use_multi_core"};
381 SwitchableSetting<bool> use_extended_memory_layout{false, "use_extended_memory_layout"}; 380 SwitchableSetting<bool> use_extended_memory_layout{false, "use_extended_memory_layout"};
382 381
383 // Cpu 382 // Cpu
384 SwitchableSetting<CPUAccuracy> cpu_accuracy{CPUAccuracy::Auto, CPUAccuracy::Auto, 383 SwitchableSetting<CPUAccuracy, true> cpu_accuracy{CPUAccuracy::Auto, CPUAccuracy::Auto,
385 CPUAccuracy::Paranoid, "cpu_accuracy"}; 384 CPUAccuracy::Paranoid, "cpu_accuracy"};
386 // TODO: remove cpu_accuracy_first_time, migration setting added 8 July 2021 385 // TODO: remove cpu_accuracy_first_time, migration setting added 8 July 2021
387 Setting<bool> cpu_accuracy_first_time{true, "cpu_accuracy_first_time"}; 386 Setting<bool> cpu_accuracy_first_time{true, "cpu_accuracy_first_time"};
388 Setting<bool> cpu_debug_mode{false, "cpu_debug_mode"}; 387 Setting<bool> cpu_debug_mode{false, "cpu_debug_mode"};
@@ -409,7 +408,7 @@ struct Values {
409 true, "cpuopt_unsafe_ignore_global_monitor"}; 408 true, "cpuopt_unsafe_ignore_global_monitor"};
410 409
411 // Renderer 410 // Renderer
412 SwitchableSetting<RendererBackend> renderer_backend{ 411 SwitchableSetting<RendererBackend, true> renderer_backend{
413 RendererBackend::Vulkan, RendererBackend::OpenGL, RendererBackend::Vulkan, "backend"}; 412 RendererBackend::Vulkan, RendererBackend::OpenGL, RendererBackend::Vulkan, "backend"};
414 Setting<bool> renderer_debug{false, "debug"}; 413 Setting<bool> renderer_debug{false, "debug"};
415 Setting<bool> renderer_shader_feedback{false, "shader_feedback"}; 414 Setting<bool> renderer_shader_feedback{false, "shader_feedback"};
@@ -423,28 +422,26 @@ struct Values {
423 SwitchableSetting<AntiAliasing> anti_aliasing{AntiAliasing::None, "anti_aliasing"}; 422 SwitchableSetting<AntiAliasing> anti_aliasing{AntiAliasing::None, "anti_aliasing"};
424 // *nix platforms may have issues with the borderless windowed fullscreen mode. 423 // *nix platforms may have issues with the borderless windowed fullscreen mode.
425 // Default to exclusive fullscreen on these platforms for now. 424 // Default to exclusive fullscreen on these platforms for now.
426 SwitchableSetting<FullscreenMode> fullscreen_mode{ 425 SwitchableSetting<FullscreenMode, true> fullscreen_mode{
427#ifdef _WIN32 426#ifdef _WIN32
428 FullscreenMode::Borderless, 427 FullscreenMode::Borderless,
429#else 428#else
430 FullscreenMode::Exclusive, 429 FullscreenMode::Exclusive,
431#endif 430#endif
432 FullscreenMode::Borderless, FullscreenMode::Exclusive, "fullscreen_mode"}; 431 FullscreenMode::Borderless, FullscreenMode::Exclusive, "fullscreen_mode"};
433 SwitchableSetting<int> aspect_ratio{0, 0, 3, "aspect_ratio"}; 432 SwitchableSetting<int, true> aspect_ratio{0, 0, 3, "aspect_ratio"};
434 SwitchableSetting<int> max_anisotropy{0, 0, 5, "max_anisotropy"}; 433 SwitchableSetting<int, true> max_anisotropy{0, 0, 5, "max_anisotropy"};
435 SwitchableSetting<bool> use_speed_limit{true, "use_speed_limit"}; 434 SwitchableSetting<bool> use_speed_limit{true, "use_speed_limit"};
436 SwitchableSetting<u16> speed_limit{100, 0, 9999, "speed_limit"}; 435 SwitchableSetting<u16, true> speed_limit{100, 0, 9999, "speed_limit"};
437 SwitchableSetting<bool> use_disk_shader_cache{true, "use_disk_shader_cache"}; 436 SwitchableSetting<bool> use_disk_shader_cache{true, "use_disk_shader_cache"};
438 SwitchableSetting<GPUAccuracy> gpu_accuracy{GPUAccuracy::High, GPUAccuracy::Normal, 437 SwitchableSetting<GPUAccuracy, true> gpu_accuracy{GPUAccuracy::High, GPUAccuracy::Normal,
439 GPUAccuracy::Extreme, "gpu_accuracy"}; 438 GPUAccuracy::Extreme, "gpu_accuracy"};
440 SwitchableSetting<bool> use_asynchronous_gpu_emulation{true, "use_asynchronous_gpu_emulation"}; 439 SwitchableSetting<bool> use_asynchronous_gpu_emulation{true, "use_asynchronous_gpu_emulation"};
441 SwitchableSetting<NvdecEmulation> nvdec_emulation{NvdecEmulation::GPU, "nvdec_emulation"}; 440 SwitchableSetting<NvdecEmulation> nvdec_emulation{NvdecEmulation::GPU, "nvdec_emulation"};
442 SwitchableSetting<bool> accelerate_astc{true, "accelerate_astc"}; 441 SwitchableSetting<bool> accelerate_astc{true, "accelerate_astc"};
443 SwitchableSetting<bool> use_vsync{true, "use_vsync"}; 442 SwitchableSetting<bool> use_vsync{true, "use_vsync"};
444 SwitchableSetting<u16> fps_cap{1000, 1, 1000, "fps_cap"}; 443 SwitchableSetting<ShaderBackend, true> shader_backend{ShaderBackend::GLASM, ShaderBackend::GLSL,
445 Setting<bool> disable_fps_limit{false, "disable_fps_limit"}; 444 ShaderBackend::SPIRV, "shader_backend"};
446 SwitchableSetting<ShaderBackend> shader_backend{ShaderBackend::GLASM, ShaderBackend::GLSL,
447 ShaderBackend::SPIRV, "shader_backend"};
448 SwitchableSetting<bool> use_asynchronous_shaders{false, "use_asynchronous_shaders"}; 445 SwitchableSetting<bool> use_asynchronous_shaders{false, "use_asynchronous_shaders"};
449 SwitchableSetting<bool> use_fast_gpu_time{true, "use_fast_gpu_time"}; 446 SwitchableSetting<bool> use_fast_gpu_time{true, "use_fast_gpu_time"};
450 447
@@ -460,10 +457,10 @@ struct Values {
460 s64 custom_rtc_differential; 457 s64 custom_rtc_differential;
461 458
462 Setting<s32> current_user{0, "current_user"}; 459 Setting<s32> current_user{0, "current_user"};
463 SwitchableSetting<s32> language_index{1, 0, 17, "language_index"}; 460 SwitchableSetting<s32, true> language_index{1, 0, 17, "language_index"};
464 SwitchableSetting<s32> region_index{1, 0, 6, "region_index"}; 461 SwitchableSetting<s32, true> region_index{1, 0, 6, "region_index"};
465 SwitchableSetting<s32> time_zone_index{0, 0, 45, "time_zone_index"}; 462 SwitchableSetting<s32, true> time_zone_index{0, 0, 45, "time_zone_index"};
466 SwitchableSetting<s32> sound_index{1, 0, 2, "sound_index"}; 463 SwitchableSetting<s32, true> sound_index{1, 0, 2, "sound_index"};
467 464
468 // Controls 465 // Controls
469 InputSetting<std::array<PlayerInput, 10>> players; 466 InputSetting<std::array<PlayerInput, 10>> players;
@@ -485,7 +482,7 @@ struct Values {
485 Setting<bool> tas_loop{false, "tas_loop"}; 482 Setting<bool> tas_loop{false, "tas_loop"};
486 483
487 Setting<bool> mouse_panning{false, "mouse_panning"}; 484 Setting<bool> mouse_panning{false, "mouse_panning"};
488 Setting<u8> mouse_panning_sensitivity{10, 1, 100, "mouse_panning_sensitivity"}; 485 Setting<u8, true> mouse_panning_sensitivity{10, 1, 100, "mouse_panning_sensitivity"};
489 Setting<bool> mouse_enabled{false, "mouse_enabled"}; 486 Setting<bool> mouse_enabled{false, "mouse_enabled"};
490 487
491 Setting<bool> emulate_analog_keyboard{false, "emulate_analog_keyboard"}; 488 Setting<bool> emulate_analog_keyboard{false, "emulate_analog_keyboard"};
diff --git a/src/common/wall_clock.cpp b/src/common/wall_clock.cpp
index b4fb3a59f..ae07f2811 100644
--- a/src/common/wall_clock.cpp
+++ b/src/common/wall_clock.cpp
@@ -67,7 +67,7 @@ std::unique_ptr<WallClock> CreateBestMatchingClock(u64 emulated_cpu_frequency,
67 const auto& caps = GetCPUCaps(); 67 const auto& caps = GetCPUCaps();
68 u64 rtsc_frequency = 0; 68 u64 rtsc_frequency = 0;
69 if (caps.invariant_tsc) { 69 if (caps.invariant_tsc) {
70 rtsc_frequency = EstimateRDTSCFrequency(); 70 rtsc_frequency = caps.tsc_frequency ? caps.tsc_frequency : EstimateRDTSCFrequency();
71 } 71 }
72 72
73 // Fallback to StandardWallClock if the hardware TSC does not have the precision greater than: 73 // Fallback to StandardWallClock if the hardware TSC does not have the precision greater than:
diff --git a/src/common/x64/cpu_detect.cpp b/src/common/x64/cpu_detect.cpp
index 322aa1f08..1a27532d4 100644
--- a/src/common/x64/cpu_detect.cpp
+++ b/src/common/x64/cpu_detect.cpp
@@ -161,6 +161,22 @@ static CPUCaps Detect() {
161 caps.invariant_tsc = Common::Bit<8>(cpu_id[3]); 161 caps.invariant_tsc = Common::Bit<8>(cpu_id[3]);
162 } 162 }
163 163
164 if (max_std_fn >= 0x15) {
165 __cpuid(cpu_id, 0x15);
166 caps.tsc_crystal_ratio_denominator = cpu_id[0];
167 caps.tsc_crystal_ratio_numerator = cpu_id[1];
168 caps.crystal_frequency = cpu_id[2];
169 // Some CPU models might not return a crystal frequency.
170 // The CPU model can be detected to use the values from turbostat
171 // https://github.com/torvalds/linux/blob/master/tools/power/x86/turbostat/turbostat.c#L5569
172 // but it's easier to just estimate the TSC tick rate for these cases.
173 if (caps.tsc_crystal_ratio_denominator) {
174 caps.tsc_frequency = static_cast<u64>(caps.crystal_frequency) *
175 caps.tsc_crystal_ratio_numerator /
176 caps.tsc_crystal_ratio_denominator;
177 }
178 }
179
164 if (max_std_fn >= 0x16) { 180 if (max_std_fn >= 0x16) {
165 __cpuid(cpu_id, 0x16); 181 __cpuid(cpu_id, 0x16);
166 caps.base_frequency = cpu_id[0]; 182 caps.base_frequency = cpu_id[0];
diff --git a/src/common/x64/cpu_detect.h b/src/common/x64/cpu_detect.h
index 9bdc9dbfa..6830f3795 100644
--- a/src/common/x64/cpu_detect.h
+++ b/src/common/x64/cpu_detect.h
@@ -30,6 +30,11 @@ struct CPUCaps {
30 u32 max_frequency; 30 u32 max_frequency;
31 u32 bus_frequency; 31 u32 bus_frequency;
32 32
33 u32 tsc_crystal_ratio_denominator;
34 u32 tsc_crystal_ratio_numerator;
35 u32 crystal_frequency;
36 u64 tsc_frequency; // Derived from the above three values
37
33 bool sse : 1; 38 bool sse : 1;
34 bool sse2 : 1; 39 bool sse2 : 1;
35 bool sse3 : 1; 40 bool sse3 : 1;
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index d9357138f..11d554bad 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -605,6 +605,10 @@ add_library(core STATIC
605 hle/service/psc/psc.h 605 hle/service/psc/psc.h
606 hle/service/ptm/psm.cpp 606 hle/service/ptm/psm.cpp
607 hle/service/ptm/psm.h 607 hle/service/ptm/psm.h
608 hle/service/ptm/ptm.cpp
609 hle/service/ptm/ptm.h
610 hle/service/ptm/ts.cpp
611 hle/service/ptm/ts.h
608 hle/service/kernel_helpers.cpp 612 hle/service/kernel_helpers.cpp
609 hle/service/kernel_helpers.h 613 hle/service/kernel_helpers.h
610 hle/service/service.cpp 614 hle/service/service.cpp
diff --git a/src/core/arm/arm_interface.cpp b/src/core/arm/arm_interface.cpp
index cef79b245..e72b250be 100644
--- a/src/core/arm/arm_interface.cpp
+++ b/src/core/arm/arm_interface.cpp
@@ -147,7 +147,6 @@ void ARM_Interface::Run() {
147 147
148 // Notify the debugger and go to sleep if a watchpoint was hit. 148 // Notify the debugger and go to sleep if a watchpoint was hit.
149 if (Has(hr, watchpoint)) { 149 if (Has(hr, watchpoint)) {
150 RewindBreakpointInstruction();
151 if (system.DebuggerEnabled()) { 150 if (system.DebuggerEnabled()) {
152 system.GetDebugger().NotifyThreadWatchpoint(current_thread, *HaltedWatchpoint()); 151 system.GetDebugger().NotifyThreadWatchpoint(current_thread, *HaltedWatchpoint());
153 } 152 }
diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h
index 8a066ed91..c092db9ff 100644
--- a/src/core/arm/arm_interface.h
+++ b/src/core/arm/arm_interface.h
@@ -203,7 +203,7 @@ public:
203 static constexpr Dynarmic::HaltReason break_loop = Dynarmic::HaltReason::UserDefined2; 203 static constexpr Dynarmic::HaltReason break_loop = Dynarmic::HaltReason::UserDefined2;
204 static constexpr Dynarmic::HaltReason svc_call = Dynarmic::HaltReason::UserDefined3; 204 static constexpr Dynarmic::HaltReason svc_call = Dynarmic::HaltReason::UserDefined3;
205 static constexpr Dynarmic::HaltReason breakpoint = Dynarmic::HaltReason::UserDefined4; 205 static constexpr Dynarmic::HaltReason breakpoint = Dynarmic::HaltReason::UserDefined4;
206 static constexpr Dynarmic::HaltReason watchpoint = Dynarmic::HaltReason::UserDefined5; 206 static constexpr Dynarmic::HaltReason watchpoint = Dynarmic::HaltReason::MemoryAbort;
207 static constexpr Dynarmic::HaltReason no_execute = Dynarmic::HaltReason::UserDefined6; 207 static constexpr Dynarmic::HaltReason no_execute = Dynarmic::HaltReason::UserDefined6;
208 208
209protected: 209protected:
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
index 1be5fe1c1..b8d2ce224 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
@@ -52,7 +52,7 @@ public:
52 if (!memory.IsValidVirtualAddressRange(vaddr, sizeof(u32))) { 52 if (!memory.IsValidVirtualAddressRange(vaddr, sizeof(u32))) {
53 return std::nullopt; 53 return std::nullopt;
54 } 54 }
55 return MemoryRead32(vaddr); 55 return memory.Read32(vaddr);
56 } 56 }
57 57
58 void MemoryWrite8(u32 vaddr, u8 value) override { 58 void MemoryWrite8(u32 vaddr, u8 value) override {
@@ -97,7 +97,7 @@ public:
97 parent.LogBacktrace(); 97 parent.LogBacktrace();
98 LOG_ERROR(Core_ARM, 98 LOG_ERROR(Core_ARM,
99 "Unimplemented instruction @ 0x{:X} for {} instructions (instr = {:08X})", pc, 99 "Unimplemented instruction @ 0x{:X} for {} instructions (instr = {:08X})", pc,
100 num_instructions, MemoryRead32(pc)); 100 num_instructions, memory.Read32(pc));
101 } 101 }
102 102
103 void ExceptionRaised(u32 pc, Dynarmic::A32::Exception exception) override { 103 void ExceptionRaised(u32 pc, Dynarmic::A32::Exception exception) override {
@@ -115,7 +115,7 @@ public:
115 parent.LogBacktrace(); 115 parent.LogBacktrace();
116 LOG_CRITICAL(Core_ARM, 116 LOG_CRITICAL(Core_ARM,
117 "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X}, thumb = {})", 117 "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X}, thumb = {})",
118 exception, pc, MemoryRead32(pc), parent.IsInThumbMode()); 118 exception, pc, memory.Read32(pc), parent.IsInThumbMode());
119 } 119 }
120 } 120 }
121 121
@@ -155,7 +155,7 @@ public:
155 const auto match{parent.MatchingWatchpoint(addr, size, type)}; 155 const auto match{parent.MatchingWatchpoint(addr, size, type)};
156 if (match) { 156 if (match) {
157 parent.halted_watchpoint = match; 157 parent.halted_watchpoint = match;
158 ReturnException(parent.jit.load()->Regs()[15], ARM_Interface::watchpoint); 158 parent.jit.load()->HaltExecution(ARM_Interface::watchpoint);
159 return false; 159 return false;
160 } 160 }
161 161
@@ -204,7 +204,6 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable*
204 204
205 // Code cache size 205 // Code cache size
206 config.code_cache_size = 512_MiB; 206 config.code_cache_size = 512_MiB;
207 config.far_code_offset = 400_MiB;
208 207
209 // Allow memory fault handling to work 208 // Allow memory fault handling to work
210 if (system.DebuggerEnabled()) { 209 if (system.DebuggerEnabled()) {
@@ -215,7 +214,6 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable*
215 if (!page_table) { 214 if (!page_table) {
216 // Don't waste too much memory on null_jit 215 // Don't waste too much memory on null_jit
217 config.code_cache_size = 8_MiB; 216 config.code_cache_size = 8_MiB;
218 config.far_code_offset = 4_MiB;
219 } 217 }
220 218
221 // Safe optimizations 219 // Safe optimizations
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
index c437f24b8..1a4d37cbc 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
@@ -56,7 +56,7 @@ public:
56 if (!memory.IsValidVirtualAddressRange(vaddr, sizeof(u32))) { 56 if (!memory.IsValidVirtualAddressRange(vaddr, sizeof(u32))) {
57 return std::nullopt; 57 return std::nullopt;
58 } 58 }
59 return MemoryRead32(vaddr); 59 return memory.Read32(vaddr);
60 } 60 }
61 61
62 void MemoryWrite8(u64 vaddr, u8 value) override { 62 void MemoryWrite8(u64 vaddr, u8 value) override {
@@ -111,7 +111,7 @@ public:
111 parent.LogBacktrace(); 111 parent.LogBacktrace();
112 LOG_ERROR(Core_ARM, 112 LOG_ERROR(Core_ARM,
113 "Unimplemented instruction @ 0x{:X} for {} instructions (instr = {:08X})", pc, 113 "Unimplemented instruction @ 0x{:X} for {} instructions (instr = {:08X})", pc,
114 num_instructions, MemoryRead32(pc)); 114 num_instructions, memory.Read32(pc));
115 } 115 }
116 116
117 void InstructionCacheOperationRaised(Dynarmic::A64::InstructionCacheOperation op, 117 void InstructionCacheOperationRaised(Dynarmic::A64::InstructionCacheOperation op,
@@ -156,7 +156,7 @@ public:
156 156
157 parent.LogBacktrace(); 157 parent.LogBacktrace();
158 LOG_CRITICAL(Core_ARM, "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X})", 158 LOG_CRITICAL(Core_ARM, "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X})",
159 static_cast<std::size_t>(exception), pc, MemoryRead32(pc)); 159 static_cast<std::size_t>(exception), pc, memory.Read32(pc));
160 } 160 }
161 } 161 }
162 162
@@ -198,7 +198,7 @@ public:
198 const auto match{parent.MatchingWatchpoint(addr, size, type)}; 198 const auto match{parent.MatchingWatchpoint(addr, size, type)};
199 if (match) { 199 if (match) {
200 parent.halted_watchpoint = match; 200 parent.halted_watchpoint = match;
201 ReturnException(parent.jit.load()->GetPC(), ARM_Interface::watchpoint); 201 parent.jit.load()->HaltExecution(ARM_Interface::watchpoint);
202 return false; 202 return false;
203 } 203 }
204 204
@@ -264,7 +264,6 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable*
264 264
265 // Code cache size 265 // Code cache size
266 config.code_cache_size = 512_MiB; 266 config.code_cache_size = 512_MiB;
267 config.far_code_offset = 400_MiB;
268 267
269 // Allow memory fault handling to work 268 // Allow memory fault handling to work
270 if (system.DebuggerEnabled()) { 269 if (system.DebuggerEnabled()) {
@@ -275,7 +274,6 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable*
275 if (!page_table) { 274 if (!page_table) {
276 // Don't waste too much memory on null_jit 275 // Don't waste too much memory on null_jit
277 config.code_cache_size = 8_MiB; 276 config.code_cache_size = 8_MiB;
278 config.far_code_offset = 4_MiB;
279 } 277 }
280 278
281 // Safe optimizations 279 // Safe optimizations
diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp
index b726ac27a..def105832 100644
--- a/src/core/hle/service/acc/acc.cpp
+++ b/src/core/hle/service/acc/acc.cpp
@@ -290,7 +290,7 @@ protected:
290 void Get(Kernel::HLERequestContext& ctx) { 290 void Get(Kernel::HLERequestContext& ctx) {
291 LOG_DEBUG(Service_ACC, "called user_id=0x{}", user_id.RawString()); 291 LOG_DEBUG(Service_ACC, "called user_id=0x{}", user_id.RawString());
292 ProfileBase profile_base{}; 292 ProfileBase profile_base{};
293 ProfileData data{}; 293 UserData data{};
294 if (profile_manager.GetProfileBaseAndData(user_id, profile_base, data)) { 294 if (profile_manager.GetProfileBaseAndData(user_id, profile_base, data)) {
295 ctx.WriteBuffer(data); 295 ctx.WriteBuffer(data);
296 IPC::ResponseBuilder rb{ctx, 16}; 296 IPC::ResponseBuilder rb{ctx, 16};
@@ -373,18 +373,18 @@ protected:
373 reinterpret_cast<const char*>(base.username.data()), base.username.size()), 373 reinterpret_cast<const char*>(base.username.data()), base.username.size()),
374 base.timestamp, base.user_uuid.RawString()); 374 base.timestamp, base.user_uuid.RawString());
375 375
376 if (user_data.size() < sizeof(ProfileData)) { 376 if (user_data.size() < sizeof(UserData)) {
377 LOG_ERROR(Service_ACC, "ProfileData buffer too small!"); 377 LOG_ERROR(Service_ACC, "UserData buffer too small!");
378 IPC::ResponseBuilder rb{ctx, 2}; 378 IPC::ResponseBuilder rb{ctx, 2};
379 rb.Push(ERR_INVALID_BUFFER); 379 rb.Push(ERR_INVALID_BUFFER);
380 return; 380 return;
381 } 381 }
382 382
383 ProfileData data; 383 UserData data;
384 std::memcpy(&data, user_data.data(), sizeof(ProfileData)); 384 std::memcpy(&data, user_data.data(), sizeof(UserData));
385 385
386 if (!profile_manager.SetProfileBaseAndData(user_id, base, data)) { 386 if (!profile_manager.SetProfileBaseAndData(user_id, base, data)) {
387 LOG_ERROR(Service_ACC, "Failed to update profile data and base!"); 387 LOG_ERROR(Service_ACC, "Failed to update user data and base!");
388 IPC::ResponseBuilder rb{ctx, 2}; 388 IPC::ResponseBuilder rb{ctx, 2};
389 rb.Push(ERR_FAILED_SAVE_DATA); 389 rb.Push(ERR_FAILED_SAVE_DATA);
390 return; 390 return;
@@ -406,15 +406,15 @@ protected:
406 reinterpret_cast<const char*>(base.username.data()), base.username.size()), 406 reinterpret_cast<const char*>(base.username.data()), base.username.size()),
407 base.timestamp, base.user_uuid.RawString()); 407 base.timestamp, base.user_uuid.RawString());
408 408
409 if (user_data.size() < sizeof(ProfileData)) { 409 if (user_data.size() < sizeof(UserData)) {
410 LOG_ERROR(Service_ACC, "ProfileData buffer too small!"); 410 LOG_ERROR(Service_ACC, "UserData buffer too small!");
411 IPC::ResponseBuilder rb{ctx, 2}; 411 IPC::ResponseBuilder rb{ctx, 2};
412 rb.Push(ERR_INVALID_BUFFER); 412 rb.Push(ERR_INVALID_BUFFER);
413 return; 413 return;
414 } 414 }
415 415
416 ProfileData data; 416 UserData data;
417 std::memcpy(&data, user_data.data(), sizeof(ProfileData)); 417 std::memcpy(&data, user_data.data(), sizeof(UserData));
418 418
419 Common::FS::IOFile image(GetImagePath(user_id), Common::FS::FileAccessMode::Write, 419 Common::FS::IOFile image(GetImagePath(user_id), Common::FS::FileAccessMode::Write,
420 Common::FS::FileType::BinaryFile); 420 Common::FS::FileType::BinaryFile);
diff --git a/src/core/hle/service/acc/profile_manager.cpp b/src/core/hle/service/acc/profile_manager.cpp
index 8118ead33..a58da4d5f 100644
--- a/src/core/hle/service/acc/profile_manager.cpp
+++ b/src/core/hle/service/acc/profile_manager.cpp
@@ -22,7 +22,7 @@ struct UserRaw {
22 UUID uuid2{}; 22 UUID uuid2{};
23 u64 timestamp{}; 23 u64 timestamp{};
24 ProfileUsername username{}; 24 ProfileUsername username{};
25 ProfileData extra_data{}; 25 UserData extra_data{};
26}; 26};
27static_assert(sizeof(UserRaw) == 0xC8, "UserRaw has incorrect size."); 27static_assert(sizeof(UserRaw) == 0xC8, "UserRaw has incorrect size.");
28 28
@@ -263,7 +263,7 @@ UUID ProfileManager::GetLastOpenedUser() const {
263 263
264/// Return the users profile base and the unknown arbitary data. 264/// Return the users profile base and the unknown arbitary data.
265bool ProfileManager::GetProfileBaseAndData(std::optional<std::size_t> index, ProfileBase& profile, 265bool ProfileManager::GetProfileBaseAndData(std::optional<std::size_t> index, ProfileBase& profile,
266 ProfileData& data) const { 266 UserData& data) const {
267 if (GetProfileBase(index, profile)) { 267 if (GetProfileBase(index, profile)) {
268 data = profiles[*index].data; 268 data = profiles[*index].data;
269 return true; 269 return true;
@@ -272,15 +272,14 @@ bool ProfileManager::GetProfileBaseAndData(std::optional<std::size_t> index, Pro
272} 272}
273 273
274/// Return the users profile base and the unknown arbitary data. 274/// Return the users profile base and the unknown arbitary data.
275bool ProfileManager::GetProfileBaseAndData(UUID uuid, ProfileBase& profile, 275bool ProfileManager::GetProfileBaseAndData(UUID uuid, ProfileBase& profile, UserData& data) const {
276 ProfileData& data) const {
277 const auto idx = GetUserIndex(uuid); 276 const auto idx = GetUserIndex(uuid);
278 return GetProfileBaseAndData(idx, profile, data); 277 return GetProfileBaseAndData(idx, profile, data);
279} 278}
280 279
281/// Return the users profile base and the unknown arbitary data. 280/// Return the users profile base and the unknown arbitary data.
282bool ProfileManager::GetProfileBaseAndData(const ProfileInfo& user, ProfileBase& profile, 281bool ProfileManager::GetProfileBaseAndData(const ProfileInfo& user, ProfileBase& profile,
283 ProfileData& data) const { 282 UserData& data) const {
284 return GetProfileBaseAndData(user.user_uuid, profile, data); 283 return GetProfileBaseAndData(user.user_uuid, profile, data);
285} 284}
286 285
@@ -318,7 +317,7 @@ bool ProfileManager::SetProfileBase(UUID uuid, const ProfileBase& profile_new) {
318} 317}
319 318
320bool ProfileManager::SetProfileBaseAndData(Common::UUID uuid, const ProfileBase& profile_new, 319bool ProfileManager::SetProfileBaseAndData(Common::UUID uuid, const ProfileBase& profile_new,
321 const ProfileData& data_new) { 320 const UserData& data_new) {
322 const auto index = GetUserIndex(uuid); 321 const auto index = GetUserIndex(uuid);
323 if (index.has_value() && SetProfileBase(uuid, profile_new)) { 322 if (index.has_value() && SetProfileBase(uuid, profile_new)) {
324 profiles[*index].data = data_new; 323 profiles[*index].data = data_new;
diff --git a/src/core/hle/service/acc/profile_manager.h b/src/core/hle/service/acc/profile_manager.h
index 9940957f1..135f7d0d5 100644
--- a/src/core/hle/service/acc/profile_manager.h
+++ b/src/core/hle/service/acc/profile_manager.h
@@ -22,7 +22,7 @@ using UserIDArray = std::array<Common::UUID, MAX_USERS>;
22 22
23/// Contains extra data related to a user. 23/// Contains extra data related to a user.
24/// TODO: RE this structure 24/// TODO: RE this structure
25struct ProfileData { 25struct UserData {
26 INSERT_PADDING_WORDS_NOINIT(1); 26 INSERT_PADDING_WORDS_NOINIT(1);
27 u32 icon_id; 27 u32 icon_id;
28 u8 bg_color_id; 28 u8 bg_color_id;
@@ -30,7 +30,7 @@ struct ProfileData {
30 INSERT_PADDING_BYTES_NOINIT(0x10); 30 INSERT_PADDING_BYTES_NOINIT(0x10);
31 INSERT_PADDING_BYTES_NOINIT(0x60); 31 INSERT_PADDING_BYTES_NOINIT(0x60);
32}; 32};
33static_assert(sizeof(ProfileData) == 0x80, "ProfileData structure has incorrect size"); 33static_assert(sizeof(UserData) == 0x80, "UserData structure has incorrect size");
34 34
35/// This holds general information about a users profile. This is where we store all the information 35/// This holds general information about a users profile. This is where we store all the information
36/// based on a specific user 36/// based on a specific user
@@ -38,7 +38,7 @@ struct ProfileInfo {
38 Common::UUID user_uuid{}; 38 Common::UUID user_uuid{};
39 ProfileUsername username{}; 39 ProfileUsername username{};
40 u64 creation_time{}; 40 u64 creation_time{};
41 ProfileData data{}; // TODO(ognik): Work out what this is 41 UserData data{}; // TODO(ognik): Work out what this is
42 bool is_open{}; 42 bool is_open{};
43}; 43};
44 44
@@ -74,10 +74,9 @@ public:
74 bool GetProfileBase(Common::UUID uuid, ProfileBase& profile) const; 74 bool GetProfileBase(Common::UUID uuid, ProfileBase& profile) const;
75 bool GetProfileBase(const ProfileInfo& user, ProfileBase& profile) const; 75 bool GetProfileBase(const ProfileInfo& user, ProfileBase& profile) const;
76 bool GetProfileBaseAndData(std::optional<std::size_t> index, ProfileBase& profile, 76 bool GetProfileBaseAndData(std::optional<std::size_t> index, ProfileBase& profile,
77 ProfileData& data) const; 77 UserData& data) const;
78 bool GetProfileBaseAndData(Common::UUID uuid, ProfileBase& profile, ProfileData& data) const; 78 bool GetProfileBaseAndData(Common::UUID uuid, ProfileBase& profile, UserData& data) const;
79 bool GetProfileBaseAndData(const ProfileInfo& user, ProfileBase& profile, 79 bool GetProfileBaseAndData(const ProfileInfo& user, ProfileBase& profile, UserData& data) const;
80 ProfileData& data) const;
81 std::size_t GetUserCount() const; 80 std::size_t GetUserCount() const;
82 std::size_t GetOpenUserCount() const; 81 std::size_t GetOpenUserCount() const;
83 bool UserExists(Common::UUID uuid) const; 82 bool UserExists(Common::UUID uuid) const;
@@ -93,7 +92,7 @@ public:
93 bool RemoveUser(Common::UUID uuid); 92 bool RemoveUser(Common::UUID uuid);
94 bool SetProfileBase(Common::UUID uuid, const ProfileBase& profile_new); 93 bool SetProfileBase(Common::UUID uuid, const ProfileBase& profile_new);
95 bool SetProfileBaseAndData(Common::UUID uuid, const ProfileBase& profile_new, 94 bool SetProfileBaseAndData(Common::UUID uuid, const ProfileBase& profile_new,
96 const ProfileData& data_new); 95 const UserData& data_new);
97 96
98private: 97private:
99 void ParseUserSaveFile(); 98 void ParseUserSaveFile();
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index d35644e73..9116dd77c 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -238,6 +238,7 @@ IDebugFunctions::IDebugFunctions(Core::System& system_)
238 {130, nullptr, "FriendInvitationSetApplicationParameter"}, 238 {130, nullptr, "FriendInvitationSetApplicationParameter"},
239 {131, nullptr, "FriendInvitationClearApplicationParameter"}, 239 {131, nullptr, "FriendInvitationClearApplicationParameter"},
240 {132, nullptr, "FriendInvitationPushApplicationParameter"}, 240 {132, nullptr, "FriendInvitationPushApplicationParameter"},
241 {140, nullptr, "RestrictPowerOperationForSecureLaunchModeForDebug"},
241 {900, nullptr, "GetGrcProcessLaunchedSystemEvent"}, 242 {900, nullptr, "GetGrcProcessLaunchedSystemEvent"},
242 }; 243 };
243 // clang-format on 244 // clang-format on
@@ -635,6 +636,10 @@ void AppletMessageQueue::RequestExit() {
635 PushMessage(AppletMessage::Exit); 636 PushMessage(AppletMessage::Exit);
636} 637}
637 638
639void AppletMessageQueue::RequestResume() {
640 PushMessage(AppletMessage::Resume);
641}
642
638void AppletMessageQueue::FocusStateChanged() { 643void AppletMessageQueue::FocusStateChanged() {
639 PushMessage(AppletMessage::FocusStateChanged); 644 PushMessage(AppletMessage::FocusStateChanged);
640} 645}
@@ -1310,6 +1315,8 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_)
1310 {33, &IApplicationFunctions::EndBlockingHomeButton, "EndBlockingHomeButton"}, 1315 {33, &IApplicationFunctions::EndBlockingHomeButton, "EndBlockingHomeButton"},
1311 {34, nullptr, "SelectApplicationLicense"}, 1316 {34, nullptr, "SelectApplicationLicense"},
1312 {35, nullptr, "GetDeviceSaveDataSizeMax"}, 1317 {35, nullptr, "GetDeviceSaveDataSizeMax"},
1318 {36, nullptr, "GetLimitedApplicationLicense"},
1319 {37, nullptr, "GetLimitedApplicationLicenseUpgradableEvent"},
1313 {40, &IApplicationFunctions::NotifyRunning, "NotifyRunning"}, 1320 {40, &IApplicationFunctions::NotifyRunning, "NotifyRunning"},
1314 {50, &IApplicationFunctions::GetPseudoDeviceId, "GetPseudoDeviceId"}, 1321 {50, &IApplicationFunctions::GetPseudoDeviceId, "GetPseudoDeviceId"},
1315 {60, nullptr, "SetMediaPlaybackStateForApplication"}, 1322 {60, nullptr, "SetMediaPlaybackStateForApplication"},
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h
index 988ead215..53144427b 100644
--- a/src/core/hle/service/am/am.h
+++ b/src/core/hle/service/am/am.h
@@ -90,6 +90,7 @@ public:
90 AppletMessage PopMessage(); 90 AppletMessage PopMessage();
91 std::size_t GetMessageCount() const; 91 std::size_t GetMessageCount() const;
92 void RequestExit(); 92 void RequestExit();
93 void RequestResume();
93 void FocusStateChanged(); 94 void FocusStateChanged();
94 void OperationModeChanged(); 95 void OperationModeChanged();
95 96
diff --git a/src/core/hle/service/bcat/bcat_module.cpp b/src/core/hle/service/bcat/bcat_module.cpp
index d928e37fb..bc08ac487 100644
--- a/src/core/hle/service/bcat/bcat_module.cpp
+++ b/src/core/hle/service/bcat/bcat_module.cpp
@@ -140,8 +140,8 @@ public:
140 {20401, nullptr, "UnregisterSystemApplicationDeliveryTask"}, 140 {20401, nullptr, "UnregisterSystemApplicationDeliveryTask"},
141 {20410, nullptr, "SetSystemApplicationDeliveryTaskTimer"}, 141 {20410, nullptr, "SetSystemApplicationDeliveryTaskTimer"},
142 {30100, &IBcatService::SetPassphrase, "SetPassphrase"}, 142 {30100, &IBcatService::SetPassphrase, "SetPassphrase"},
143 {30101, nullptr, "Unknown"}, 143 {30101, nullptr, "Unknown30101"},
144 {30102, nullptr, "Unknown2"}, 144 {30102, nullptr, "Unknown30102"},
145 {30200, nullptr, "RegisterBackgroundDeliveryTask"}, 145 {30200, nullptr, "RegisterBackgroundDeliveryTask"},
146 {30201, nullptr, "UnregisterBackgroundDeliveryTask"}, 146 {30201, nullptr, "UnregisterBackgroundDeliveryTask"},
147 {30202, nullptr, "BlockDeliveryTask"}, 147 {30202, nullptr, "BlockDeliveryTask"},
diff --git a/src/core/hle/service/btdrv/btdrv.cpp b/src/core/hle/service/btdrv/btdrv.cpp
index f9ee2b624..ec7e5320c 100644
--- a/src/core/hle/service/btdrv/btdrv.cpp
+++ b/src/core/hle/service/btdrv/btdrv.cpp
@@ -181,6 +181,11 @@ public:
181 {147, nullptr, "RegisterAudioControlNotification"}, 181 {147, nullptr, "RegisterAudioControlNotification"},
182 {148, nullptr, "SendAudioControlPassthroughCommand"}, 182 {148, nullptr, "SendAudioControlPassthroughCommand"},
183 {149, nullptr, "SendAudioControlSetAbsoluteVolumeCommand"}, 183 {149, nullptr, "SendAudioControlSetAbsoluteVolumeCommand"},
184 {150, nullptr, "AcquireAudioSinkVolumeLocallyChangedEvent"},
185 {151, nullptr, "AcquireAudioSinkVolumeUpdateRequestCompletedEvent"},
186 {152, nullptr, "GetAudioSinkVolume"},
187 {153, nullptr, "RequestUpdateAudioSinkVolume"},
188 {154, nullptr, "IsAudioSinkVolumeSupported"},
184 {256, nullptr, "IsManufacturingMode"}, 189 {256, nullptr, "IsManufacturingMode"},
185 {257, nullptr, "EmulateBluetoothCrash"}, 190 {257, nullptr, "EmulateBluetoothCrash"},
186 {258, nullptr, "GetBleChannelMap"}, 191 {258, nullptr, "GetBleChannelMap"},
diff --git a/src/core/hle/service/btm/btm.cpp b/src/core/hle/service/btm/btm.cpp
index 3fa88cbd3..eebf85e03 100644
--- a/src/core/hle/service/btm/btm.cpp
+++ b/src/core/hle/service/btm/btm.cpp
@@ -214,8 +214,12 @@ public:
214 {76, nullptr, "Unknown76"}, 214 {76, nullptr, "Unknown76"},
215 {100, nullptr, "Unknown100"}, 215 {100, nullptr, "Unknown100"},
216 {101, nullptr, "Unknown101"}, 216 {101, nullptr, "Unknown101"},
217 {110, nullptr, "Unknown102"}, 217 {110, nullptr, "Unknown110"},
218 {111, nullptr, "Unknown103"}, 218 {111, nullptr, "Unknown111"},
219 {112, nullptr, "Unknown112"},
220 {113, nullptr, "Unknown113"},
221 {114, nullptr, "Unknown114"},
222 {115, nullptr, "Unknown115"},
219 }; 223 };
220 // clang-format on 224 // clang-format on
221 225
diff --git a/src/core/hle/service/fatal/fatal_p.cpp b/src/core/hle/service/fatal/fatal_p.cpp
index 7d35b4208..4a81bb5e2 100644
--- a/src/core/hle/service/fatal/fatal_p.cpp
+++ b/src/core/hle/service/fatal/fatal_p.cpp
@@ -6,7 +6,13 @@
6namespace Service::Fatal { 6namespace Service::Fatal {
7 7
8Fatal_P::Fatal_P(std::shared_ptr<Module> module_, Core::System& system_) 8Fatal_P::Fatal_P(std::shared_ptr<Module> module_, Core::System& system_)
9 : Interface(std::move(module_), system_, "fatal:p") {} 9 : Interface(std::move(module_), system_, "fatal:p") {
10 static const FunctionInfo functions[] = {
11 {0, nullptr, "GetFatalEvent"},
12 {10, nullptr, "GetFatalContext"},
13 };
14 RegisterHandlers(functions);
15}
10 16
11Fatal_P::~Fatal_P() = default; 17Fatal_P::~Fatal_P() = default;
12 18
diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp
index 0310ce883..7055ea93e 100644
--- a/src/core/hle/service/nifm/nifm.cpp
+++ b/src/core/hle/service/nifm/nifm.cpp
@@ -30,6 +30,19 @@ enum class RequestState : u32 {
30 Connected = 3, 30 Connected = 3,
31}; 31};
32 32
33enum class InternetConnectionType : u8 {
34 WiFi = 1,
35 Ethernet = 2,
36};
37
38enum class InternetConnectionStatus : u8 {
39 ConnectingUnknown1,
40 ConnectingUnknown2,
41 ConnectingUnknown3,
42 ConnectingUnknown4,
43 Connected,
44};
45
33struct IpAddressSetting { 46struct IpAddressSetting {
34 bool is_automatic{}; 47 bool is_automatic{};
35 Network::IPv4Address current_address{}; 48 Network::IPv4Address current_address{};
@@ -271,6 +284,7 @@ private:
271 rb.Push(ResultSuccess); 284 rb.Push(ResultSuccess);
272 rb.Push<u64>(client_id); // Client ID needs to be non zero otherwise it's considered invalid 285 rb.Push<u64>(client_id); // Client ID needs to be non zero otherwise it's considered invalid
273 } 286 }
287
274 void CreateScanRequest(Kernel::HLERequestContext& ctx) { 288 void CreateScanRequest(Kernel::HLERequestContext& ctx) {
275 LOG_DEBUG(Service_NIFM, "called"); 289 LOG_DEBUG(Service_NIFM, "called");
276 290
@@ -279,6 +293,7 @@ private:
279 rb.Push(ResultSuccess); 293 rb.Push(ResultSuccess);
280 rb.PushIpcInterface<IScanRequest>(system); 294 rb.PushIpcInterface<IScanRequest>(system);
281 } 295 }
296
282 void CreateRequest(Kernel::HLERequestContext& ctx) { 297 void CreateRequest(Kernel::HLERequestContext& ctx) {
283 LOG_DEBUG(Service_NIFM, "called"); 298 LOG_DEBUG(Service_NIFM, "called");
284 299
@@ -287,6 +302,7 @@ private:
287 rb.Push(ResultSuccess); 302 rb.Push(ResultSuccess);
288 rb.PushIpcInterface<IRequest>(system); 303 rb.PushIpcInterface<IRequest>(system);
289 } 304 }
305
290 void GetCurrentNetworkProfile(Kernel::HLERequestContext& ctx) { 306 void GetCurrentNetworkProfile(Kernel::HLERequestContext& ctx) {
291 LOG_WARNING(Service_NIFM, "(STUBBED) called"); 307 LOG_WARNING(Service_NIFM, "(STUBBED) called");
292 308
@@ -335,12 +351,14 @@ private:
335 IPC::ResponseBuilder rb{ctx, 2}; 351 IPC::ResponseBuilder rb{ctx, 2};
336 rb.Push(ResultSuccess); 352 rb.Push(ResultSuccess);
337 } 353 }
354
338 void RemoveNetworkProfile(Kernel::HLERequestContext& ctx) { 355 void RemoveNetworkProfile(Kernel::HLERequestContext& ctx) {
339 LOG_WARNING(Service_NIFM, "(STUBBED) called"); 356 LOG_WARNING(Service_NIFM, "(STUBBED) called");
340 357
341 IPC::ResponseBuilder rb{ctx, 2}; 358 IPC::ResponseBuilder rb{ctx, 2};
342 rb.Push(ResultSuccess); 359 rb.Push(ResultSuccess);
343 } 360 }
361
344 void GetCurrentIpAddress(Kernel::HLERequestContext& ctx) { 362 void GetCurrentIpAddress(Kernel::HLERequestContext& ctx) {
345 LOG_WARNING(Service_NIFM, "(STUBBED) called"); 363 LOG_WARNING(Service_NIFM, "(STUBBED) called");
346 364
@@ -354,6 +372,7 @@ private:
354 rb.Push(ResultSuccess); 372 rb.Push(ResultSuccess);
355 rb.PushRaw(*ipv4); 373 rb.PushRaw(*ipv4);
356 } 374 }
375
357 void CreateTemporaryNetworkProfile(Kernel::HLERequestContext& ctx) { 376 void CreateTemporaryNetworkProfile(Kernel::HLERequestContext& ctx) {
358 LOG_DEBUG(Service_NIFM, "called"); 377 LOG_DEBUG(Service_NIFM, "called");
359 378
@@ -369,6 +388,7 @@ private:
369 rb.PushIpcInterface<INetworkProfile>(system); 388 rb.PushIpcInterface<INetworkProfile>(system);
370 rb.PushRaw<u128>(uuid); 389 rb.PushRaw<u128>(uuid);
371 } 390 }
391
372 void GetCurrentIpConfigInfo(Kernel::HLERequestContext& ctx) { 392 void GetCurrentIpConfigInfo(Kernel::HLERequestContext& ctx) {
373 LOG_WARNING(Service_NIFM, "(STUBBED) called"); 393 LOG_WARNING(Service_NIFM, "(STUBBED) called");
374 394
@@ -405,6 +425,7 @@ private:
405 rb.Push(ResultSuccess); 425 rb.Push(ResultSuccess);
406 rb.PushRaw<IpConfigInfo>(ip_config_info); 426 rb.PushRaw<IpConfigInfo>(ip_config_info);
407 } 427 }
428
408 void IsWirelessCommunicationEnabled(Kernel::HLERequestContext& ctx) { 429 void IsWirelessCommunicationEnabled(Kernel::HLERequestContext& ctx) {
409 LOG_WARNING(Service_NIFM, "(STUBBED) called"); 430 LOG_WARNING(Service_NIFM, "(STUBBED) called");
410 431
@@ -412,6 +433,24 @@ private:
412 rb.Push(ResultSuccess); 433 rb.Push(ResultSuccess);
413 rb.Push<u8>(0); 434 rb.Push<u8>(0);
414 } 435 }
436
437 void GetInternetConnectionStatus(Kernel::HLERequestContext& ctx) {
438 LOG_WARNING(Service_NIFM, "(STUBBED) called");
439
440 struct Output {
441 InternetConnectionType type{InternetConnectionType::WiFi};
442 u8 wifi_strength{3};
443 InternetConnectionStatus state{InternetConnectionStatus::Connected};
444 };
445 static_assert(sizeof(Output) == 0x3, "Output has incorrect size.");
446
447 constexpr Output out{};
448
449 IPC::ResponseBuilder rb{ctx, 3};
450 rb.Push(ResultSuccess);
451 rb.PushRaw(out);
452 }
453
415 void IsEthernetCommunicationEnabled(Kernel::HLERequestContext& ctx) { 454 void IsEthernetCommunicationEnabled(Kernel::HLERequestContext& ctx) {
416 LOG_WARNING(Service_NIFM, "(STUBBED) called"); 455 LOG_WARNING(Service_NIFM, "(STUBBED) called");
417 456
@@ -423,6 +462,7 @@ private:
423 rb.Push<u8>(0); 462 rb.Push<u8>(0);
424 } 463 }
425 } 464 }
465
426 void IsAnyInternetRequestAccepted(Kernel::HLERequestContext& ctx) { 466 void IsAnyInternetRequestAccepted(Kernel::HLERequestContext& ctx) {
427 LOG_WARNING(Service_NIFM, "(STUBBED) called"); 467 LOG_WARNING(Service_NIFM, "(STUBBED) called");
428 468
@@ -456,7 +496,7 @@ IGeneralService::IGeneralService(Core::System& system_)
456 {15, &IGeneralService::GetCurrentIpConfigInfo, "GetCurrentIpConfigInfo"}, 496 {15, &IGeneralService::GetCurrentIpConfigInfo, "GetCurrentIpConfigInfo"},
457 {16, nullptr, "SetWirelessCommunicationEnabled"}, 497 {16, nullptr, "SetWirelessCommunicationEnabled"},
458 {17, &IGeneralService::IsWirelessCommunicationEnabled, "IsWirelessCommunicationEnabled"}, 498 {17, &IGeneralService::IsWirelessCommunicationEnabled, "IsWirelessCommunicationEnabled"},
459 {18, nullptr, "GetInternetConnectionStatus"}, 499 {18, &IGeneralService::GetInternetConnectionStatus, "GetInternetConnectionStatus"},
460 {19, nullptr, "SetEthernetCommunicationEnabled"}, 500 {19, nullptr, "SetEthernetCommunicationEnabled"},
461 {20, &IGeneralService::IsEthernetCommunicationEnabled, "IsEthernetCommunicationEnabled"}, 501 {20, &IGeneralService::IsEthernetCommunicationEnabled, "IsEthernetCommunicationEnabled"},
462 {21, &IGeneralService::IsAnyInternetRequestAccepted, "IsAnyInternetRequestAccepted"}, 502 {21, &IGeneralService::IsAnyInternetRequestAccepted, "IsAnyInternetRequestAccepted"},
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp
index 5f69c8c2c..5574269eb 100644
--- a/src/core/hle/service/nvflinger/nvflinger.cpp
+++ b/src/core/hle/service/nvflinger/nvflinger.cpp
@@ -287,9 +287,21 @@ s64 NVFlinger::GetNextTicks() const {
287 static constexpr s64 max_hertz = 120LL; 287 static constexpr s64 max_hertz = 120LL;
288 288
289 const auto& settings = Settings::values; 289 const auto& settings = Settings::values;
290 const bool unlocked_fps = settings.disable_fps_limit.GetValue(); 290 auto speed_scale = 1.f;
291 const s64 fps_cap = unlocked_fps ? static_cast<s64>(settings.fps_cap.GetValue()) : 1; 291 if (settings.use_multi_core.GetValue()) {
292 return (1000000000 * (1LL << swap_interval)) / (max_hertz * fps_cap); 292 if (settings.use_speed_limit.GetValue()) {
293 // Scales the speed based on speed_limit setting on MC. SC is handled by
294 // SpeedLimiter::DoSpeedLimiting.
295 speed_scale = 100.f / settings.speed_limit.GetValue();
296 } else {
297 // Run at unlocked framerate.
298 speed_scale = 0.01f;
299 }
300 }
301
302 const auto next_ticks = ((1000000000 * (1LL << swap_interval)) / max_hertz);
303
304 return static_cast<s64>(speed_scale * static_cast<float>(next_ticks));
293} 305}
294 306
295} // namespace Service::NVFlinger 307} // namespace Service::NVFlinger
diff --git a/src/core/hle/service/ptm/psm.cpp b/src/core/hle/service/ptm/psm.cpp
index 9e0eb6ac0..2c31e9485 100644
--- a/src/core/hle/service/ptm/psm.cpp
+++ b/src/core/hle/service/ptm/psm.cpp
@@ -9,10 +9,8 @@
9#include "core/hle/kernel/k_event.h" 9#include "core/hle/kernel/k_event.h"
10#include "core/hle/service/kernel_helpers.h" 10#include "core/hle/service/kernel_helpers.h"
11#include "core/hle/service/ptm/psm.h" 11#include "core/hle/service/ptm/psm.h"
12#include "core/hle/service/service.h"
13#include "core/hle/service/sm/sm.h"
14 12
15namespace Service::PSM { 13namespace Service::PTM {
16 14
17class IPsmSession final : public ServiceFramework<IPsmSession> { 15class IPsmSession final : public ServiceFramework<IPsmSession> {
18public: 16public:
@@ -57,7 +55,7 @@ public:
57 55
58private: 56private:
59 void BindStateChangeEvent(Kernel::HLERequestContext& ctx) { 57 void BindStateChangeEvent(Kernel::HLERequestContext& ctx) {
60 LOG_DEBUG(Service_PSM, "called"); 58 LOG_DEBUG(Service_PTM, "called");
61 59
62 should_signal = true; 60 should_signal = true;
63 61
@@ -67,7 +65,7 @@ private:
67 } 65 }
68 66
69 void UnbindStateChangeEvent(Kernel::HLERequestContext& ctx) { 67 void UnbindStateChangeEvent(Kernel::HLERequestContext& ctx) {
70 LOG_DEBUG(Service_PSM, "called"); 68 LOG_DEBUG(Service_PTM, "called");
71 69
72 should_signal = false; 70 should_signal = false;
73 71
@@ -78,7 +76,7 @@ private:
78 void SetChargerTypeChangeEventEnabled(Kernel::HLERequestContext& ctx) { 76 void SetChargerTypeChangeEventEnabled(Kernel::HLERequestContext& ctx) {
79 IPC::RequestParser rp{ctx}; 77 IPC::RequestParser rp{ctx};
80 const auto state = rp.Pop<bool>(); 78 const auto state = rp.Pop<bool>();
81 LOG_DEBUG(Service_PSM, "called, state={}", state); 79 LOG_DEBUG(Service_PTM, "called, state={}", state);
82 80
83 should_signal_charger_type = state; 81 should_signal_charger_type = state;
84 82
@@ -89,7 +87,7 @@ private:
89 void SetPowerSupplyChangeEventEnabled(Kernel::HLERequestContext& ctx) { 87 void SetPowerSupplyChangeEventEnabled(Kernel::HLERequestContext& ctx) {
90 IPC::RequestParser rp{ctx}; 88 IPC::RequestParser rp{ctx};
91 const auto state = rp.Pop<bool>(); 89 const auto state = rp.Pop<bool>();
92 LOG_DEBUG(Service_PSM, "called, state={}", state); 90 LOG_DEBUG(Service_PTM, "called, state={}", state);
93 91
94 should_signal_power_supply = state; 92 should_signal_power_supply = state;
95 93
@@ -100,7 +98,7 @@ private:
100 void SetBatteryVoltageStateChangeEventEnabled(Kernel::HLERequestContext& ctx) { 98 void SetBatteryVoltageStateChangeEventEnabled(Kernel::HLERequestContext& ctx) {
101 IPC::RequestParser rp{ctx}; 99 IPC::RequestParser rp{ctx};
102 const auto state = rp.Pop<bool>(); 100 const auto state = rp.Pop<bool>();
103 LOG_DEBUG(Service_PSM, "called, state={}", state); 101 LOG_DEBUG(Service_PTM, "called, state={}", state);
104 102
105 should_signal_battery_voltage = state; 103 should_signal_battery_voltage = state;
106 104
@@ -117,76 +115,58 @@ private:
117 Kernel::KEvent* state_change_event; 115 Kernel::KEvent* state_change_event;
118}; 116};
119 117
120class PSM final : public ServiceFramework<PSM> { 118PSM::PSM(Core::System& system_) : ServiceFramework{system_, "psm"} {
121public: 119 // clang-format off
122 explicit PSM(Core::System& system_) : ServiceFramework{system_, "psm"} { 120 static const FunctionInfo functions[] = {
123 // clang-format off 121 {0, &PSM::GetBatteryChargePercentage, "GetBatteryChargePercentage"},
124 static const FunctionInfo functions[] = { 122 {1, &PSM::GetChargerType, "GetChargerType"},
125 {0, &PSM::GetBatteryChargePercentage, "GetBatteryChargePercentage"}, 123 {2, nullptr, "EnableBatteryCharging"},
126 {1, &PSM::GetChargerType, "GetChargerType"}, 124 {3, nullptr, "DisableBatteryCharging"},
127 {2, nullptr, "EnableBatteryCharging"}, 125 {4, nullptr, "IsBatteryChargingEnabled"},
128 {3, nullptr, "DisableBatteryCharging"}, 126 {5, nullptr, "AcquireControllerPowerSupply"},
129 {4, nullptr, "IsBatteryChargingEnabled"}, 127 {6, nullptr, "ReleaseControllerPowerSupply"},
130 {5, nullptr, "AcquireControllerPowerSupply"}, 128 {7, &PSM::OpenSession, "OpenSession"},
131 {6, nullptr, "ReleaseControllerPowerSupply"}, 129 {8, nullptr, "EnableEnoughPowerChargeEmulation"},
132 {7, &PSM::OpenSession, "OpenSession"}, 130 {9, nullptr, "DisableEnoughPowerChargeEmulation"},
133 {8, nullptr, "EnableEnoughPowerChargeEmulation"}, 131 {10, nullptr, "EnableFastBatteryCharging"},
134 {9, nullptr, "DisableEnoughPowerChargeEmulation"}, 132 {11, nullptr, "DisableFastBatteryCharging"},
135 {10, nullptr, "EnableFastBatteryCharging"}, 133 {12, nullptr, "GetBatteryVoltageState"},
136 {11, nullptr, "DisableFastBatteryCharging"}, 134 {13, nullptr, "GetRawBatteryChargePercentage"},
137 {12, nullptr, "GetBatteryVoltageState"}, 135 {14, nullptr, "IsEnoughPowerSupplied"},
138 {13, nullptr, "GetRawBatteryChargePercentage"}, 136 {15, nullptr, "GetBatteryAgePercentage"},
139 {14, nullptr, "IsEnoughPowerSupplied"}, 137 {16, nullptr, "GetBatteryChargeInfoEvent"},
140 {15, nullptr, "GetBatteryAgePercentage"}, 138 {17, nullptr, "GetBatteryChargeInfoFields"},
141 {16, nullptr, "GetBatteryChargeInfoEvent"}, 139 {18, nullptr, "GetBatteryChargeCalibratedEvent"},
142 {17, nullptr, "GetBatteryChargeInfoFields"}, 140 };
143 {18, nullptr, "GetBatteryChargeCalibratedEvent"}, 141 // clang-format on
144 };
145 // clang-format on
146
147 RegisterHandlers(functions);
148 }
149
150 ~PSM() override = default;
151
152private:
153 void GetBatteryChargePercentage(Kernel::HLERequestContext& ctx) {
154 LOG_DEBUG(Service_PSM, "called");
155 142
156 IPC::ResponseBuilder rb{ctx, 3}; 143 RegisterHandlers(functions);
157 rb.Push(ResultSuccess); 144}
158 rb.Push<u32>(battery_charge_percentage);
159 }
160 145
161 void GetChargerType(Kernel::HLERequestContext& ctx) { 146PSM::~PSM() = default;
162 LOG_DEBUG(Service_PSM, "called");
163 147
164 IPC::ResponseBuilder rb{ctx, 3}; 148void PSM::GetBatteryChargePercentage(Kernel::HLERequestContext& ctx) {
165 rb.Push(ResultSuccess); 149 LOG_DEBUG(Service_PTM, "called");
166 rb.PushEnum(charger_type);
167 }
168 150
169 void OpenSession(Kernel::HLERequestContext& ctx) { 151 IPC::ResponseBuilder rb{ctx, 3};
170 LOG_DEBUG(Service_PSM, "called"); 152 rb.Push(ResultSuccess);
153 rb.Push<u32>(battery_charge_percentage);
154}
171 155
172 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 156void PSM::GetChargerType(Kernel::HLERequestContext& ctx) {
173 rb.Push(ResultSuccess); 157 LOG_DEBUG(Service_PTM, "called");
174 rb.PushIpcInterface<IPsmSession>(system);
175 }
176 158
177 enum class ChargerType : u32 { 159 IPC::ResponseBuilder rb{ctx, 3};
178 Unplugged = 0, 160 rb.Push(ResultSuccess);
179 RegularCharger = 1, 161 rb.PushEnum(charger_type);
180 LowPowerCharger = 2, 162}
181 Unknown = 3,
182 };
183 163
184 u32 battery_charge_percentage{100}; // 100% 164void PSM::OpenSession(Kernel::HLERequestContext& ctx) {
185 ChargerType charger_type{ChargerType::RegularCharger}; 165 LOG_DEBUG(Service_PTM, "called");
186};
187 166
188void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) { 167 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
189 std::make_shared<PSM>(system)->InstallAsService(sm); 168 rb.Push(ResultSuccess);
169 rb.PushIpcInterface<IPsmSession>(system);
190} 170}
191 171
192} // namespace Service::PSM 172} // namespace Service::PTM
diff --git a/src/core/hle/service/ptm/psm.h b/src/core/hle/service/ptm/psm.h
index 94a1044db..f674ba8bc 100644
--- a/src/core/hle/service/ptm/psm.h
+++ b/src/core/hle/service/ptm/psm.h
@@ -3,16 +3,29 @@
3 3
4#pragma once 4#pragma once
5 5
6namespace Core { 6#include "core/hle/service/service.h"
7class System;
8}
9 7
10namespace Service::SM { 8namespace Service::PTM {
11class ServiceManager;
12}
13 9
14namespace Service::PSM { 10class PSM final : public ServiceFramework<PSM> {
11public:
12 explicit PSM(Core::System& system_);
13 ~PSM() override;
15 14
16void InstallInterfaces(SM::ServiceManager& sm, Core::System& system); 15private:
16 enum class ChargerType : u32 {
17 Unplugged = 0,
18 RegularCharger = 1,
19 LowPowerCharger = 2,
20 Unknown = 3,
21 };
17 22
18} // namespace Service::PSM 23 void GetBatteryChargePercentage(Kernel::HLERequestContext& ctx);
24 void GetChargerType(Kernel::HLERequestContext& ctx);
25 void OpenSession(Kernel::HLERequestContext& ctx);
26
27 u32 battery_charge_percentage{100};
28 ChargerType charger_type{ChargerType::RegularCharger};
29};
30
31} // namespace Service::PTM
diff --git a/src/core/hle/service/ptm/ptm.cpp b/src/core/hle/service/ptm/ptm.cpp
new file mode 100644
index 000000000..4bea995c6
--- /dev/null
+++ b/src/core/hle/service/ptm/ptm.cpp
@@ -0,0 +1,18 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include <memory>
5
6#include "core/core.h"
7#include "core/hle/service/ptm/psm.h"
8#include "core/hle/service/ptm/ptm.h"
9#include "core/hle/service/ptm/ts.h"
10
11namespace Service::PTM {
12
13void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {
14 std::make_shared<PSM>(system)->InstallAsService(sm);
15 std::make_shared<TS>(system)->InstallAsService(sm);
16}
17
18} // namespace Service::PTM
diff --git a/src/core/hle/service/ptm/ptm.h b/src/core/hle/service/ptm/ptm.h
new file mode 100644
index 000000000..06224a24e
--- /dev/null
+++ b/src/core/hle/service/ptm/ptm.h
@@ -0,0 +1,18 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6namespace Core {
7class System;
8}
9
10namespace Service::SM {
11class ServiceManager;
12}
13
14namespace Service::PTM {
15
16void InstallInterfaces(SM::ServiceManager& sm, Core::System& system);
17
18} // namespace Service::PTM
diff --git a/src/core/hle/service/ptm/ts.cpp b/src/core/hle/service/ptm/ts.cpp
new file mode 100644
index 000000000..65c3f135f
--- /dev/null
+++ b/src/core/hle/service/ptm/ts.cpp
@@ -0,0 +1,41 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include <memory>
5
6#include "core/core.h"
7#include "core/hle/ipc_helpers.h"
8#include "core/hle/service/ptm/ts.h"
9
10namespace Service::PTM {
11
12TS::TS(Core::System& system_) : ServiceFramework{system_, "ts"} {
13 // clang-format off
14 static const FunctionInfo functions[] = {
15 {0, nullptr, "GetTemperatureRange"},
16 {1, &TS::GetTemperature, "GetTemperature"},
17 {2, nullptr, "SetMeasurementMode"},
18 {3, nullptr, "GetTemperatureMilliC"},
19 {4, nullptr, "OpenSession"},
20 };
21 // clang-format on
22
23 RegisterHandlers(functions);
24}
25
26TS::~TS() = default;
27
28void TS::GetTemperature(Kernel::HLERequestContext& ctx) {
29 IPC::RequestParser rp{ctx};
30 const auto location{rp.PopEnum<Location>()};
31
32 LOG_WARNING(Service_HID, "(STUBBED) called. location={}", location);
33
34 const s32 temperature = location == Location::Internal ? 35 : 20;
35
36 IPC::ResponseBuilder rb{ctx, 3};
37 rb.Push(ResultSuccess);
38 rb.Push(temperature);
39}
40
41} // namespace Service::PTM
diff --git a/src/core/hle/service/ptm/ts.h b/src/core/hle/service/ptm/ts.h
new file mode 100644
index 000000000..39a734ef7
--- /dev/null
+++ b/src/core/hle/service/ptm/ts.h
@@ -0,0 +1,25 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "common/common_types.h"
7#include "core/hle/service/service.h"
8
9namespace Service::PTM {
10
11class TS final : public ServiceFramework<TS> {
12public:
13 explicit TS(Core::System& system_);
14 ~TS() override;
15
16private:
17 enum class Location : u8 {
18 Internal,
19 External,
20 };
21
22 void GetTemperature(Kernel::HLERequestContext& ctx);
23};
24
25} // namespace Service::PTM
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index 318009e4f..c64291e7f 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -58,7 +58,7 @@
58#include "core/hle/service/pm/pm.h" 58#include "core/hle/service/pm/pm.h"
59#include "core/hle/service/prepo/prepo.h" 59#include "core/hle/service/prepo/prepo.h"
60#include "core/hle/service/psc/psc.h" 60#include "core/hle/service/psc/psc.h"
61#include "core/hle/service/ptm/psm.h" 61#include "core/hle/service/ptm/ptm.h"
62#include "core/hle/service/service.h" 62#include "core/hle/service/service.h"
63#include "core/hle/service/set/settings.h" 63#include "core/hle/service/set/settings.h"
64#include "core/hle/service/sm/sm.h" 64#include "core/hle/service/sm/sm.h"
@@ -287,7 +287,7 @@ Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system
287 PlayReport::InstallInterfaces(*sm, system); 287 PlayReport::InstallInterfaces(*sm, system);
288 PM::InstallInterfaces(system); 288 PM::InstallInterfaces(system);
289 PSC::InstallInterfaces(*sm, system); 289 PSC::InstallInterfaces(*sm, system);
290 PSM::InstallInterfaces(*sm, system); 290 PTM::InstallInterfaces(*sm, system);
291 Set::InstallInterfaces(*sm, system); 291 Set::InstallInterfaces(*sm, system);
292 Sockets::InstallInterfaces(*sm, system); 292 Sockets::InstallInterfaces(*sm, system);
293 SPL::InstallInterfaces(*sm, system); 293 SPL::InstallInterfaces(*sm, system);
diff --git a/src/video_core/renderer_vulkan/vk_swapchain.cpp b/src/video_core/renderer_vulkan/vk_swapchain.cpp
index a0c26a72a..fa8efd22e 100644
--- a/src/video_core/renderer_vulkan/vk_swapchain.cpp
+++ b/src/video_core/renderer_vulkan/vk_swapchain.cpp
@@ -38,7 +38,7 @@ VkPresentModeKHR ChooseSwapPresentMode(vk::Span<VkPresentModeKHR> modes) {
38 if (found_mailbox != modes.end()) { 38 if (found_mailbox != modes.end()) {
39 return VK_PRESENT_MODE_MAILBOX_KHR; 39 return VK_PRESENT_MODE_MAILBOX_KHR;
40 } 40 }
41 if (Settings::values.disable_fps_limit.GetValue()) { 41 if (!Settings::values.use_speed_limit.GetValue()) {
42 // FIFO present mode locks the framerate to the monitor's refresh rate, 42 // FIFO present mode locks the framerate to the monitor's refresh rate,
43 // Find an alternative to surpass this limitation if FPS is unlocked. 43 // Find an alternative to surpass this limitation if FPS is unlocked.
44 const auto found_imm = std::find(modes.begin(), modes.end(), VK_PRESENT_MODE_IMMEDIATE_KHR); 44 const auto found_imm = std::find(modes.begin(), modes.end(), VK_PRESENT_MODE_IMMEDIATE_KHR);
@@ -205,7 +205,7 @@ void Swapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities, u3
205 205
206 extent = swapchain_ci.imageExtent; 206 extent = swapchain_ci.imageExtent;
207 current_srgb = srgb; 207 current_srgb = srgb;
208 current_fps_unlocked = Settings::values.disable_fps_limit.GetValue(); 208 current_fps_unlocked = !Settings::values.use_speed_limit.GetValue();
209 209
210 images = swapchain.GetImages(); 210 images = swapchain.GetImages();
211 image_count = static_cast<u32>(images.size()); 211 image_count = static_cast<u32>(images.size());
@@ -259,7 +259,7 @@ void Swapchain::Destroy() {
259} 259}
260 260
261bool Swapchain::HasFpsUnlockChanged() const { 261bool Swapchain::HasFpsUnlockChanged() const {
262 return current_fps_unlocked != Settings::values.disable_fps_limit.GetValue(); 262 return current_fps_unlocked != !Settings::values.use_speed_limit.GetValue();
263} 263}
264 264
265bool Swapchain::NeedsPresentModeUpdate() const { 265bool Swapchain::NeedsPresentModeUpdate() const {
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index 9686412d0..0a61839da 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -143,8 +143,8 @@ void Config::ReadBasicSetting(Settings::Setting<std::string>& setting) {
143 } 143 }
144} 144}
145 145
146template <typename Type> 146template <typename Type, bool ranged>
147void Config::ReadBasicSetting(Settings::Setting<Type>& setting) { 147void Config::ReadBasicSetting(Settings::Setting<Type, ranged>& setting) {
148 const QString name = QString::fromStdString(setting.GetLabel()); 148 const QString name = QString::fromStdString(setting.GetLabel());
149 const Type default_value = setting.GetDefault(); 149 const Type default_value = setting.GetDefault();
150 if (qt_config->value(name + QStringLiteral("/default"), false).toBool()) { 150 if (qt_config->value(name + QStringLiteral("/default"), false).toBool()) {
@@ -164,16 +164,16 @@ void Config::WriteBasicSetting(const Settings::Setting<std::string>& setting) {
164 qt_config->setValue(name, QString::fromStdString(value)); 164 qt_config->setValue(name, QString::fromStdString(value));
165} 165}
166 166
167template <typename Type> 167template <typename Type, bool ranged>
168void Config::WriteBasicSetting(const Settings::Setting<Type>& setting) { 168void Config::WriteBasicSetting(const Settings::Setting<Type, ranged>& setting) {
169 const QString name = QString::fromStdString(setting.GetLabel()); 169 const QString name = QString::fromStdString(setting.GetLabel());
170 const Type value = setting.GetValue(); 170 const Type value = setting.GetValue();
171 qt_config->setValue(name + QStringLiteral("/default"), value == setting.GetDefault()); 171 qt_config->setValue(name + QStringLiteral("/default"), value == setting.GetDefault());
172 qt_config->setValue(name, value); 172 qt_config->setValue(name, value);
173} 173}
174 174
175template <typename Type> 175template <typename Type, bool ranged>
176void Config::WriteGlobalSetting(const Settings::SwitchableSetting<Type>& setting) { 176void Config::WriteGlobalSetting(const Settings::SwitchableSetting<Type, ranged>& setting) {
177 const QString name = QString::fromStdString(setting.GetLabel()); 177 const QString name = QString::fromStdString(setting.GetLabel());
178 const Type& value = setting.GetValue(global); 178 const Type& value = setting.GetValue(global);
179 if (!global) { 179 if (!global) {
@@ -668,7 +668,6 @@ void Config::ReadRendererValues() {
668 ReadGlobalSetting(Settings::values.max_anisotropy); 668 ReadGlobalSetting(Settings::values.max_anisotropy);
669 ReadGlobalSetting(Settings::values.use_speed_limit); 669 ReadGlobalSetting(Settings::values.use_speed_limit);
670 ReadGlobalSetting(Settings::values.speed_limit); 670 ReadGlobalSetting(Settings::values.speed_limit);
671 ReadGlobalSetting(Settings::values.fps_cap);
672 ReadGlobalSetting(Settings::values.use_disk_shader_cache); 671 ReadGlobalSetting(Settings::values.use_disk_shader_cache);
673 ReadGlobalSetting(Settings::values.gpu_accuracy); 672 ReadGlobalSetting(Settings::values.gpu_accuracy);
674 ReadGlobalSetting(Settings::values.use_asynchronous_gpu_emulation); 673 ReadGlobalSetting(Settings::values.use_asynchronous_gpu_emulation);
@@ -1237,7 +1236,6 @@ void Config::SaveRendererValues() {
1237 WriteGlobalSetting(Settings::values.max_anisotropy); 1236 WriteGlobalSetting(Settings::values.max_anisotropy);
1238 WriteGlobalSetting(Settings::values.use_speed_limit); 1237 WriteGlobalSetting(Settings::values.use_speed_limit);
1239 WriteGlobalSetting(Settings::values.speed_limit); 1238 WriteGlobalSetting(Settings::values.speed_limit);
1240 WriteGlobalSetting(Settings::values.fps_cap);
1241 WriteGlobalSetting(Settings::values.use_disk_shader_cache); 1239 WriteGlobalSetting(Settings::values.use_disk_shader_cache);
1242 WriteSetting(QString::fromStdString(Settings::values.gpu_accuracy.GetLabel()), 1240 WriteSetting(QString::fromStdString(Settings::values.gpu_accuracy.GetLabel()),
1243 static_cast<u32>(Settings::values.gpu_accuracy.GetValue(global)), 1241 static_cast<u32>(Settings::values.gpu_accuracy.GetValue(global)),
@@ -1421,8 +1419,8 @@ QVariant Config::ReadSetting(const QString& name, const QVariant& default_value)
1421 return result; 1419 return result;
1422} 1420}
1423 1421
1424template <typename Type> 1422template <typename Type, bool ranged>
1425void Config::ReadGlobalSetting(Settings::SwitchableSetting<Type>& setting) { 1423void Config::ReadGlobalSetting(Settings::SwitchableSetting<Type, ranged>& setting) {
1426 QString name = QString::fromStdString(setting.GetLabel()); 1424 QString name = QString::fromStdString(setting.GetLabel());
1427 const bool use_global = qt_config->value(name + QStringLiteral("/use_global"), true).toBool(); 1425 const bool use_global = qt_config->value(name + QStringLiteral("/use_global"), true).toBool();
1428 setting.SetGlobal(use_global); 1426 setting.SetGlobal(use_global);
diff --git a/src/yuzu/configuration/config.h b/src/yuzu/configuration/config.h
index 9ca878d23..d511b3dbd 100644
--- a/src/yuzu/configuration/config.h
+++ b/src/yuzu/configuration/config.h
@@ -159,8 +159,8 @@ private:
159 * 159 *
160 * @param The setting 160 * @param The setting
161 */ 161 */
162 template <typename Type> 162 template <typename Type, bool ranged>
163 void ReadGlobalSetting(Settings::SwitchableSetting<Type>& setting); 163 void ReadGlobalSetting(Settings::SwitchableSetting<Type, ranged>& setting);
164 164
165 /** 165 /**
166 * Sets a value to the qt_config using the setting's label and default value. If the config is a 166 * Sets a value to the qt_config using the setting's label and default value. If the config is a
@@ -168,8 +168,8 @@ private:
168 * 168 *
169 * @param The setting 169 * @param The setting
170 */ 170 */
171 template <typename Type> 171 template <typename Type, bool ranged>
172 void WriteGlobalSetting(const Settings::SwitchableSetting<Type>& setting); 172 void WriteGlobalSetting(const Settings::SwitchableSetting<Type, ranged>& setting);
173 173
174 /** 174 /**
175 * Reads a value from the qt_config using the setting's label and default value and applies the 175 * Reads a value from the qt_config using the setting's label and default value and applies the
@@ -177,15 +177,15 @@ private:
177 * 177 *
178 * @param The setting 178 * @param The setting
179 */ 179 */
180 template <typename Type> 180 template <typename Type, bool ranged>
181 void ReadBasicSetting(Settings::Setting<Type>& setting); 181 void ReadBasicSetting(Settings::Setting<Type, ranged>& setting);
182 182
183 /** Sets a value from the setting in the qt_config using the setting's label and default value. 183 /** Sets a value from the setting in the qt_config using the setting's label and default value.
184 * 184 *
185 * @param The setting 185 * @param The setting
186 */ 186 */
187 template <typename Type> 187 template <typename Type, bool ranged>
188 void WriteBasicSetting(const Settings::Setting<Type>& setting); 188 void WriteBasicSetting(const Settings::Setting<Type, ranged>& setting);
189 189
190 ConfigType type; 190 ConfigType type;
191 std::unique_ptr<QSettings> qt_config; 191 std::unique_ptr<QSettings> qt_config;
diff --git a/src/yuzu/configuration/configuration_shared.h b/src/yuzu/configuration/configuration_shared.h
index 77802a367..56800b6ff 100644
--- a/src/yuzu/configuration/configuration_shared.h
+++ b/src/yuzu/configuration/configuration_shared.h
@@ -27,8 +27,9 @@ enum class CheckState {
27// ApplyPerGameSetting, given a Settings::Setting and a Qt UI element, properly applies a Setting 27// ApplyPerGameSetting, given a Settings::Setting and a Qt UI element, properly applies a Setting
28void ApplyPerGameSetting(Settings::SwitchableSetting<bool>* setting, const QCheckBox* checkbox, 28void ApplyPerGameSetting(Settings::SwitchableSetting<bool>* setting, const QCheckBox* checkbox,
29 const CheckState& tracker); 29 const CheckState& tracker);
30template <typename Type> 30template <typename Type, bool ranged>
31void ApplyPerGameSetting(Settings::SwitchableSetting<Type>* setting, const QComboBox* combobox) { 31void ApplyPerGameSetting(Settings::SwitchableSetting<Type, ranged>* setting,
32 const QComboBox* combobox) {
32 if (Settings::IsConfiguringGlobal() && setting->UsingGlobal()) { 33 if (Settings::IsConfiguringGlobal() && setting->UsingGlobal()) {
33 setting->SetValue(static_cast<Type>(combobox->currentIndex())); 34 setting->SetValue(static_cast<Type>(combobox->currentIndex()));
34 } else if (!Settings::IsConfiguringGlobal()) { 35 } else if (!Settings::IsConfiguringGlobal()) {
@@ -45,8 +46,9 @@ void ApplyPerGameSetting(Settings::SwitchableSetting<Type>* setting, const QComb
45// Sets a Qt UI element given a Settings::Setting 46// Sets a Qt UI element given a Settings::Setting
46void SetPerGameSetting(QCheckBox* checkbox, const Settings::SwitchableSetting<bool>* setting); 47void SetPerGameSetting(QCheckBox* checkbox, const Settings::SwitchableSetting<bool>* setting);
47 48
48template <typename Type> 49template <typename Type, bool ranged>
49void SetPerGameSetting(QComboBox* combobox, const Settings::SwitchableSetting<Type>* setting) { 50void SetPerGameSetting(QComboBox* combobox,
51 const Settings::SwitchableSetting<Type, ranged>* setting) {
50 combobox->setCurrentIndex(setting->UsingGlobal() ? ConfigurationShared::USE_GLOBAL_INDEX 52 combobox->setCurrentIndex(setting->UsingGlobal() ? ConfigurationShared::USE_GLOBAL_INDEX
51 : static_cast<int>(setting->GetValue()) + 53 : static_cast<int>(setting->GetValue()) +
52 ConfigurationShared::USE_GLOBAL_OFFSET); 54 ConfigurationShared::USE_GLOBAL_OFFSET);
diff --git a/src/yuzu/configuration/configure_general.cpp b/src/yuzu/configuration/configure_general.cpp
index a31fabd3f..2a446205b 100644
--- a/src/yuzu/configuration/configure_general.cpp
+++ b/src/yuzu/configuration/configure_general.cpp
@@ -27,9 +27,6 @@ ConfigureGeneral::ConfigureGeneral(const Core::System& system_, QWidget* parent)
27 27
28 connect(ui->button_reset_defaults, &QPushButton::clicked, this, 28 connect(ui->button_reset_defaults, &QPushButton::clicked, this,
29 &ConfigureGeneral::ResetDefaults); 29 &ConfigureGeneral::ResetDefaults);
30
31 ui->fps_cap_label->setVisible(Settings::IsConfiguringGlobal());
32 ui->fps_cap_combobox->setVisible(!Settings::IsConfiguringGlobal());
33} 30}
34 31
35ConfigureGeneral::~ConfigureGeneral() = default; 32ConfigureGeneral::~ConfigureGeneral() = default;
@@ -52,8 +49,6 @@ void ConfigureGeneral::SetConfiguration() {
52 ui->toggle_speed_limit->setChecked(Settings::values.use_speed_limit.GetValue()); 49 ui->toggle_speed_limit->setChecked(Settings::values.use_speed_limit.GetValue());
53 ui->speed_limit->setValue(Settings::values.speed_limit.GetValue()); 50 ui->speed_limit->setValue(Settings::values.speed_limit.GetValue());
54 51
55 ui->fps_cap->setValue(Settings::values.fps_cap.GetValue());
56
57 ui->button_reset_defaults->setEnabled(runtime_lock); 52 ui->button_reset_defaults->setEnabled(runtime_lock);
58 53
59 if (Settings::IsConfiguringGlobal()) { 54 if (Settings::IsConfiguringGlobal()) {
@@ -61,11 +56,6 @@ void ConfigureGeneral::SetConfiguration() {
61 } else { 56 } else {
62 ui->speed_limit->setEnabled(Settings::values.use_speed_limit.GetValue() && 57 ui->speed_limit->setEnabled(Settings::values.use_speed_limit.GetValue() &&
63 use_speed_limit != ConfigurationShared::CheckState::Global); 58 use_speed_limit != ConfigurationShared::CheckState::Global);
64
65 ui->fps_cap_combobox->setCurrentIndex(Settings::values.fps_cap.UsingGlobal() ? 0 : 1);
66 ui->fps_cap->setEnabled(!Settings::values.fps_cap.UsingGlobal());
67 ConfigurationShared::SetHighlight(ui->fps_cap_layout,
68 !Settings::values.fps_cap.UsingGlobal());
69 } 59 }
70} 60}
71 61
@@ -102,8 +92,6 @@ void ConfigureGeneral::ApplyConfiguration() {
102 UISettings::values.mute_when_in_background = ui->toggle_background_mute->isChecked(); 92 UISettings::values.mute_when_in_background = ui->toggle_background_mute->isChecked();
103 UISettings::values.hide_mouse = ui->toggle_hide_mouse->isChecked(); 93 UISettings::values.hide_mouse = ui->toggle_hide_mouse->isChecked();
104 94
105 Settings::values.fps_cap.SetValue(ui->fps_cap->value());
106
107 // Guard if during game and set to game-specific value 95 // Guard if during game and set to game-specific value
108 if (Settings::values.use_speed_limit.UsingGlobal()) { 96 if (Settings::values.use_speed_limit.UsingGlobal()) {
109 Settings::values.use_speed_limit.SetValue(ui->toggle_speed_limit->checkState() == 97 Settings::values.use_speed_limit.SetValue(ui->toggle_speed_limit->checkState() ==
@@ -119,13 +107,6 @@ void ConfigureGeneral::ApplyConfiguration() {
119 Qt::Checked); 107 Qt::Checked);
120 Settings::values.speed_limit.SetValue(ui->speed_limit->value()); 108 Settings::values.speed_limit.SetValue(ui->speed_limit->value());
121 } 109 }
122
123 if (ui->fps_cap_combobox->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
124 Settings::values.fps_cap.SetGlobal(true);
125 } else {
126 Settings::values.fps_cap.SetGlobal(false);
127 Settings::values.fps_cap.SetValue(ui->fps_cap->value());
128 }
129 } 110 }
130} 111}
131 112
@@ -171,9 +152,4 @@ void ConfigureGeneral::SetupPerGameUI() {
171 ui->speed_limit->setEnabled(ui->toggle_speed_limit->isChecked() && 152 ui->speed_limit->setEnabled(ui->toggle_speed_limit->isChecked() &&
172 (use_speed_limit != ConfigurationShared::CheckState::Global)); 153 (use_speed_limit != ConfigurationShared::CheckState::Global));
173 }); 154 });
174
175 connect(ui->fps_cap_combobox, qOverload<int>(&QComboBox::activated), this, [this](int index) {
176 ui->fps_cap->setEnabled(index == 1);
177 ConfigurationShared::SetHighlight(ui->fps_cap_layout, index == 1);
178 });
179} 155}
diff --git a/src/yuzu/configuration/configure_general.ui b/src/yuzu/configuration/configure_general.ui
index c6ef2ab70..5b90b1109 100644
--- a/src/yuzu/configuration/configure_general.ui
+++ b/src/yuzu/configuration/configure_general.ui
@@ -28,87 +28,6 @@
28 <item> 28 <item>
29 <layout class="QVBoxLayout" name="GeneralVerticalLayout"> 29 <layout class="QVBoxLayout" name="GeneralVerticalLayout">
30 <item> 30 <item>
31 <widget class="QWidget" name="fps_cap_layout" native="true">
32 <layout class="QHBoxLayout" name="horizontalLayout" stretch="1,1">
33 <property name="leftMargin">
34 <number>0</number>
35 </property>
36 <property name="topMargin">
37 <number>0</number>
38 </property>
39 <property name="rightMargin">
40 <number>0</number>
41 </property>
42 <property name="bottomMargin">
43 <number>0</number>
44 </property>
45 <item>
46 <layout class="QHBoxLayout" name="horizontalLayout_4">
47 <item>
48 <widget class="QComboBox" name="fps_cap_combobox">
49 <property name="currentText">
50 <string>Use global framerate cap</string>
51 </property>
52 <property name="currentIndex">
53 <number>0</number>
54 </property>
55 <item>
56 <property name="text">
57 <string>Use global framerate cap</string>
58 </property>
59 </item>
60 <item>
61 <property name="text">
62 <string>Set framerate cap:</string>
63 </property>
64 </item>
65 </widget>
66 </item>
67 <item>
68 <widget class="QLabel" name="fps_cap_label">
69 <property name="toolTip">
70 <string>Requires the use of the FPS Limiter Toggle hotkey to take effect.</string>
71 </property>
72 <property name="text">
73 <string>Framerate Cap</string>
74 </property>
75 </widget>
76 </item>
77 <item>
78 <spacer name="horizontalSpacer">
79 <property name="orientation">
80 <enum>Qt::Horizontal</enum>
81 </property>
82 <property name="sizeHint" stdset="0">
83 <size>
84 <width>40</width>
85 <height>20</height>
86 </size>
87 </property>
88 </spacer>
89 </item>
90 </layout>
91 </item>
92 <item>
93 <widget class="QSpinBox" name="fps_cap">
94 <property name="suffix">
95 <string>x</string>
96 </property>
97 <property name="minimum">
98 <number>1</number>
99 </property>
100 <property name="maximum">
101 <number>1000</number>
102 </property>
103 <property name="value">
104 <number>500</number>
105 </property>
106 </widget>
107 </item>
108 </layout>
109 </widget>
110 </item>
111 <item>
112 <layout class="QHBoxLayout" name="horizontalLayout_2"> 31 <layout class="QHBoxLayout" name="horizontalLayout_2">
113 <item> 32 <item>
114 <widget class="QCheckBox" name="toggle_speed_limit"> 33 <widget class="QCheckBox" name="toggle_speed_limit">
diff --git a/src/yuzu/configuration/configure_input.ui b/src/yuzu/configuration/configure_input.ui
index 2707025e7..d51774028 100644
--- a/src/yuzu/configuration/configure_input.ui
+++ b/src/yuzu/configuration/configure_input.ui
@@ -166,7 +166,7 @@
166 <item> 166 <item>
167 <widget class="QRadioButton" name="radioUndocked"> 167 <widget class="QRadioButton" name="radioUndocked">
168 <property name="text"> 168 <property name="text">
169 <string>Undocked</string> 169 <string>Handheld</string>
170 </property> 170 </property>
171 </widget> 171 </widget>
172 </item> 172 </item>
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index b460020b1..e60d84054 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -1059,7 +1059,7 @@ void GMainWindow::InitializeHotkeys() {
1059 Settings::values.volume.SetValue(static_cast<u8>(new_volume)); 1059 Settings::values.volume.SetValue(static_cast<u8>(new_volume));
1060 }); 1060 });
1061 connect_shortcut(QStringLiteral("Toggle Framerate Limit"), [] { 1061 connect_shortcut(QStringLiteral("Toggle Framerate Limit"), [] {
1062 Settings::values.disable_fps_limit.SetValue(!Settings::values.disable_fps_limit.GetValue()); 1062 Settings::values.use_speed_limit.SetValue(!Settings::values.use_speed_limit.GetValue());
1063 }); 1063 });
1064 connect_shortcut(QStringLiteral("Toggle Mouse Panning"), [&] { 1064 connect_shortcut(QStringLiteral("Toggle Mouse Panning"), [&] {
1065 Settings::values.mouse_panning = !Settings::values.mouse_panning; 1065 Settings::values.mouse_panning = !Settings::values.mouse_panning;
@@ -1131,6 +1131,7 @@ void GMainWindow::OnAppFocusStateChanged(Qt::ApplicationState state) {
1131 OnPauseGame(); 1131 OnPauseGame();
1132 } else if (!emu_thread->IsRunning() && auto_paused && state == Qt::ApplicationActive) { 1132 } else if (!emu_thread->IsRunning() && auto_paused && state == Qt::ApplicationActive) {
1133 auto_paused = false; 1133 auto_paused = false;
1134 RequestGameResume();
1134 OnStartGame(); 1135 OnStartGame();
1135 } 1136 }
1136 } 1137 }
@@ -1483,9 +1484,6 @@ void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t
1483 Config per_game_config(*system, config_file_name, Config::ConfigType::PerGameConfig); 1484 Config per_game_config(*system, config_file_name, Config::ConfigType::PerGameConfig);
1484 } 1485 }
1485 1486
1486 // Disable fps limit toggle when booting a new title
1487 Settings::values.disable_fps_limit.SetValue(false);
1488
1489 // Save configurations 1487 // Save configurations
1490 UpdateUISettings(); 1488 UpdateUISettings();
1491 game_list->SaveInterfaceLayout(); 1489 game_list->SaveInterfaceLayout();
@@ -2573,6 +2571,7 @@ void GMainWindow::OnPauseContinueGame() {
2573 if (emu_thread->IsRunning()) { 2571 if (emu_thread->IsRunning()) {
2574 OnPauseGame(); 2572 OnPauseGame();
2575 } else { 2573 } else {
2574 RequestGameResume();
2576 OnStartGame(); 2575 OnStartGame();
2577 } 2576 }
2578 } 2577 }
@@ -3277,7 +3276,7 @@ void GMainWindow::UpdateStatusBar() {
3277 } else { 3276 } else {
3278 emu_speed_label->setText(tr("Speed: %1%").arg(results.emulation_speed * 100.0, 0, 'f', 0)); 3277 emu_speed_label->setText(tr("Speed: %1%").arg(results.emulation_speed * 100.0, 0, 'f', 0));
3279 } 3278 }
3280 if (Settings::values.disable_fps_limit) { 3279 if (!Settings::values.use_speed_limit) {
3281 game_fps_label->setText( 3280 game_fps_label->setText(
3282 tr("Game: %1 FPS (Unlocked)").arg(results.average_game_fps, 0, 'f', 0)); 3281 tr("Game: %1 FPS (Unlocked)").arg(results.average_game_fps, 0, 'f', 0));
3283 } else { 3282 } else {
@@ -3752,6 +3751,21 @@ void GMainWindow::RequestGameExit() {
3752 } 3751 }
3753} 3752}
3754 3753
3754void GMainWindow::RequestGameResume() {
3755 auto& sm{system->ServiceManager()};
3756 auto applet_oe = sm.GetService<Service::AM::AppletOE>("appletOE");
3757 auto applet_ae = sm.GetService<Service::AM::AppletAE>("appletAE");
3758
3759 if (applet_oe != nullptr) {
3760 applet_oe->GetMessageQueue()->RequestResume();
3761 return;
3762 }
3763
3764 if (applet_ae != nullptr) {
3765 applet_ae->GetMessageQueue()->RequestResume();
3766 }
3767}
3768
3755void GMainWindow::filterBarSetChecked(bool state) { 3769void GMainWindow::filterBarSetChecked(bool state) {
3756 ui->action_Show_Filter_Bar->setChecked(state); 3770 ui->action_Show_Filter_Bar->setChecked(state);
3757 emit(OnToggleFilterBar()); 3771 emit(OnToggleFilterBar());
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index 8cf224c9c..09e37f152 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -244,6 +244,7 @@ private:
244 bool ConfirmChangeGame(); 244 bool ConfirmChangeGame();
245 bool ConfirmForceLockedExit(); 245 bool ConfirmForceLockedExit();
246 void RequestGameExit(); 246 void RequestGameExit();
247 void RequestGameResume();
247 void closeEvent(QCloseEvent* event) override; 248 void closeEvent(QCloseEvent* event) override;
248 249
249private slots: 250private slots:
diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp
index 903e02297..5576fb795 100644
--- a/src/yuzu_cmd/config.cpp
+++ b/src/yuzu_cmd/config.cpp
@@ -99,8 +99,8 @@ void Config::ReadSetting(const std::string& group, Settings::Setting<bool>& sett
99 setting = sdl2_config->GetBoolean(group, setting.GetLabel(), setting.GetDefault()); 99 setting = sdl2_config->GetBoolean(group, setting.GetLabel(), setting.GetDefault());
100} 100}
101 101
102template <typename Type> 102template <typename Type, bool ranged>
103void Config::ReadSetting(const std::string& group, Settings::Setting<Type>& setting) { 103void Config::ReadSetting(const std::string& group, Settings::Setting<Type, ranged>& setting) {
104 setting = static_cast<Type>(sdl2_config->GetInteger(group, setting.GetLabel(), 104 setting = static_cast<Type>(sdl2_config->GetInteger(group, setting.GetLabel(),
105 static_cast<long>(setting.GetDefault()))); 105 static_cast<long>(setting.GetDefault())));
106} 106}
@@ -310,8 +310,6 @@ void Config::ReadValues() {
310 ReadSetting("Renderer", Settings::values.gpu_accuracy); 310 ReadSetting("Renderer", Settings::values.gpu_accuracy);
311 ReadSetting("Renderer", Settings::values.use_asynchronous_gpu_emulation); 311 ReadSetting("Renderer", Settings::values.use_asynchronous_gpu_emulation);
312 ReadSetting("Renderer", Settings::values.use_vsync); 312 ReadSetting("Renderer", Settings::values.use_vsync);
313 ReadSetting("Renderer", Settings::values.fps_cap);
314 ReadSetting("Renderer", Settings::values.disable_fps_limit);
315 ReadSetting("Renderer", Settings::values.shader_backend); 313 ReadSetting("Renderer", Settings::values.shader_backend);
316 ReadSetting("Renderer", Settings::values.use_asynchronous_shaders); 314 ReadSetting("Renderer", Settings::values.use_asynchronous_shaders);
317 ReadSetting("Renderer", Settings::values.nvdec_emulation); 315 ReadSetting("Renderer", Settings::values.nvdec_emulation);
diff --git a/src/yuzu_cmd/config.h b/src/yuzu_cmd/config.h
index ccf77d668..32c03075f 100644
--- a/src/yuzu_cmd/config.h
+++ b/src/yuzu_cmd/config.h
@@ -33,6 +33,6 @@ private:
33 * @param group The name of the INI group 33 * @param group The name of the INI group
34 * @param setting The yuzu setting to modify 34 * @param setting The yuzu setting to modify
35 */ 35 */
36 template <typename Type> 36 template <typename Type, bool ranged>
37 void ReadSetting(const std::string& group, Settings::Setting<Type>& setting); 37 void ReadSetting(const std::string& group, Settings::Setting<Type, ranged>& setting);
38}; 38};
diff --git a/src/yuzu_cmd/default_ini.h b/src/yuzu_cmd/default_ini.h
index a3b8432f5..d9a2a460c 100644
--- a/src/yuzu_cmd/default_ini.h
+++ b/src/yuzu_cmd/default_ini.h
@@ -330,10 +330,6 @@ bg_red =
330bg_blue = 330bg_blue =
331bg_green = 331bg_green =
332 332
333# Caps the unlocked framerate to a multiple of the title's target FPS.
334# 1 - 1000: Target FPS multiple cap. 1000 (default)
335fps_cap =
336
337[Audio] 333[Audio]
338# Which audio output engine to use. 334# Which audio output engine to use.
339# auto (default): Auto-select 335# auto (default): Auto-select
@@ -434,9 +430,6 @@ use_debug_asserts =
434use_auto_stub = 430use_auto_stub =
435# Enables/Disables the macro JIT compiler 431# Enables/Disables the macro JIT compiler
436disable_macro_jit=false 432disable_macro_jit=false
437# Presents guest frames as they become available. Experimental.
438# false: Disabled (default), true: Enabled
439disable_fps_limit=false
440# Determines whether to enable the GDB stub and wait for the debugger to attach before running. 433# Determines whether to enable the GDB stub and wait for the debugger to attach before running.
441# false: Disabled (default), true: Enabled 434# false: Disabled (default), true: Enabled
442use_gdbstub=false 435use_gdbstub=false