summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt8
-rw-r--r--src/common/fiber.cpp21
-rw-r--r--src/common/fiber.h7
-rw-r--r--src/common/settings.h452
-rw-r--r--src/core/arm/arm_interface.cpp15
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_32.cpp30
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_32.h2
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_64.cpp17
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_64.h2
-rw-r--r--src/core/cpu_manager.cpp51
-rw-r--r--src/core/cpu_manager.h21
-rw-r--r--src/core/debugger/gdbstub_arch.cpp8
-rw-r--r--src/core/hid/hid_types.h1
-rw-r--r--src/core/hle/kernel/k_process.cpp2
-rw-r--r--src/core/hle/kernel/k_scheduler.cpp7
-rw-r--r--src/core/hle/kernel/k_scheduler.h1
-rw-r--r--src/core/hle/kernel/k_thread.cpp22
-rw-r--r--src/core/hle/kernel/k_thread.h3
-rw-r--r--src/core/hle/service/hid/controllers/npad.cpp34
-rw-r--r--src/core/hle/service/hid/controllers/npad.h3
-rw-r--r--src/core/hle/service/hid/errors.h3
-rw-r--r--src/core/hle/service/hid/hid.cpp75
-rw-r--r--src/tests/common/fibers.cpp123
-rw-r--r--src/yuzu/applets/qt_web_browser.cpp6
-rw-r--r--src/yuzu/configuration/config.cpp12
-rw-r--r--src/yuzu/configuration/config.h8
-rw-r--r--src/yuzu/configuration/configuration_shared.cpp6
-rw-r--r--src/yuzu/configuration/configuration_shared.h10
-rw-r--r--src/yuzu/uisettings.h54
-rw-r--r--src/yuzu_cmd/config.cpp6
-rw-r--r--src/yuzu_cmd/config.h4
31 files changed, 459 insertions, 555 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 39d038493..39ae573b2 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -36,7 +36,6 @@ if (MSVC)
36 # /GT - Supports fiber safety for data allocated using static thread-local storage 36 # /GT - Supports fiber safety for data allocated using static thread-local storage
37 add_compile_options( 37 add_compile_options(
38 /MP 38 /MP
39 /Zi
40 /Zm200 39 /Zm200
41 /Zo 40 /Zo
42 /permissive- 41 /permissive-
@@ -79,6 +78,13 @@ if (MSVC)
79 /we5245 # 'function': unreferenced function with internal linkage has been removed 78 /we5245 # 'function': unreferenced function with internal linkage has been removed
80 ) 79 )
81 80
81 if (USE_CCACHE)
82 # when caching, we need to use /Z7 to downgrade debug info to use an older but more cachable format
83 add_compile_options(/Z7)
84 else()
85 add_compile_options(/Zi)
86 endif()
87
82 if (ARCHITECTURE_x86_64) 88 if (ARCHITECTURE_x86_64)
83 add_compile_options(/QIntel-jcc-erratum) 89 add_compile_options(/QIntel-jcc-erratum)
84 endif() 90 endif()
diff --git a/src/common/fiber.cpp b/src/common/fiber.cpp
index f9aeb692a..bc92b360b 100644
--- a/src/common/fiber.cpp
+++ b/src/common/fiber.cpp
@@ -20,10 +20,8 @@ struct Fiber::FiberImpl {
20 VirtualBuffer<u8> rewind_stack; 20 VirtualBuffer<u8> rewind_stack;
21 21
22 std::mutex guard; 22 std::mutex guard;
23 std::function<void(void*)> entry_point; 23 std::function<void()> entry_point;
24 std::function<void(void*)> rewind_point; 24 std::function<void()> rewind_point;
25 void* rewind_parameter{};
26 void* start_parameter{};
27 std::shared_ptr<Fiber> previous_fiber; 25 std::shared_ptr<Fiber> previous_fiber;
28 bool is_thread_fiber{}; 26 bool is_thread_fiber{};
29 bool released{}; 27 bool released{};
@@ -34,13 +32,8 @@ struct Fiber::FiberImpl {
34 boost::context::detail::fcontext_t rewind_context{}; 32 boost::context::detail::fcontext_t rewind_context{};
35}; 33};
36 34
37void Fiber::SetStartParameter(void* new_parameter) { 35void Fiber::SetRewindPoint(std::function<void()>&& rewind_func) {
38 impl->start_parameter = new_parameter;
39}
40
41void Fiber::SetRewindPoint(std::function<void(void*)>&& rewind_func, void* rewind_param) {
42 impl->rewind_point = std::move(rewind_func); 36 impl->rewind_point = std::move(rewind_func);
43 impl->rewind_parameter = rewind_param;
44} 37}
45 38
46void Fiber::Start(boost::context::detail::transfer_t& transfer) { 39void Fiber::Start(boost::context::detail::transfer_t& transfer) {
@@ -48,7 +41,7 @@ void Fiber::Start(boost::context::detail::transfer_t& transfer) {
48 impl->previous_fiber->impl->context = transfer.fctx; 41 impl->previous_fiber->impl->context = transfer.fctx;
49 impl->previous_fiber->impl->guard.unlock(); 42 impl->previous_fiber->impl->guard.unlock();
50 impl->previous_fiber.reset(); 43 impl->previous_fiber.reset();
51 impl->entry_point(impl->start_parameter); 44 impl->entry_point();
52 UNREACHABLE(); 45 UNREACHABLE();
53} 46}
54 47
@@ -59,7 +52,7 @@ void Fiber::OnRewind([[maybe_unused]] boost::context::detail::transfer_t& transf
59 u8* tmp = impl->stack_limit; 52 u8* tmp = impl->stack_limit;
60 impl->stack_limit = impl->rewind_stack_limit; 53 impl->stack_limit = impl->rewind_stack_limit;
61 impl->rewind_stack_limit = tmp; 54 impl->rewind_stack_limit = tmp;
62 impl->rewind_point(impl->rewind_parameter); 55 impl->rewind_point();
63 UNREACHABLE(); 56 UNREACHABLE();
64} 57}
65 58
@@ -73,10 +66,8 @@ void Fiber::RewindStartFunc(boost::context::detail::transfer_t transfer) {
73 fiber->OnRewind(transfer); 66 fiber->OnRewind(transfer);
74} 67}
75 68
76Fiber::Fiber(std::function<void(void*)>&& entry_point_func, void* start_parameter) 69Fiber::Fiber(std::function<void()>&& entry_point_func) : impl{std::make_unique<FiberImpl>()} {
77 : impl{std::make_unique<FiberImpl>()} {
78 impl->entry_point = std::move(entry_point_func); 70 impl->entry_point = std::move(entry_point_func);
79 impl->start_parameter = start_parameter;
80 impl->stack_limit = impl->stack.data(); 71 impl->stack_limit = impl->stack.data();
81 impl->rewind_stack_limit = impl->rewind_stack.data(); 72 impl->rewind_stack_limit = impl->rewind_stack.data();
82 u8* stack_base = impl->stack_limit + default_stack_size; 73 u8* stack_base = impl->stack_limit + default_stack_size;
diff --git a/src/common/fiber.h b/src/common/fiber.h
index 873604bc6..f24d333a3 100644
--- a/src/common/fiber.h
+++ b/src/common/fiber.h
@@ -29,7 +29,7 @@ namespace Common {
29 */ 29 */
30class Fiber { 30class Fiber {
31public: 31public:
32 Fiber(std::function<void(void*)>&& entry_point_func, void* start_parameter); 32 Fiber(std::function<void()>&& entry_point_func);
33 ~Fiber(); 33 ~Fiber();
34 34
35 Fiber(const Fiber&) = delete; 35 Fiber(const Fiber&) = delete;
@@ -43,16 +43,13 @@ public:
43 static void YieldTo(std::weak_ptr<Fiber> weak_from, Fiber& to); 43 static void YieldTo(std::weak_ptr<Fiber> weak_from, Fiber& to);
44 [[nodiscard]] static std::shared_ptr<Fiber> ThreadToFiber(); 44 [[nodiscard]] static std::shared_ptr<Fiber> ThreadToFiber();
45 45
46 void SetRewindPoint(std::function<void(void*)>&& rewind_func, void* rewind_param); 46 void SetRewindPoint(std::function<void()>&& rewind_func);
47 47
48 void Rewind(); 48 void Rewind();
49 49
50 /// Only call from main thread's fiber 50 /// Only call from main thread's fiber
51 void Exit(); 51 void Exit();
52 52
53 /// Changes the start parameter of the fiber. Has no effect if the fiber already started
54 void SetStartParameter(void* new_parameter);
55
56private: 53private:
57 Fiber(); 54 Fiber();
58 55
diff --git a/src/common/settings.h b/src/common/settings.h
index a507744a2..3583a2e70 100644
--- a/src/common/settings.h
+++ b/src/common/settings.h
@@ -101,15 +101,15 @@ struct ResolutionScalingInfo {
101 } 101 }
102}; 102};
103 103
104/** The BasicSetting class is a simple resource manager. It defines a label and default value 104/** The Setting class is a simple resource manager. It defines a label and default value alongside
105 * alongside the actual value of the setting for simpler and less-error prone use with frontend 105 * the actual value of the setting for simpler and less-error prone use with frontend
106 * configurations. Setting a default value and label is required, though subclasses may deviate from 106 * configurations. Specifying a default value and label is required. A minimum and maximum range can
107 * this requirement. 107 * be specified for sanitization.
108 */ 108 */
109template <typename Type> 109template <typename Type>
110class BasicSetting { 110class Setting {
111protected: 111protected:
112 BasicSetting() = default; 112 Setting() = default;
113 113
114 /** 114 /**
115 * Only sets the setting to the given initializer, leaving the other members to their default 115 * Only sets the setting to the given initializer, leaving the other members to their default
@@ -117,7 +117,7 @@ protected:
117 * 117 *
118 * @param global_val Initial value of the setting 118 * @param global_val Initial value of the setting
119 */ 119 */
120 explicit BasicSetting(const Type& global_val) : global{global_val} {} 120 explicit Setting(const Type& val) : value{val} {}
121 121
122public: 122public:
123 /** 123 /**
@@ -126,9 +126,22 @@ 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 BasicSetting(const Type& default_val, const std::string& name) 129 explicit Setting(const Type& default_val, const std::string& name)
130 : default_value{default_val}, global{default_val}, label{name} {} 130 : value{default_val}, default_value{default_val}, ranged{false}, label{name} {}
131 virtual ~BasicSetting() = default; 131 virtual ~Setting() = default;
132
133 /**
134 * Sets a default value, minimum value, maximum value, and label.
135 *
136 * @param default_val Intial value of the setting, and default value of the setting
137 * @param min_val Sets the minimum allowed value of the setting
138 * @param max_val Sets the maximum allowed value of the setting
139 * @param name Label for the setting
140 */
141 explicit Setting(const Type& default_val, const Type& min_val, const Type& max_val,
142 const std::string& name)
143 : value{default_val}, default_value{default_val}, maximum{max_val}, minimum{min_val},
144 ranged{true}, label{name} {}
132 145
133 /** 146 /**
134 * Returns a reference to the setting's value. 147 * Returns a reference to the setting's value.
@@ -136,17 +149,17 @@ public:
136 * @returns A reference to the setting 149 * @returns A reference to the setting
137 */ 150 */
138 [[nodiscard]] virtual const Type& GetValue() const { 151 [[nodiscard]] virtual const Type& GetValue() const {
139 return global; 152 return value;
140 } 153 }
141 154
142 /** 155 /**
143 * Sets the setting to the given value. 156 * Sets the setting to the given value.
144 * 157 *
145 * @param value The desired value 158 * @param val The desired value
146 */ 159 */
147 virtual void SetValue(const Type& value) { 160 virtual void SetValue(const Type& val) {
148 Type temp{value}; 161 Type temp{(ranged) ? std::clamp(val, minimum, maximum) : val};
149 std::swap(global, temp); 162 std::swap(value, temp);
150 } 163 }
151 164
152 /** 165 /**
@@ -170,14 +183,14 @@ public:
170 /** 183 /**
171 * Assigns a value to the setting. 184 * Assigns a value to the setting.
172 * 185 *
173 * @param value The desired setting value 186 * @param val The desired setting value
174 * 187 *
175 * @returns A reference to the setting 188 * @returns A reference to the setting
176 */ 189 */
177 virtual const Type& operator=(const Type& value) { 190 virtual const Type& operator=(const Type& val) {
178 Type temp{value}; 191 Type temp{(ranged) ? std::clamp(val, minimum, maximum) : val};
179 std::swap(global, temp); 192 std::swap(value, temp);
180 return global; 193 return value;
181 } 194 }
182 195
183 /** 196 /**
@@ -186,72 +199,28 @@ public:
186 * @returns A reference to the setting 199 * @returns A reference to the setting
187 */ 200 */
188 explicit virtual operator const Type&() const { 201 explicit virtual operator const Type&() const {
189 return global; 202 return value;
190 } 203 }
191 204
192protected: 205protected:
206 Type value{}; ///< The setting
193 const Type default_value{}; ///< The default value 207 const Type default_value{}; ///< The default value
194 Type global{}; ///< The setting 208 const Type maximum{}; ///< Maximum allowed value of the setting
209 const Type minimum{}; ///< Minimum allowed value of the setting
210 const bool ranged; ///< The setting has sanitization ranges
195 const std::string label{}; ///< The setting's label 211 const std::string label{}; ///< The setting's label
196}; 212};
197 213
198/** 214/**
199 * BasicRangedSetting class is intended for use with quantifiable settings that need a more 215 * The SwitchableSetting class is a slightly more complex version of the Setting class. This adds a
200 * restrictive range than implicitly defined by its type. Implements a minimum and maximum that is
201 * simply used to sanitize SetValue and the assignment overload.
202 */
203template <typename Type>
204class BasicRangedSetting : virtual public BasicSetting<Type> {
205public:
206 /**
207 * Sets a default value, minimum value, maximum value, and label.
208 *
209 * @param default_val Intial value of the setting, and default value of the setting
210 * @param min_val Sets the minimum allowed value of the setting
211 * @param max_val Sets the maximum allowed value of the setting
212 * @param name Label for the setting
213 */
214 explicit BasicRangedSetting(const Type& default_val, const Type& min_val, const Type& max_val,
215 const std::string& name)
216 : BasicSetting<Type>{default_val, name}, minimum{min_val}, maximum{max_val} {}
217 virtual ~BasicRangedSetting() = default;
218
219 /**
220 * Like BasicSetting's SetValue, except value is clamped to the range of the setting.
221 *
222 * @param value The desired value
223 */
224 void SetValue(const Type& value) override {
225 this->global = std::clamp(value, minimum, maximum);
226 }
227
228 /**
229 * Like BasicSetting's assignment overload, except value is clamped to the range of the setting.
230 *
231 * @param value The desired value
232 * @returns A reference to the setting's value
233 */
234 const Type& operator=(const Type& value) override {
235 this->global = std::clamp(value, minimum, maximum);
236 return this->global;
237 }
238
239 const Type minimum; ///< Minimum allowed value of the setting
240 const Type maximum; ///< Maximum allowed value of the setting
241};
242
243/**
244 * The Setting class is a slightly more complex version of the BasicSetting class. This adds a
245 * custom setting to switch to when a guest application specifically requires it. The effect is that 216 * custom setting to switch to when a guest application specifically requires it. The effect is that
246 * other components of the emulator can access the setting's intended value without any need for the 217 * other components of the emulator can access the setting's intended value without any need for the
247 * component to ask whether the custom or global setting is needed at the moment. 218 * component to ask whether the custom or global setting is needed at the moment.
248 * 219 *
249 * By default, the global setting is used. 220 * By default, the global setting is used.
250 *
251 * Like the BasicSetting, this requires setting a default value and label to use.
252 */ 221 */
253template <typename Type> 222template <typename Type>
254class Setting : virtual public BasicSetting<Type> { 223class SwitchableSetting : virtual public Setting<Type> {
255public: 224public:
256 /** 225 /**
257 * Sets a default value, label, and setting value. 226 * Sets a default value, label, and setting value.
@@ -259,9 +228,21 @@ public:
259 * @param default_val Intial value of the setting, and default value of the setting 228 * @param default_val Intial value of the setting, and default value of the setting
260 * @param name Label for the setting 229 * @param name Label for the setting
261 */ 230 */
262 explicit Setting(const Type& default_val, const std::string& name) 231 explicit SwitchableSetting(const Type& default_val, const std::string& name)
263 : BasicSetting<Type>(default_val, name) {} 232 : Setting<Type>{default_val, name} {}
264 virtual ~Setting() = default; 233 virtual ~SwitchableSetting() = default;
234
235 /**
236 * Sets a default value, minimum value, maximum value, and label.
237 *
238 * @param default_val Intial value of the setting, and default value of the setting
239 * @param min_val Sets the minimum allowed value of the setting
240 * @param max_val Sets the maximum allowed value of the setting
241 * @param name Label for the setting
242 */
243 explicit SwitchableSetting(const Type& default_val, const Type& min_val, const Type& max_val,
244 const std::string& name)
245 : Setting<Type>{default_val, min_val, max_val, name} {}
265 246
266 /** 247 /**
267 * Tells this setting to represent either the global or custom setting when other member 248 * Tells this setting to represent either the global or custom setting when other member
@@ -292,13 +273,13 @@ public:
292 */ 273 */
293 [[nodiscard]] virtual const Type& GetValue() const override { 274 [[nodiscard]] virtual const Type& GetValue() const override {
294 if (use_global) { 275 if (use_global) {
295 return this->global; 276 return this->value;
296 } 277 }
297 return custom; 278 return custom;
298 } 279 }
299 [[nodiscard]] virtual const Type& GetValue(bool need_global) const { 280 [[nodiscard]] virtual const Type& GetValue(bool need_global) const {
300 if (use_global || need_global) { 281 if (use_global || need_global) {
301 return this->global; 282 return this->value;
302 } 283 }
303 return custom; 284 return custom;
304 } 285 }
@@ -306,12 +287,12 @@ public:
306 /** 287 /**
307 * Sets the current setting value depending on the global state. 288 * Sets the current setting value depending on the global state.
308 * 289 *
309 * @param value The new value 290 * @param val The new value
310 */ 291 */
311 void SetValue(const Type& value) override { 292 void SetValue(const Type& val) override {
312 Type temp{value}; 293 Type temp{(this->ranged) ? std::clamp(val, this->minimum, this->maximum) : val};
313 if (use_global) { 294 if (use_global) {
314 std::swap(this->global, temp); 295 std::swap(this->value, temp);
315 } else { 296 } else {
316 std::swap(custom, temp); 297 std::swap(custom, temp);
317 } 298 }
@@ -320,15 +301,15 @@ public:
320 /** 301 /**
321 * Assigns the current setting value depending on the global state. 302 * Assigns the current setting value depending on the global state.
322 * 303 *
323 * @param value The new value 304 * @param val The new value
324 * 305 *
325 * @returns A reference to the current setting value 306 * @returns A reference to the current setting value
326 */ 307 */
327 const Type& operator=(const Type& value) override { 308 const Type& operator=(const Type& val) override {
328 Type temp{value}; 309 Type temp{(this->ranged) ? std::clamp(val, this->minimum, this->maximum) : val};
329 if (use_global) { 310 if (use_global) {
330 std::swap(this->global, temp); 311 std::swap(this->value, temp);
331 return this->global; 312 return this->value;
332 } 313 }
333 std::swap(custom, temp); 314 std::swap(custom, temp);
334 return custom; 315 return custom;
@@ -341,7 +322,7 @@ public:
341 */ 322 */
342 virtual explicit operator const Type&() const override { 323 virtual explicit operator const Type&() const override {
343 if (use_global) { 324 if (use_global) {
344 return this->global; 325 return this->value;
345 } 326 }
346 return custom; 327 return custom;
347 } 328 }
@@ -352,75 +333,6 @@ protected:
352}; 333};
353 334
354/** 335/**
355 * RangedSetting is a Setting that implements a maximum and minimum value for its setting. Intended
356 * for use with quantifiable settings.
357 */
358template <typename Type>
359class RangedSetting final : public BasicRangedSetting<Type>, public Setting<Type> {
360public:
361 /**
362 * Sets a default value, minimum value, maximum value, and label.
363 *
364 * @param default_val Intial value of the setting, and default value of the setting
365 * @param min_val Sets the minimum allowed value of the setting
366 * @param max_val Sets the maximum allowed value of the setting
367 * @param name Label for the setting
368 */
369 explicit RangedSetting(const Type& default_val, const Type& min_val, const Type& max_val,
370 const std::string& name)
371 : BasicSetting<Type>{default_val, name},
372 BasicRangedSetting<Type>{default_val, min_val, max_val, name}, Setting<Type>{default_val,
373 name} {}
374 virtual ~RangedSetting() = default;
375
376 // The following are needed to avoid a MSVC bug
377 // (source: https://stackoverflow.com/questions/469508)
378 [[nodiscard]] const Type& GetValue() const override {
379 return Setting<Type>::GetValue();
380 }
381 [[nodiscard]] const Type& GetValue(bool need_global) const override {
382 return Setting<Type>::GetValue(need_global);
383 }
384 explicit operator const Type&() const override {
385 if (this->use_global) {
386 return this->global;
387 }
388 return this->custom;
389 }
390
391 /**
392 * Like BasicSetting's SetValue, except value is clamped to the range of the setting. Sets the
393 * appropriate value depending on the global state.
394 *
395 * @param value The desired value
396 */
397 void SetValue(const Type& value) override {
398 const Type temp = std::clamp(value, this->minimum, this->maximum);
399 if (this->use_global) {
400 this->global = temp;
401 }
402 this->custom = temp;
403 }
404
405 /**
406 * Like BasicSetting's assignment overload, except value is clamped to the range of the setting.
407 * Uses the appropriate value depending on the global state.
408 *
409 * @param value The desired value
410 * @returns A reference to the setting's value
411 */
412 const Type& operator=(const Type& value) override {
413 const Type temp = std::clamp(value, this->minimum, this->maximum);
414 if (this->use_global) {
415 this->global = temp;
416 return this->global;
417 }
418 this->custom = temp;
419 return this->custom;
420 }
421};
422
423/**
424 * The InputSetting class allows for getting a reference to either the global or custom members. 336 * The InputSetting class allows for getting a reference to either the global or custom members.
425 * This is required as we cannot easily modify the values of user-defined types within containers 337 * This is required as we cannot easily modify the values of user-defined types within containers
426 * using the SetValue() member function found in the Setting class. The primary purpose of this 338 * using the SetValue() member function found in the Setting class. The primary purpose of this
@@ -431,7 +343,7 @@ template <typename Type>
431class InputSetting final { 343class InputSetting final {
432public: 344public:
433 InputSetting() = default; 345 InputSetting() = default;
434 explicit InputSetting(Type val) : BasicSetting<Type>(val) {} 346 explicit InputSetting(Type val) : Setting<Type>(val) {}
435 ~InputSetting() = default; 347 ~InputSetting() = default;
436 void SetGlobal(bool to_global) { 348 void SetGlobal(bool to_global) {
437 use_global = to_global; 349 use_global = to_global;
@@ -459,175 +371,175 @@ struct TouchFromButtonMap {
459 371
460struct Values { 372struct Values {
461 // Audio 373 // Audio
462 BasicSetting<std::string> audio_device_id{"auto", "output_device"}; 374 Setting<std::string> audio_device_id{"auto", "output_device"};
463 BasicSetting<std::string> sink_id{"auto", "output_engine"}; 375 Setting<std::string> sink_id{"auto", "output_engine"};
464 BasicSetting<bool> audio_muted{false, "audio_muted"}; 376 Setting<bool> audio_muted{false, "audio_muted"};
465 RangedSetting<u8> volume{100, 0, 100, "volume"}; 377 SwitchableSetting<u8> volume{100, 0, 100, "volume"};
466 378
467 // Core 379 // Core
468 Setting<bool> use_multi_core{true, "use_multi_core"}; 380 SwitchableSetting<bool> use_multi_core{true, "use_multi_core"};
469 Setting<bool> use_extended_memory_layout{false, "use_extended_memory_layout"}; 381 SwitchableSetting<bool> use_extended_memory_layout{false, "use_extended_memory_layout"};
470 382
471 // Cpu 383 // Cpu
472 RangedSetting<CPUAccuracy> cpu_accuracy{CPUAccuracy::Auto, CPUAccuracy::Auto, 384 SwitchableSetting<CPUAccuracy> cpu_accuracy{CPUAccuracy::Auto, CPUAccuracy::Auto,
473 CPUAccuracy::Paranoid, "cpu_accuracy"}; 385 CPUAccuracy::Paranoid, "cpu_accuracy"};
474 // TODO: remove cpu_accuracy_first_time, migration setting added 8 July 2021 386 // TODO: remove cpu_accuracy_first_time, migration setting added 8 July 2021
475 BasicSetting<bool> cpu_accuracy_first_time{true, "cpu_accuracy_first_time"}; 387 Setting<bool> cpu_accuracy_first_time{true, "cpu_accuracy_first_time"};
476 BasicSetting<bool> cpu_debug_mode{false, "cpu_debug_mode"}; 388 Setting<bool> cpu_debug_mode{false, "cpu_debug_mode"};
477 389
478 BasicSetting<bool> cpuopt_page_tables{true, "cpuopt_page_tables"}; 390 Setting<bool> cpuopt_page_tables{true, "cpuopt_page_tables"};
479 BasicSetting<bool> cpuopt_block_linking{true, "cpuopt_block_linking"}; 391 Setting<bool> cpuopt_block_linking{true, "cpuopt_block_linking"};
480 BasicSetting<bool> cpuopt_return_stack_buffer{true, "cpuopt_return_stack_buffer"}; 392 Setting<bool> cpuopt_return_stack_buffer{true, "cpuopt_return_stack_buffer"};
481 BasicSetting<bool> cpuopt_fast_dispatcher{true, "cpuopt_fast_dispatcher"}; 393 Setting<bool> cpuopt_fast_dispatcher{true, "cpuopt_fast_dispatcher"};
482 BasicSetting<bool> cpuopt_context_elimination{true, "cpuopt_context_elimination"}; 394 Setting<bool> cpuopt_context_elimination{true, "cpuopt_context_elimination"};
483 BasicSetting<bool> cpuopt_const_prop{true, "cpuopt_const_prop"}; 395 Setting<bool> cpuopt_const_prop{true, "cpuopt_const_prop"};
484 BasicSetting<bool> cpuopt_misc_ir{true, "cpuopt_misc_ir"}; 396 Setting<bool> cpuopt_misc_ir{true, "cpuopt_misc_ir"};
485 BasicSetting<bool> cpuopt_reduce_misalign_checks{true, "cpuopt_reduce_misalign_checks"}; 397 Setting<bool> cpuopt_reduce_misalign_checks{true, "cpuopt_reduce_misalign_checks"};
486 BasicSetting<bool> cpuopt_fastmem{true, "cpuopt_fastmem"}; 398 Setting<bool> cpuopt_fastmem{true, "cpuopt_fastmem"};
487 BasicSetting<bool> cpuopt_fastmem_exclusives{true, "cpuopt_fastmem_exclusives"}; 399 Setting<bool> cpuopt_fastmem_exclusives{true, "cpuopt_fastmem_exclusives"};
488 BasicSetting<bool> cpuopt_recompile_exclusives{true, "cpuopt_recompile_exclusives"}; 400 Setting<bool> cpuopt_recompile_exclusives{true, "cpuopt_recompile_exclusives"};
489 401
490 Setting<bool> cpuopt_unsafe_unfuse_fma{true, "cpuopt_unsafe_unfuse_fma"}; 402 SwitchableSetting<bool> cpuopt_unsafe_unfuse_fma{true, "cpuopt_unsafe_unfuse_fma"};
491 Setting<bool> cpuopt_unsafe_reduce_fp_error{true, "cpuopt_unsafe_reduce_fp_error"}; 403 SwitchableSetting<bool> cpuopt_unsafe_reduce_fp_error{true, "cpuopt_unsafe_reduce_fp_error"};
492 Setting<bool> cpuopt_unsafe_ignore_standard_fpcr{true, "cpuopt_unsafe_ignore_standard_fpcr"}; 404 SwitchableSetting<bool> cpuopt_unsafe_ignore_standard_fpcr{
493 Setting<bool> cpuopt_unsafe_inaccurate_nan{true, "cpuopt_unsafe_inaccurate_nan"}; 405 true, "cpuopt_unsafe_ignore_standard_fpcr"};
494 Setting<bool> cpuopt_unsafe_fastmem_check{true, "cpuopt_unsafe_fastmem_check"}; 406 SwitchableSetting<bool> cpuopt_unsafe_inaccurate_nan{true, "cpuopt_unsafe_inaccurate_nan"};
495 Setting<bool> cpuopt_unsafe_ignore_global_monitor{true, "cpuopt_unsafe_ignore_global_monitor"}; 407 SwitchableSetting<bool> cpuopt_unsafe_fastmem_check{true, "cpuopt_unsafe_fastmem_check"};
408 SwitchableSetting<bool> cpuopt_unsafe_ignore_global_monitor{
409 true, "cpuopt_unsafe_ignore_global_monitor"};
496 410
497 // Renderer 411 // Renderer
498 RangedSetting<RendererBackend> renderer_backend{ 412 SwitchableSetting<RendererBackend> renderer_backend{
499 RendererBackend::Vulkan, RendererBackend::OpenGL, RendererBackend::Vulkan, "backend"}; 413 RendererBackend::Vulkan, RendererBackend::OpenGL, RendererBackend::Vulkan, "backend"};
500 BasicSetting<bool> renderer_debug{false, "debug"}; 414 Setting<bool> renderer_debug{false, "debug"};
501 BasicSetting<bool> renderer_shader_feedback{false, "shader_feedback"}; 415 Setting<bool> renderer_shader_feedback{false, "shader_feedback"};
502 BasicSetting<bool> enable_nsight_aftermath{false, "nsight_aftermath"}; 416 Setting<bool> enable_nsight_aftermath{false, "nsight_aftermath"};
503 BasicSetting<bool> disable_shader_loop_safety_checks{false, 417 Setting<bool> disable_shader_loop_safety_checks{false, "disable_shader_loop_safety_checks"};
504 "disable_shader_loop_safety_checks"}; 418 SwitchableSetting<int> vulkan_device{0, "vulkan_device"};
505 Setting<int> vulkan_device{0, "vulkan_device"};
506 419
507 ResolutionScalingInfo resolution_info{}; 420 ResolutionScalingInfo resolution_info{};
508 Setting<ResolutionSetup> resolution_setup{ResolutionSetup::Res1X, "resolution_setup"}; 421 SwitchableSetting<ResolutionSetup> resolution_setup{ResolutionSetup::Res1X, "resolution_setup"};
509 Setting<ScalingFilter> scaling_filter{ScalingFilter::Bilinear, "scaling_filter"}; 422 SwitchableSetting<ScalingFilter> scaling_filter{ScalingFilter::Bilinear, "scaling_filter"};
510 Setting<AntiAliasing> anti_aliasing{AntiAliasing::None, "anti_aliasing"}; 423 SwitchableSetting<AntiAliasing> anti_aliasing{AntiAliasing::None, "anti_aliasing"};
511 // *nix platforms may have issues with the borderless windowed fullscreen mode. 424 // *nix platforms may have issues with the borderless windowed fullscreen mode.
512 // Default to exclusive fullscreen on these platforms for now. 425 // Default to exclusive fullscreen on these platforms for now.
513 RangedSetting<FullscreenMode> fullscreen_mode{ 426 SwitchableSetting<FullscreenMode> fullscreen_mode{
514#ifdef _WIN32 427#ifdef _WIN32
515 FullscreenMode::Borderless, 428 FullscreenMode::Borderless,
516#else 429#else
517 FullscreenMode::Exclusive, 430 FullscreenMode::Exclusive,
518#endif 431#endif
519 FullscreenMode::Borderless, FullscreenMode::Exclusive, "fullscreen_mode"}; 432 FullscreenMode::Borderless, FullscreenMode::Exclusive, "fullscreen_mode"};
520 RangedSetting<int> aspect_ratio{0, 0, 3, "aspect_ratio"}; 433 SwitchableSetting<int> aspect_ratio{0, 0, 3, "aspect_ratio"};
521 RangedSetting<int> max_anisotropy{0, 0, 5, "max_anisotropy"}; 434 SwitchableSetting<int> max_anisotropy{0, 0, 5, "max_anisotropy"};
522 Setting<bool> use_speed_limit{true, "use_speed_limit"}; 435 SwitchableSetting<bool> use_speed_limit{true, "use_speed_limit"};
523 RangedSetting<u16> speed_limit{100, 0, 9999, "speed_limit"}; 436 SwitchableSetting<u16> speed_limit{100, 0, 9999, "speed_limit"};
524 Setting<bool> use_disk_shader_cache{true, "use_disk_shader_cache"}; 437 SwitchableSetting<bool> use_disk_shader_cache{true, "use_disk_shader_cache"};
525 RangedSetting<GPUAccuracy> gpu_accuracy{GPUAccuracy::High, GPUAccuracy::Normal, 438 SwitchableSetting<GPUAccuracy> gpu_accuracy{GPUAccuracy::High, GPUAccuracy::Normal,
526 GPUAccuracy::Extreme, "gpu_accuracy"}; 439 GPUAccuracy::Extreme, "gpu_accuracy"};
527 Setting<bool> use_asynchronous_gpu_emulation{true, "use_asynchronous_gpu_emulation"}; 440 SwitchableSetting<bool> use_asynchronous_gpu_emulation{true, "use_asynchronous_gpu_emulation"};
528 Setting<NvdecEmulation> nvdec_emulation{NvdecEmulation::GPU, "nvdec_emulation"}; 441 SwitchableSetting<NvdecEmulation> nvdec_emulation{NvdecEmulation::GPU, "nvdec_emulation"};
529 Setting<bool> accelerate_astc{true, "accelerate_astc"}; 442 SwitchableSetting<bool> accelerate_astc{true, "accelerate_astc"};
530 Setting<bool> use_vsync{true, "use_vsync"}; 443 SwitchableSetting<bool> use_vsync{true, "use_vsync"};
531 RangedSetting<u16> fps_cap{1000, 1, 1000, "fps_cap"}; 444 SwitchableSetting<u16> fps_cap{1000, 1, 1000, "fps_cap"};
532 BasicSetting<bool> disable_fps_limit{false, "disable_fps_limit"}; 445 Setting<bool> disable_fps_limit{false, "disable_fps_limit"};
533 RangedSetting<ShaderBackend> shader_backend{ShaderBackend::GLASM, ShaderBackend::GLSL, 446 SwitchableSetting<ShaderBackend> shader_backend{ShaderBackend::GLASM, ShaderBackend::GLSL,
534 ShaderBackend::SPIRV, "shader_backend"}; 447 ShaderBackend::SPIRV, "shader_backend"};
535 Setting<bool> use_asynchronous_shaders{false, "use_asynchronous_shaders"}; 448 SwitchableSetting<bool> use_asynchronous_shaders{false, "use_asynchronous_shaders"};
536 Setting<bool> use_fast_gpu_time{true, "use_fast_gpu_time"}; 449 SwitchableSetting<bool> use_fast_gpu_time{true, "use_fast_gpu_time"};
537 450
538 Setting<u8> bg_red{0, "bg_red"}; 451 SwitchableSetting<u8> bg_red{0, "bg_red"};
539 Setting<u8> bg_green{0, "bg_green"}; 452 SwitchableSetting<u8> bg_green{0, "bg_green"};
540 Setting<u8> bg_blue{0, "bg_blue"}; 453 SwitchableSetting<u8> bg_blue{0, "bg_blue"};
541 454
542 // System 455 // System
543 Setting<std::optional<u32>> rng_seed{std::optional<u32>(), "rng_seed"}; 456 SwitchableSetting<std::optional<u32>> rng_seed{std::optional<u32>(), "rng_seed"};
544 // Measured in seconds since epoch 457 // Measured in seconds since epoch
545 std::optional<s64> custom_rtc; 458 std::optional<s64> custom_rtc;
546 // Set on game boot, reset on stop. Seconds difference between current time and `custom_rtc` 459 // Set on game boot, reset on stop. Seconds difference between current time and `custom_rtc`
547 s64 custom_rtc_differential; 460 s64 custom_rtc_differential;
548 461
549 BasicSetting<s32> current_user{0, "current_user"}; 462 Setting<s32> current_user{0, "current_user"};
550 RangedSetting<s32> language_index{1, 0, 17, "language_index"}; 463 SwitchableSetting<s32> language_index{1, 0, 17, "language_index"};
551 RangedSetting<s32> region_index{1, 0, 6, "region_index"}; 464 SwitchableSetting<s32> region_index{1, 0, 6, "region_index"};
552 RangedSetting<s32> time_zone_index{0, 0, 45, "time_zone_index"}; 465 SwitchableSetting<s32> time_zone_index{0, 0, 45, "time_zone_index"};
553 RangedSetting<s32> sound_index{1, 0, 2, "sound_index"}; 466 SwitchableSetting<s32> sound_index{1, 0, 2, "sound_index"};
554 467
555 // Controls 468 // Controls
556 InputSetting<std::array<PlayerInput, 10>> players; 469 InputSetting<std::array<PlayerInput, 10>> players;
557 470
558 Setting<bool> use_docked_mode{true, "use_docked_mode"}; 471 SwitchableSetting<bool> use_docked_mode{true, "use_docked_mode"};
559 472
560 BasicSetting<bool> enable_raw_input{false, "enable_raw_input"}; 473 Setting<bool> enable_raw_input{false, "enable_raw_input"};
561 BasicSetting<bool> controller_navigation{true, "controller_navigation"}; 474 Setting<bool> controller_navigation{true, "controller_navigation"};
562 475
563 Setting<bool> vibration_enabled{true, "vibration_enabled"}; 476 SwitchableSetting<bool> vibration_enabled{true, "vibration_enabled"};
564 Setting<bool> enable_accurate_vibrations{false, "enable_accurate_vibrations"}; 477 SwitchableSetting<bool> enable_accurate_vibrations{false, "enable_accurate_vibrations"};
565 478
566 Setting<bool> motion_enabled{true, "motion_enabled"}; 479 SwitchableSetting<bool> motion_enabled{true, "motion_enabled"};
567 BasicSetting<std::string> udp_input_servers{"127.0.0.1:26760", "udp_input_servers"}; 480 Setting<std::string> udp_input_servers{"127.0.0.1:26760", "udp_input_servers"};
568 BasicSetting<bool> enable_udp_controller{false, "enable_udp_controller"}; 481 Setting<bool> enable_udp_controller{false, "enable_udp_controller"};
569 482
570 BasicSetting<bool> pause_tas_on_load{true, "pause_tas_on_load"}; 483 Setting<bool> pause_tas_on_load{true, "pause_tas_on_load"};
571 BasicSetting<bool> tas_enable{false, "tas_enable"}; 484 Setting<bool> tas_enable{false, "tas_enable"};
572 BasicSetting<bool> tas_loop{false, "tas_loop"}; 485 Setting<bool> tas_loop{false, "tas_loop"};
573 486
574 BasicSetting<bool> mouse_panning{false, "mouse_panning"}; 487 Setting<bool> mouse_panning{false, "mouse_panning"};
575 BasicRangedSetting<u8> mouse_panning_sensitivity{10, 1, 100, "mouse_panning_sensitivity"}; 488 Setting<u8> mouse_panning_sensitivity{10, 1, 100, "mouse_panning_sensitivity"};
576 BasicSetting<bool> mouse_enabled{false, "mouse_enabled"}; 489 Setting<bool> mouse_enabled{false, "mouse_enabled"};
577 490
578 BasicSetting<bool> emulate_analog_keyboard{false, "emulate_analog_keyboard"}; 491 Setting<bool> emulate_analog_keyboard{false, "emulate_analog_keyboard"};
579 BasicSetting<bool> keyboard_enabled{false, "keyboard_enabled"}; 492 Setting<bool> keyboard_enabled{false, "keyboard_enabled"};
580 493
581 BasicSetting<bool> debug_pad_enabled{false, "debug_pad_enabled"}; 494 Setting<bool> debug_pad_enabled{false, "debug_pad_enabled"};
582 ButtonsRaw debug_pad_buttons; 495 ButtonsRaw debug_pad_buttons;
583 AnalogsRaw debug_pad_analogs; 496 AnalogsRaw debug_pad_analogs;
584 497
585 TouchscreenInput touchscreen; 498 TouchscreenInput touchscreen;
586 499
587 BasicSetting<std::string> touch_device{"min_x:100,min_y:50,max_x:1800,max_y:850", 500 Setting<std::string> touch_device{"min_x:100,min_y:50,max_x:1800,max_y:850", "touch_device"};
588 "touch_device"}; 501 Setting<int> touch_from_button_map_index{0, "touch_from_button_map"};
589 BasicSetting<int> touch_from_button_map_index{0, "touch_from_button_map"};
590 std::vector<TouchFromButtonMap> touch_from_button_maps; 502 std::vector<TouchFromButtonMap> touch_from_button_maps;
591 503
592 BasicSetting<bool> enable_ring_controller{true, "enable_ring_controller"}; 504 Setting<bool> enable_ring_controller{true, "enable_ring_controller"};
593 RingconRaw ringcon_analogs; 505 RingconRaw ringcon_analogs;
594 506
595 // Data Storage 507 // Data Storage
596 BasicSetting<bool> use_virtual_sd{true, "use_virtual_sd"}; 508 Setting<bool> use_virtual_sd{true, "use_virtual_sd"};
597 BasicSetting<bool> gamecard_inserted{false, "gamecard_inserted"}; 509 Setting<bool> gamecard_inserted{false, "gamecard_inserted"};
598 BasicSetting<bool> gamecard_current_game{false, "gamecard_current_game"}; 510 Setting<bool> gamecard_current_game{false, "gamecard_current_game"};
599 BasicSetting<std::string> gamecard_path{std::string(), "gamecard_path"}; 511 Setting<std::string> gamecard_path{std::string(), "gamecard_path"};
600 512
601 // Debugging 513 // Debugging
602 bool record_frame_times; 514 bool record_frame_times;
603 BasicSetting<bool> use_gdbstub{false, "use_gdbstub"}; 515 Setting<bool> use_gdbstub{false, "use_gdbstub"};
604 BasicSetting<u16> gdbstub_port{6543, "gdbstub_port"}; 516 Setting<u16> gdbstub_port{6543, "gdbstub_port"};
605 BasicSetting<std::string> program_args{std::string(), "program_args"}; 517 Setting<std::string> program_args{std::string(), "program_args"};
606 BasicSetting<bool> dump_exefs{false, "dump_exefs"}; 518 Setting<bool> dump_exefs{false, "dump_exefs"};
607 BasicSetting<bool> dump_nso{false, "dump_nso"}; 519 Setting<bool> dump_nso{false, "dump_nso"};
608 BasicSetting<bool> dump_shaders{false, "dump_shaders"}; 520 Setting<bool> dump_shaders{false, "dump_shaders"};
609 BasicSetting<bool> dump_macros{false, "dump_macros"}; 521 Setting<bool> dump_macros{false, "dump_macros"};
610 BasicSetting<bool> enable_fs_access_log{false, "enable_fs_access_log"}; 522 Setting<bool> enable_fs_access_log{false, "enable_fs_access_log"};
611 BasicSetting<bool> reporting_services{false, "reporting_services"}; 523 Setting<bool> reporting_services{false, "reporting_services"};
612 BasicSetting<bool> quest_flag{false, "quest_flag"}; 524 Setting<bool> quest_flag{false, "quest_flag"};
613 BasicSetting<bool> disable_macro_jit{false, "disable_macro_jit"}; 525 Setting<bool> disable_macro_jit{false, "disable_macro_jit"};
614 BasicSetting<bool> extended_logging{false, "extended_logging"}; 526 Setting<bool> extended_logging{false, "extended_logging"};
615 BasicSetting<bool> use_debug_asserts{false, "use_debug_asserts"}; 527 Setting<bool> use_debug_asserts{false, "use_debug_asserts"};
616 BasicSetting<bool> use_auto_stub{false, "use_auto_stub"}; 528 Setting<bool> use_auto_stub{false, "use_auto_stub"};
617 BasicSetting<bool> enable_all_controllers{false, "enable_all_controllers"}; 529 Setting<bool> enable_all_controllers{false, "enable_all_controllers"};
618 530
619 // Miscellaneous 531 // Miscellaneous
620 BasicSetting<std::string> log_filter{"*:Info", "log_filter"}; 532 Setting<std::string> log_filter{"*:Info", "log_filter"};
621 BasicSetting<bool> use_dev_keys{false, "use_dev_keys"}; 533 Setting<bool> use_dev_keys{false, "use_dev_keys"};
622 534
623 // Network 535 // Network
624 BasicSetting<std::string> network_interface{std::string(), "network_interface"}; 536 Setting<std::string> network_interface{std::string(), "network_interface"};
625 537
626 // WebService 538 // WebService
627 BasicSetting<bool> enable_telemetry{true, "enable_telemetry"}; 539 Setting<bool> enable_telemetry{true, "enable_telemetry"};
628 BasicSetting<std::string> web_api_url{"https://api.yuzu-emu.org", "web_api_url"}; 540 Setting<std::string> web_api_url{"https://api.yuzu-emu.org", "web_api_url"};
629 BasicSetting<std::string> yuzu_username{std::string(), "yuzu_username"}; 541 Setting<std::string> yuzu_username{std::string(), "yuzu_username"};
630 BasicSetting<std::string> yuzu_token{std::string(), "yuzu_token"}; 542 Setting<std::string> yuzu_token{std::string(), "yuzu_token"};
631 543
632 // Add-Ons 544 // Add-Ons
633 std::map<u64, std::vector<std::string>> disabled_addons; 545 std::map<u64, std::vector<std::string>> disabled_addons;
diff --git a/src/core/arm/arm_interface.cpp b/src/core/arm/arm_interface.cpp
index 0efc3732f..cef79b245 100644
--- a/src/core/arm/arm_interface.cpp
+++ b/src/core/arm/arm_interface.cpp
@@ -1,6 +1,10 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#ifndef _MSC_VER
5#include <cxxabi.h>
6#endif
7
4#include <map> 8#include <map>
5#include <optional> 9#include <optional>
6#include "common/bit_field.h" 10#include "common/bit_field.h"
@@ -68,8 +72,19 @@ void ARM_Interface::SymbolicateBacktrace(Core::System& system, std::vector<Backt
68 if (symbol_set != symbols.end()) { 72 if (symbol_set != symbols.end()) {
69 const auto symbol = Symbols::GetSymbolName(symbol_set->second, entry.offset); 73 const auto symbol = Symbols::GetSymbolName(symbol_set->second, entry.offset);
70 if (symbol.has_value()) { 74 if (symbol.has_value()) {
75#ifdef _MSC_VER
71 // TODO(DarkLordZach): Add demangling of symbol names. 76 // TODO(DarkLordZach): Add demangling of symbol names.
72 entry.name = *symbol; 77 entry.name = *symbol;
78#else
79 int status{-1};
80 char* demangled{abi::__cxa_demangle(symbol->c_str(), nullptr, nullptr, &status)};
81 if (status == 0 && demangled != nullptr) {
82 entry.name = demangled;
83 std::free(demangled);
84 } else {
85 entry.name = *symbol;
86 }
87#endif
73 } 88 }
74 } 89 }
75 } 90 }
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
index 10cf72a45..1be5fe1c1 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
@@ -427,18 +427,38 @@ void ARM_Dynarmic_32::PageTableChanged(Common::PageTable& page_table,
427} 427}
428 428
429std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_32::GetBacktrace(Core::System& system, 429std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_32::GetBacktrace(Core::System& system,
430 u64 sp, u64 lr) { 430 u64 fp, u64 lr, u64 pc) {
431 // No way to get accurate stack traces in A32 yet 431 std::vector<BacktraceEntry> out;
432 return {}; 432 auto& memory = system.Memory();
433
434 out.push_back({"", 0, pc, 0, ""});
435
436 // fp (= r11) points to the last frame record.
437 // Frame records are two words long:
438 // fp+0 : pointer to previous frame record
439 // fp+4 : value of lr for frame
440 while (true) {
441 out.push_back({"", 0, lr, 0, ""});
442 if (!fp || (fp % 4 != 0) || !memory.IsValidVirtualAddressRange(fp, 8)) {
443 break;
444 }
445 lr = memory.Read32(fp + 4);
446 fp = memory.Read32(fp);
447 }
448
449 SymbolicateBacktrace(system, out);
450
451 return out;
433} 452}
434 453
435std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_32::GetBacktraceFromContext( 454std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_32::GetBacktraceFromContext(
436 System& system, const ThreadContext32& ctx) { 455 System& system, const ThreadContext32& ctx) {
437 return GetBacktrace(system, ctx.cpu_registers[13], ctx.cpu_registers[14]); 456 const auto& reg = ctx.cpu_registers;
457 return GetBacktrace(system, reg[11], reg[14], reg[15]);
438} 458}
439 459
440std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_32::GetBacktrace() const { 460std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_32::GetBacktrace() const {
441 return GetBacktrace(system, GetReg(13), GetReg(14)); 461 return GetBacktrace(system, GetReg(11), GetReg(14), GetReg(15));
442} 462}
443 463
444} // namespace Core 464} // namespace Core
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.h b/src/core/arm/dynarmic/arm_dynarmic_32.h
index fcbe24f0c..346e9abf8 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_32.h
+++ b/src/core/arm/dynarmic/arm_dynarmic_32.h
@@ -78,7 +78,7 @@ protected:
78private: 78private:
79 std::shared_ptr<Dynarmic::A32::Jit> MakeJit(Common::PageTable* page_table) const; 79 std::shared_ptr<Dynarmic::A32::Jit> MakeJit(Common::PageTable* page_table) const;
80 80
81 static std::vector<BacktraceEntry> GetBacktrace(Core::System& system, u64 sp, u64 lr); 81 static std::vector<BacktraceEntry> GetBacktrace(Core::System& system, u64 fp, u64 lr, u64 pc);
82 82
83 using JitCacheKey = std::pair<Common::PageTable*, std::size_t>; 83 using JitCacheKey = std::pair<Common::PageTable*, std::size_t>;
84 using JitCacheType = 84 using JitCacheType =
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
index 92266aa9e..c437f24b8 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
@@ -494,22 +494,22 @@ void ARM_Dynarmic_64::PageTableChanged(Common::PageTable& page_table,
494} 494}
495 495
496std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_64::GetBacktrace(Core::System& system, 496std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_64::GetBacktrace(Core::System& system,
497 u64 fp, u64 lr) { 497 u64 fp, u64 lr, u64 pc) {
498 std::vector<BacktraceEntry> out; 498 std::vector<BacktraceEntry> out;
499 auto& memory = system.Memory(); 499 auto& memory = system.Memory();
500 500
501 // fp (= r29) points to the last frame record. 501 out.push_back({"", 0, pc, 0, ""});
502 // Note that this is the frame record for the *previous* frame, not the current one. 502
503 // Note we need to subtract 4 from our last read to get the proper address 503 // fp (= x29) points to the previous frame record.
504 // Frame records are two words long: 504 // Frame records are two words long:
505 // fp+0 : pointer to previous frame record 505 // fp+0 : pointer to previous frame record
506 // fp+8 : value of lr for frame 506 // fp+8 : value of lr for frame
507 while (true) { 507 while (true) {
508 out.push_back({"", 0, lr, 0, ""}); 508 out.push_back({"", 0, lr, 0, ""});
509 if (!fp) { 509 if (!fp || (fp % 4 != 0) || !memory.IsValidVirtualAddressRange(fp, 16)) {
510 break; 510 break;
511 } 511 }
512 lr = memory.Read64(fp + 8) - 4; 512 lr = memory.Read64(fp + 8);
513 fp = memory.Read64(fp); 513 fp = memory.Read64(fp);
514 } 514 }
515 515
@@ -520,11 +520,12 @@ std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_64::GetBacktrace(Core::S
520 520
521std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_64::GetBacktraceFromContext( 521std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_64::GetBacktraceFromContext(
522 System& system, const ThreadContext64& ctx) { 522 System& system, const ThreadContext64& ctx) {
523 return GetBacktrace(system, ctx.cpu_registers[29], ctx.cpu_registers[30]); 523 const auto& reg = ctx.cpu_registers;
524 return GetBacktrace(system, reg[29], reg[30], ctx.pc);
524} 525}
525 526
526std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_64::GetBacktrace() const { 527std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_64::GetBacktrace() const {
527 return GetBacktrace(system, GetReg(29), GetReg(30)); 528 return GetBacktrace(system, GetReg(29), GetReg(30), GetPC());
528} 529}
529 530
530} // namespace Core 531} // namespace Core
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.h b/src/core/arm/dynarmic/arm_dynarmic_64.h
index 71dbaac5e..c77a83ad7 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_64.h
+++ b/src/core/arm/dynarmic/arm_dynarmic_64.h
@@ -73,7 +73,7 @@ private:
73 std::shared_ptr<Dynarmic::A64::Jit> MakeJit(Common::PageTable* page_table, 73 std::shared_ptr<Dynarmic::A64::Jit> MakeJit(Common::PageTable* page_table,
74 std::size_t address_space_bits) const; 74 std::size_t address_space_bits) const;
75 75
76 static std::vector<BacktraceEntry> GetBacktrace(Core::System& system, u64 fp, u64 lr); 76 static std::vector<BacktraceEntry> GetBacktrace(Core::System& system, u64 fp, u64 lr, u64 pc);
77 77
78 using JitCacheKey = std::pair<Common::PageTable*, std::size_t>; 78 using JitCacheKey = std::pair<Common::PageTable*, std::size_t>;
79 using JitCacheType = 79 using JitCacheType =
diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp
index 9fc78f033..37d3d83b9 100644
--- a/src/core/cpu_manager.cpp
+++ b/src/core/cpu_manager.cpp
@@ -41,51 +41,32 @@ void CpuManager::Shutdown() {
41 } 41 }
42} 42}
43 43
44std::function<void(void*)> CpuManager::GetGuestThreadStartFunc() { 44void CpuManager::GuestThreadFunction() {
45 return GuestThreadFunction; 45 if (is_multicore) {
46} 46 MultiCoreRunGuestThread();
47
48std::function<void(void*)> CpuManager::GetIdleThreadStartFunc() {
49 return IdleThreadFunction;
50}
51
52std::function<void(void*)> CpuManager::GetShutdownThreadStartFunc() {
53 return ShutdownThreadFunction;
54}
55
56void CpuManager::GuestThreadFunction(void* cpu_manager_) {
57 CpuManager* cpu_manager = static_cast<CpuManager*>(cpu_manager_);
58 if (cpu_manager->is_multicore) {
59 cpu_manager->MultiCoreRunGuestThread();
60 } else { 47 } else {
61 cpu_manager->SingleCoreRunGuestThread(); 48 SingleCoreRunGuestThread();
62 } 49 }
63} 50}
64 51
65void CpuManager::GuestRewindFunction(void* cpu_manager_) { 52void CpuManager::GuestRewindFunction() {
66 CpuManager* cpu_manager = static_cast<CpuManager*>(cpu_manager_); 53 if (is_multicore) {
67 if (cpu_manager->is_multicore) { 54 MultiCoreRunGuestLoop();
68 cpu_manager->MultiCoreRunGuestLoop();
69 } else { 55 } else {
70 cpu_manager->SingleCoreRunGuestLoop(); 56 SingleCoreRunGuestLoop();
71 } 57 }
72} 58}
73 59
74void CpuManager::IdleThreadFunction(void* cpu_manager_) { 60void CpuManager::IdleThreadFunction() {
75 CpuManager* cpu_manager = static_cast<CpuManager*>(cpu_manager_); 61 if (is_multicore) {
76 if (cpu_manager->is_multicore) { 62 MultiCoreRunIdleThread();
77 cpu_manager->MultiCoreRunIdleThread();
78 } else { 63 } else {
79 cpu_manager->SingleCoreRunIdleThread(); 64 SingleCoreRunIdleThread();
80 } 65 }
81} 66}
82 67
83void CpuManager::ShutdownThreadFunction(void* cpu_manager) { 68void CpuManager::ShutdownThreadFunction() {
84 static_cast<CpuManager*>(cpu_manager)->ShutdownThread(); 69 ShutdownThread();
85}
86
87void* CpuManager::GetStartFuncParameter() {
88 return this;
89} 70}
90 71
91/////////////////////////////////////////////////////////////////////////////// 72///////////////////////////////////////////////////////////////////////////////
@@ -97,7 +78,7 @@ void CpuManager::MultiCoreRunGuestThread() {
97 kernel.CurrentScheduler()->OnThreadStart(); 78 kernel.CurrentScheduler()->OnThreadStart();
98 auto* thread = kernel.CurrentScheduler()->GetSchedulerCurrentThread(); 79 auto* thread = kernel.CurrentScheduler()->GetSchedulerCurrentThread();
99 auto& host_context = thread->GetHostContext(); 80 auto& host_context = thread->GetHostContext();
100 host_context->SetRewindPoint(GuestRewindFunction, this); 81 host_context->SetRewindPoint([this] { GuestRewindFunction(); });
101 MultiCoreRunGuestLoop(); 82 MultiCoreRunGuestLoop();
102} 83}
103 84
@@ -134,7 +115,7 @@ void CpuManager::SingleCoreRunGuestThread() {
134 kernel.CurrentScheduler()->OnThreadStart(); 115 kernel.CurrentScheduler()->OnThreadStart();
135 auto* thread = kernel.CurrentScheduler()->GetSchedulerCurrentThread(); 116 auto* thread = kernel.CurrentScheduler()->GetSchedulerCurrentThread();
136 auto& host_context = thread->GetHostContext(); 117 auto& host_context = thread->GetHostContext();
137 host_context->SetRewindPoint(GuestRewindFunction, this); 118 host_context->SetRewindPoint([this] { GuestRewindFunction(); });
138 SingleCoreRunGuestLoop(); 119 SingleCoreRunGuestLoop();
139} 120}
140 121
diff --git a/src/core/cpu_manager.h b/src/core/cpu_manager.h
index f0751fc58..76dc58ee1 100644
--- a/src/core/cpu_manager.h
+++ b/src/core/cpu_manager.h
@@ -50,10 +50,15 @@ public:
50 void Initialize(); 50 void Initialize();
51 void Shutdown(); 51 void Shutdown();
52 52
53 static std::function<void(void*)> GetGuestThreadStartFunc(); 53 std::function<void()> GetGuestThreadStartFunc() {
54 static std::function<void(void*)> GetIdleThreadStartFunc(); 54 return [this] { GuestThreadFunction(); };
55 static std::function<void(void*)> GetShutdownThreadStartFunc(); 55 }
56 void* GetStartFuncParameter(); 56 std::function<void()> GetIdleThreadStartFunc() {
57 return [this] { IdleThreadFunction(); };
58 }
59 std::function<void()> GetShutdownThreadStartFunc() {
60 return [this] { ShutdownThreadFunction(); };
61 }
57 62
58 void PreemptSingleCore(bool from_running_enviroment = true); 63 void PreemptSingleCore(bool from_running_enviroment = true);
59 64
@@ -62,10 +67,10 @@ public:
62 } 67 }
63 68
64private: 69private:
65 static void GuestThreadFunction(void* cpu_manager); 70 void GuestThreadFunction();
66 static void GuestRewindFunction(void* cpu_manager); 71 void GuestRewindFunction();
67 static void IdleThreadFunction(void* cpu_manager); 72 void IdleThreadFunction();
68 static void ShutdownThreadFunction(void* cpu_manager); 73 void ShutdownThreadFunction();
69 74
70 void MultiCoreRunGuestThread(); 75 void MultiCoreRunGuestThread();
71 void MultiCoreRunGuestLoop(); 76 void MultiCoreRunGuestLoop();
diff --git a/src/core/debugger/gdbstub_arch.cpp b/src/core/debugger/gdbstub_arch.cpp
index 750c353b9..4bef09bd7 100644
--- a/src/core/debugger/gdbstub_arch.cpp
+++ b/src/core/debugger/gdbstub_arch.cpp
@@ -191,8 +191,10 @@ std::string GDBStubA64::RegRead(const Kernel::KThread* thread, size_t id) const
191 const auto& gprs{context.cpu_registers}; 191 const auto& gprs{context.cpu_registers};
192 const auto& fprs{context.vector_registers}; 192 const auto& fprs{context.vector_registers};
193 193
194 if (id <= SP_REGISTER) { 194 if (id < SP_REGISTER) {
195 return ValueToHex(gprs[id]); 195 return ValueToHex(gprs[id]);
196 } else if (id == SP_REGISTER) {
197 return ValueToHex(context.sp);
196 } else if (id == PC_REGISTER) { 198 } else if (id == PC_REGISTER) {
197 return ValueToHex(context.pc); 199 return ValueToHex(context.pc);
198 } else if (id == PSTATE_REGISTER) { 200 } else if (id == PSTATE_REGISTER) {
@@ -215,8 +217,10 @@ void GDBStubA64::RegWrite(Kernel::KThread* thread, size_t id, std::string_view v
215 217
216 auto& context{thread->GetContext64()}; 218 auto& context{thread->GetContext64()};
217 219
218 if (id <= SP_REGISTER) { 220 if (id < SP_REGISTER) {
219 context.cpu_registers[id] = HexToValue<u64>(value); 221 context.cpu_registers[id] = HexToValue<u64>(value);
222 } else if (id == SP_REGISTER) {
223 context.sp = HexToValue<u64>(value);
220 } else if (id == PC_REGISTER) { 224 } else if (id == PC_REGISTER) {
221 context.pc = HexToValue<u64>(value); 225 context.pc = HexToValue<u64>(value);
222 } else if (id == PSTATE_REGISTER) { 226 } else if (id == PSTATE_REGISTER) {
diff --git a/src/core/hid/hid_types.h b/src/core/hid/hid_types.h
index 9f76f9bcb..e49223016 100644
--- a/src/core/hid/hid_types.h
+++ b/src/core/hid/hid_types.h
@@ -272,6 +272,7 @@ enum class VibrationDeviceType : u32 {
272 Unknown = 0, 272 Unknown = 0,
273 LinearResonantActuator = 1, 273 LinearResonantActuator = 1,
274 GcErm = 2, 274 GcErm = 2,
275 N64 = 3,
275}; 276};
276 277
277// This is nn::hid::VibrationGcErmCommand 278// This is nn::hid::VibrationGcErmCommand
diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp
index 183c693e3..b662788b3 100644
--- a/src/core/hle/kernel/k_process.cpp
+++ b/src/core/hle/kernel/k_process.cpp
@@ -161,7 +161,7 @@ bool KProcess::ReleaseUserException(KThread* thread) {
161 std::addressof(num_waiters), 161 std::addressof(num_waiters),
162 reinterpret_cast<uintptr_t>(std::addressof(exception_thread))); 162 reinterpret_cast<uintptr_t>(std::addressof(exception_thread)));
163 next != nullptr) { 163 next != nullptr) {
164 next->SetState(ThreadState::Runnable); 164 next->EndWait(ResultSuccess);
165 } 165 }
166 166
167 KScheduler::SetSchedulerUpdateNeeded(kernel); 167 KScheduler::SetSchedulerUpdateNeeded(kernel);
diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp
index d586b3f5c..d599d2bcb 100644
--- a/src/core/hle/kernel/k_scheduler.cpp
+++ b/src/core/hle/kernel/k_scheduler.cpp
@@ -622,7 +622,7 @@ void KScheduler::YieldToAnyThread(KernelCore& kernel) {
622} 622}
623 623
624KScheduler::KScheduler(Core::System& system_, s32 core_id_) : system{system_}, core_id{core_id_} { 624KScheduler::KScheduler(Core::System& system_, s32 core_id_) : system{system_}, core_id{core_id_} {
625 switch_fiber = std::make_shared<Common::Fiber>(OnSwitch, this); 625 switch_fiber = std::make_shared<Common::Fiber>([this] { SwitchToCurrent(); });
626 state.needs_scheduling.store(true); 626 state.needs_scheduling.store(true);
627 state.interrupt_task_thread_runnable = false; 627 state.interrupt_task_thread_runnable = false;
628 state.should_count_idle = false; 628 state.should_count_idle = false;
@@ -778,11 +778,6 @@ void KScheduler::ScheduleImpl() {
778 next_scheduler.SwitchContextStep2(); 778 next_scheduler.SwitchContextStep2();
779} 779}
780 780
781void KScheduler::OnSwitch(void* this_scheduler) {
782 KScheduler* sched = static_cast<KScheduler*>(this_scheduler);
783 sched->SwitchToCurrent();
784}
785
786void KScheduler::SwitchToCurrent() { 781void KScheduler::SwitchToCurrent() {
787 while (true) { 782 while (true) {
788 { 783 {
diff --git a/src/core/hle/kernel/k_scheduler.h b/src/core/hle/kernel/k_scheduler.h
index cc3da33f5..6a4760eca 100644
--- a/src/core/hle/kernel/k_scheduler.h
+++ b/src/core/hle/kernel/k_scheduler.h
@@ -170,7 +170,6 @@ private:
170 */ 170 */
171 void UpdateLastContextSwitchTime(KThread* thread, KProcess* process); 171 void UpdateLastContextSwitchTime(KThread* thread, KProcess* process);
172 172
173 static void OnSwitch(void* this_scheduler);
174 void SwitchToCurrent(); 173 void SwitchToCurrent();
175 174
176 KThread* prev_thread{}; 175 KThread* prev_thread{};
diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp
index 8d7faa662..50cb5fc90 100644
--- a/src/core/hle/kernel/k_thread.cpp
+++ b/src/core/hle/kernel/k_thread.cpp
@@ -246,14 +246,12 @@ Result KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_stack
246 246
247Result KThread::InitializeThread(KThread* thread, KThreadFunction func, uintptr_t arg, 247Result KThread::InitializeThread(KThread* thread, KThreadFunction func, uintptr_t arg,
248 VAddr user_stack_top, s32 prio, s32 core, KProcess* owner, 248 VAddr user_stack_top, s32 prio, s32 core, KProcess* owner,
249 ThreadType type, std::function<void(void*)>&& init_func, 249 ThreadType type, std::function<void()>&& init_func) {
250 void* init_func_parameter) {
251 // Initialize the thread. 250 // Initialize the thread.
252 R_TRY(thread->Initialize(func, arg, user_stack_top, prio, core, owner, type)); 251 R_TRY(thread->Initialize(func, arg, user_stack_top, prio, core, owner, type));
253 252
254 // Initialize emulation parameters. 253 // Initialize emulation parameters.
255 thread->host_context = 254 thread->host_context = std::make_shared<Common::Fiber>(std::move(init_func));
256 std::make_shared<Common::Fiber>(std::move(init_func), init_func_parameter);
257 thread->is_single_core = !Settings::values.use_multi_core.GetValue(); 255 thread->is_single_core = !Settings::values.use_multi_core.GetValue();
258 256
259 return ResultSuccess; 257 return ResultSuccess;
@@ -265,15 +263,13 @@ Result KThread::InitializeDummyThread(KThread* thread) {
265 263
266Result KThread::InitializeIdleThread(Core::System& system, KThread* thread, s32 virt_core) { 264Result KThread::InitializeIdleThread(Core::System& system, KThread* thread, s32 virt_core) {
267 return InitializeThread(thread, {}, {}, {}, IdleThreadPriority, virt_core, {}, ThreadType::Main, 265 return InitializeThread(thread, {}, {}, {}, IdleThreadPriority, virt_core, {}, ThreadType::Main,
268 Core::CpuManager::GetIdleThreadStartFunc(), 266 system.GetCpuManager().GetIdleThreadStartFunc());
269 system.GetCpuManager().GetStartFuncParameter());
270} 267}
271 268
272Result KThread::InitializeHighPriorityThread(Core::System& system, KThread* thread, 269Result KThread::InitializeHighPriorityThread(Core::System& system, KThread* thread,
273 KThreadFunction func, uintptr_t arg, s32 virt_core) { 270 KThreadFunction func, uintptr_t arg, s32 virt_core) {
274 return InitializeThread(thread, func, arg, {}, {}, virt_core, nullptr, ThreadType::HighPriority, 271 return InitializeThread(thread, func, arg, {}, {}, virt_core, nullptr, ThreadType::HighPriority,
275 Core::CpuManager::GetShutdownThreadStartFunc(), 272 system.GetCpuManager().GetShutdownThreadStartFunc());
276 system.GetCpuManager().GetStartFuncParameter());
277} 273}
278 274
279Result KThread::InitializeUserThread(Core::System& system, KThread* thread, KThreadFunction func, 275Result KThread::InitializeUserThread(Core::System& system, KThread* thread, KThreadFunction func,
@@ -281,8 +277,7 @@ Result KThread::InitializeUserThread(Core::System& system, KThread* thread, KThr
281 KProcess* owner) { 277 KProcess* owner) {
282 system.Kernel().GlobalSchedulerContext().AddThread(thread); 278 system.Kernel().GlobalSchedulerContext().AddThread(thread);
283 return InitializeThread(thread, func, arg, user_stack_top, prio, virt_core, owner, 279 return InitializeThread(thread, func, arg, user_stack_top, prio, virt_core, owner,
284 ThreadType::User, Core::CpuManager::GetGuestThreadStartFunc(), 280 ThreadType::User, system.GetCpuManager().GetGuestThreadStartFunc());
285 system.GetCpuManager().GetStartFuncParameter());
286} 281}
287 282
288void KThread::PostDestroy(uintptr_t arg) { 283void KThread::PostDestroy(uintptr_t arg) {
@@ -485,9 +480,7 @@ void KThread::Unpin() {
485 480
486 // Resume any threads that began waiting on us while we were pinned. 481 // Resume any threads that began waiting on us while we were pinned.
487 for (auto it = pinned_waiter_list.begin(); it != pinned_waiter_list.end(); ++it) { 482 for (auto it = pinned_waiter_list.begin(); it != pinned_waiter_list.end(); ++it) {
488 if (it->GetState() == ThreadState::Waiting) { 483 it->EndWait(ResultSuccess);
489 it->SetState(ThreadState::Runnable);
490 }
491 } 484 }
492} 485}
493 486
@@ -882,6 +875,7 @@ void KThread::AddWaiterImpl(KThread* thread) {
882 // Keep track of how many kernel waiters we have. 875 // Keep track of how many kernel waiters we have.
883 if (IsKernelAddressKey(thread->GetAddressKey())) { 876 if (IsKernelAddressKey(thread->GetAddressKey())) {
884 ASSERT((num_kernel_waiters++) >= 0); 877 ASSERT((num_kernel_waiters++) >= 0);
878 KScheduler::SetSchedulerUpdateNeeded(kernel);
885 } 879 }
886 880
887 // Insert the waiter. 881 // Insert the waiter.
@@ -895,6 +889,7 @@ void KThread::RemoveWaiterImpl(KThread* thread) {
895 // Keep track of how many kernel waiters we have. 889 // Keep track of how many kernel waiters we have.
896 if (IsKernelAddressKey(thread->GetAddressKey())) { 890 if (IsKernelAddressKey(thread->GetAddressKey())) {
897 ASSERT((num_kernel_waiters--) > 0); 891 ASSERT((num_kernel_waiters--) > 0);
892 KScheduler::SetSchedulerUpdateNeeded(kernel);
898 } 893 }
899 894
900 // Remove the waiter. 895 // Remove the waiter.
@@ -970,6 +965,7 @@ KThread* KThread::RemoveWaiterByKey(s32* out_num_waiters, VAddr key) {
970 // Keep track of how many kernel waiters we have. 965 // Keep track of how many kernel waiters we have.
971 if (IsKernelAddressKey(thread->GetAddressKey())) { 966 if (IsKernelAddressKey(thread->GetAddressKey())) {
972 ASSERT((num_kernel_waiters--) > 0); 967 ASSERT((num_kernel_waiters--) > 0);
968 KScheduler::SetSchedulerUpdateNeeded(kernel);
973 } 969 }
974 it = waiter_list.erase(it); 970 it = waiter_list.erase(it);
975 971
diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h
index 94c4cd1c8..28cd7ecb0 100644
--- a/src/core/hle/kernel/k_thread.h
+++ b/src/core/hle/kernel/k_thread.h
@@ -729,8 +729,7 @@ private:
729 [[nodiscard]] static Result InitializeThread(KThread* thread, KThreadFunction func, 729 [[nodiscard]] static Result InitializeThread(KThread* thread, KThreadFunction func,
730 uintptr_t arg, VAddr user_stack_top, s32 prio, 730 uintptr_t arg, VAddr user_stack_top, s32 prio,
731 s32 core, KProcess* owner, ThreadType type, 731 s32 core, KProcess* owner, ThreadType type,
732 std::function<void(void*)>&& init_func, 732 std::function<void()>&& init_func);
733 void* init_func_parameter);
734 733
735 static void RestorePriority(KernelCore& kernel_ctx, KThread* thread); 734 static void RestorePriority(KernelCore& kernel_ctx, KThread* thread);
736 735
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index c08b0a5dc..aa7189bda 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -49,28 +49,41 @@ bool Controller_NPad::IsNpadIdValid(Core::HID::NpadIdType npad_id) {
49 } 49 }
50} 50}
51 51
52bool Controller_NPad::IsDeviceHandleValid(const Core::HID::VibrationDeviceHandle& device_handle) { 52Result Controller_NPad::IsDeviceHandleValid(const Core::HID::VibrationDeviceHandle& device_handle) {
53 const auto npad_id = IsNpadIdValid(static_cast<Core::HID::NpadIdType>(device_handle.npad_id)); 53 const auto npad_id = IsNpadIdValid(static_cast<Core::HID::NpadIdType>(device_handle.npad_id));
54 const bool npad_type = device_handle.npad_type < Core::HID::NpadStyleIndex::MaxNpadType; 54 const bool npad_type = device_handle.npad_type < Core::HID::NpadStyleIndex::MaxNpadType;
55 const bool device_index = device_handle.device_index < Core::HID::DeviceIndex::MaxDeviceIndex; 55 const bool device_index = device_handle.device_index < Core::HID::DeviceIndex::MaxDeviceIndex;
56 return npad_id && npad_type && device_index; 56
57 if (!npad_type) {
58 return VibrationInvalidStyleIndex;
59 }
60 if (!npad_id) {
61 return VibrationInvalidNpadId;
62 }
63 if (!device_index) {
64 return VibrationDeviceIndexOutOfRange;
65 }
66
67 return ResultSuccess;
57} 68}
58 69
59Result Controller_NPad::VerifyValidSixAxisSensorHandle( 70Result Controller_NPad::VerifyValidSixAxisSensorHandle(
60 const Core::HID::SixAxisSensorHandle& device_handle) { 71 const Core::HID::SixAxisSensorHandle& device_handle) {
61 const auto npad_id = IsNpadIdValid(static_cast<Core::HID::NpadIdType>(device_handle.npad_id)); 72 const auto npad_id = IsNpadIdValid(static_cast<Core::HID::NpadIdType>(device_handle.npad_id));
73 const bool device_index = device_handle.device_index < Core::HID::DeviceIndex::MaxDeviceIndex;
74 const bool npad_type = device_handle.npad_type < Core::HID::NpadStyleIndex::MaxNpadType;
75
62 if (!npad_id) { 76 if (!npad_id) {
63 return InvalidNpadId; 77 return InvalidNpadId;
64 } 78 }
65 const bool device_index = device_handle.device_index < Core::HID::DeviceIndex::MaxDeviceIndex;
66 if (!device_index) { 79 if (!device_index) {
67 return NpadDeviceIndexOutOfRange; 80 return NpadDeviceIndexOutOfRange;
68 } 81 }
69 // This doesn't get validated on nnsdk 82 // This doesn't get validated on nnsdk
70 const bool npad_type = device_handle.npad_type < Core::HID::NpadStyleIndex::MaxNpadType;
71 if (!npad_type) { 83 if (!npad_type) {
72 return NpadInvalidHandle; 84 return NpadInvalidHandle;
73 } 85 }
86
74 return ResultSuccess; 87 return ResultSuccess;
75} 88}
76 89
@@ -705,6 +718,11 @@ Controller_NPad::NpadJoyHoldType Controller_NPad::GetHoldType() const {
705} 718}
706 719
707void Controller_NPad::SetNpadHandheldActivationMode(NpadHandheldActivationMode activation_mode) { 720void Controller_NPad::SetNpadHandheldActivationMode(NpadHandheldActivationMode activation_mode) {
721 if (activation_mode >= NpadHandheldActivationMode::MaxActivationMode) {
722 ASSERT_MSG(false, "Activation mode should be always None, Single or Dual");
723 return;
724 }
725
708 handheld_activation_mode = activation_mode; 726 handheld_activation_mode = activation_mode;
709} 727}
710 728
@@ -840,7 +858,7 @@ bool Controller_NPad::VibrateControllerAtIndex(Core::HID::NpadIdType npad_id,
840void Controller_NPad::VibrateController( 858void Controller_NPad::VibrateController(
841 const Core::HID::VibrationDeviceHandle& vibration_device_handle, 859 const Core::HID::VibrationDeviceHandle& vibration_device_handle,
842 const Core::HID::VibrationValue& vibration_value) { 860 const Core::HID::VibrationValue& vibration_value) {
843 if (!IsDeviceHandleValid(vibration_device_handle)) { 861 if (IsDeviceHandleValid(vibration_device_handle).IsError()) {
844 return; 862 return;
845 } 863 }
846 864
@@ -903,7 +921,7 @@ void Controller_NPad::VibrateControllers(
903 921
904Core::HID::VibrationValue Controller_NPad::GetLastVibration( 922Core::HID::VibrationValue Controller_NPad::GetLastVibration(
905 const Core::HID::VibrationDeviceHandle& vibration_device_handle) const { 923 const Core::HID::VibrationDeviceHandle& vibration_device_handle) const {
906 if (!IsDeviceHandleValid(vibration_device_handle)) { 924 if (IsDeviceHandleValid(vibration_device_handle).IsError()) {
907 return {}; 925 return {};
908 } 926 }
909 927
@@ -914,7 +932,7 @@ Core::HID::VibrationValue Controller_NPad::GetLastVibration(
914 932
915void Controller_NPad::InitializeVibrationDevice( 933void Controller_NPad::InitializeVibrationDevice(
916 const Core::HID::VibrationDeviceHandle& vibration_device_handle) { 934 const Core::HID::VibrationDeviceHandle& vibration_device_handle) {
917 if (!IsDeviceHandleValid(vibration_device_handle)) { 935 if (IsDeviceHandleValid(vibration_device_handle).IsError()) {
918 return; 936 return;
919 } 937 }
920 938
@@ -941,7 +959,7 @@ void Controller_NPad::SetPermitVibrationSession(bool permit_vibration_session) {
941 959
942bool Controller_NPad::IsVibrationDeviceMounted( 960bool Controller_NPad::IsVibrationDeviceMounted(
943 const Core::HID::VibrationDeviceHandle& vibration_device_handle) const { 961 const Core::HID::VibrationDeviceHandle& vibration_device_handle) const {
944 if (!IsDeviceHandleValid(vibration_device_handle)) { 962 if (IsDeviceHandleValid(vibration_device_handle).IsError()) {
945 return false; 963 return false;
946 } 964 }
947 965
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
index 8b54724ed..1a589cca2 100644
--- a/src/core/hle/service/hid/controllers/npad.h
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -81,6 +81,7 @@ public:
81 Dual = 0, 81 Dual = 0,
82 Single = 1, 82 Single = 1,
83 None = 2, 83 None = 2,
84 MaxActivationMode = 3,
84 }; 85 };
85 86
86 // This is nn::hid::NpadCommunicationMode 87 // This is nn::hid::NpadCommunicationMode
@@ -196,7 +197,7 @@ public:
196 Core::HID::NpadButton GetAndResetPressState(); 197 Core::HID::NpadButton GetAndResetPressState();
197 198
198 static bool IsNpadIdValid(Core::HID::NpadIdType npad_id); 199 static bool IsNpadIdValid(Core::HID::NpadIdType npad_id);
199 static bool IsDeviceHandleValid(const Core::HID::VibrationDeviceHandle& device_handle); 200 static Result IsDeviceHandleValid(const Core::HID::VibrationDeviceHandle& device_handle);
200 static Result VerifyValidSixAxisSensorHandle( 201 static Result VerifyValidSixAxisSensorHandle(
201 const Core::HID::SixAxisSensorHandle& device_handle); 202 const Core::HID::SixAxisSensorHandle& device_handle);
202 203
diff --git a/src/core/hle/service/hid/errors.h b/src/core/hle/service/hid/errors.h
index 615c23b84..46282f42e 100644
--- a/src/core/hle/service/hid/errors.h
+++ b/src/core/hle/service/hid/errors.h
@@ -9,6 +9,9 @@ namespace Service::HID {
9 9
10constexpr Result NpadInvalidHandle{ErrorModule::HID, 100}; 10constexpr Result NpadInvalidHandle{ErrorModule::HID, 100};
11constexpr Result NpadDeviceIndexOutOfRange{ErrorModule::HID, 107}; 11constexpr Result NpadDeviceIndexOutOfRange{ErrorModule::HID, 107};
12constexpr Result VibrationInvalidStyleIndex{ErrorModule::HID, 122};
13constexpr Result VibrationInvalidNpadId{ErrorModule::HID, 123};
14constexpr Result VibrationDeviceIndexOutOfRange{ErrorModule::HID, 124};
12constexpr Result InvalidSixAxisFusionRange{ErrorModule::HID, 423}; 15constexpr Result InvalidSixAxisFusionRange{ErrorModule::HID, 423};
13constexpr Result NpadIsDualJoycon{ErrorModule::HID, 601}; 16constexpr Result NpadIsDualJoycon{ErrorModule::HID, 601};
14constexpr Result NpadIsSameType{ErrorModule::HID, 602}; 17constexpr Result NpadIsSameType{ErrorModule::HID, 602};
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index dc5d0366d..78efffc50 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -778,7 +778,7 @@ void Hid::IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) {
778 778
779 bool is_at_rest{}; 779 bool is_at_rest{};
780 auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad); 780 auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
781 const auto result = controller.IsSixAxisSensorAtRest(parameters.sixaxis_handle, is_at_rest); 781 controller.IsSixAxisSensorAtRest(parameters.sixaxis_handle, is_at_rest);
782 782
783 LOG_DEBUG(Service_HID, 783 LOG_DEBUG(Service_HID,
784 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", 784 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
@@ -786,7 +786,7 @@ void Hid::IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) {
786 parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id); 786 parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
787 787
788 IPC::ResponseBuilder rb{ctx, 3}; 788 IPC::ResponseBuilder rb{ctx, 3};
789 rb.Push(result); 789 rb.Push(ResultSuccess);
790 rb.Push(is_at_rest); 790 rb.Push(is_at_rest);
791} 791}
792 792
@@ -803,8 +803,8 @@ void Hid::IsFirmwareUpdateAvailableForSixAxisSensor(Kernel::HLERequestContext& c
803 803
804 bool is_firmware_available{}; 804 bool is_firmware_available{};
805 auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad); 805 auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
806 const auto result = controller.IsFirmwareUpdateAvailableForSixAxisSensor( 806 controller.IsFirmwareUpdateAvailableForSixAxisSensor(parameters.sixaxis_handle,
807 parameters.sixaxis_handle, is_firmware_available); 807 is_firmware_available);
808 808
809 LOG_WARNING( 809 LOG_WARNING(
810 Service_HID, 810 Service_HID,
@@ -813,7 +813,7 @@ void Hid::IsFirmwareUpdateAvailableForSixAxisSensor(Kernel::HLERequestContext& c
813 parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id); 813 parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
814 814
815 IPC::ResponseBuilder rb{ctx, 3}; 815 IPC::ResponseBuilder rb{ctx, 3};
816 rb.Push(result); 816 rb.Push(ResultSuccess);
817 rb.Push(is_firmware_available); 817 rb.Push(is_firmware_available);
818} 818}
819 819
@@ -1083,13 +1083,13 @@ void Hid::DisconnectNpad(Kernel::HLERequestContext& ctx) {
1083 const auto parameters{rp.PopRaw<Parameters>()}; 1083 const auto parameters{rp.PopRaw<Parameters>()};
1084 1084
1085 auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad); 1085 auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
1086 const auto result = controller.DisconnectNpad(parameters.npad_id); 1086 controller.DisconnectNpad(parameters.npad_id);
1087 1087
1088 LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id, 1088 LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id,
1089 parameters.applet_resource_user_id); 1089 parameters.applet_resource_user_id);
1090 1090
1091 IPC::ResponseBuilder rb{ctx, 2}; 1091 IPC::ResponseBuilder rb{ctx, 2};
1092 rb.Push(result); 1092 rb.Push(ResultSuccess);
1093} 1093}
1094 1094
1095void Hid::GetPlayerLedPattern(Kernel::HLERequestContext& ctx) { 1095void Hid::GetPlayerLedPattern(Kernel::HLERequestContext& ctx) {
@@ -1165,15 +1165,14 @@ void Hid::SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx
1165 const auto parameters{rp.PopRaw<Parameters>()}; 1165 const auto parameters{rp.PopRaw<Parameters>()};
1166 1166
1167 auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad); 1167 auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
1168 const auto result = 1168 controller.SetNpadMode(parameters.npad_id, Controller_NPad::NpadJoyDeviceType::Left,
1169 controller.SetNpadMode(parameters.npad_id, Controller_NPad::NpadJoyDeviceType::Left, 1169 Controller_NPad::NpadJoyAssignmentMode::Single);
1170 Controller_NPad::NpadJoyAssignmentMode::Single);
1171 1170
1172 LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id, 1171 LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id,
1173 parameters.applet_resource_user_id); 1172 parameters.applet_resource_user_id);
1174 1173
1175 IPC::ResponseBuilder rb{ctx, 2}; 1174 IPC::ResponseBuilder rb{ctx, 2};
1176 rb.Push(result); 1175 rb.Push(ResultSuccess);
1177} 1176}
1178 1177
1179void Hid::SetNpadJoyAssignmentModeSingle(Kernel::HLERequestContext& ctx) { 1178void Hid::SetNpadJoyAssignmentModeSingle(Kernel::HLERequestContext& ctx) {
@@ -1189,15 +1188,15 @@ void Hid::SetNpadJoyAssignmentModeSingle(Kernel::HLERequestContext& ctx) {
1189 const auto parameters{rp.PopRaw<Parameters>()}; 1188 const auto parameters{rp.PopRaw<Parameters>()};
1190 1189
1191 auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad); 1190 auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
1192 const auto result = controller.SetNpadMode(parameters.npad_id, parameters.npad_joy_device_type, 1191 controller.SetNpadMode(parameters.npad_id, parameters.npad_joy_device_type,
1193 Controller_NPad::NpadJoyAssignmentMode::Single); 1192 Controller_NPad::NpadJoyAssignmentMode::Single);
1194 1193
1195 LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}", 1194 LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}",
1196 parameters.npad_id, parameters.applet_resource_user_id, 1195 parameters.npad_id, parameters.applet_resource_user_id,
1197 parameters.npad_joy_device_type); 1196 parameters.npad_joy_device_type);
1198 1197
1199 IPC::ResponseBuilder rb{ctx, 2}; 1198 IPC::ResponseBuilder rb{ctx, 2};
1200 rb.Push(result); 1199 rb.Push(ResultSuccess);
1201} 1200}
1202 1201
1203void Hid::SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) { 1202void Hid::SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) {
@@ -1212,14 +1211,13 @@ void Hid::SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) {
1212 const auto parameters{rp.PopRaw<Parameters>()}; 1211 const auto parameters{rp.PopRaw<Parameters>()};
1213 1212
1214 auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad); 1213 auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
1215 const auto result = controller.SetNpadMode(parameters.npad_id, {}, 1214 controller.SetNpadMode(parameters.npad_id, {}, Controller_NPad::NpadJoyAssignmentMode::Dual);
1216 Controller_NPad::NpadJoyAssignmentMode::Dual);
1217 1215
1218 LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id, 1216 LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id,
1219 parameters.applet_resource_user_id); 1217 parameters.applet_resource_user_id);
1220 1218
1221 IPC::ResponseBuilder rb{ctx, 2}; 1219 IPC::ResponseBuilder rb{ctx, 2};
1222 rb.Push(result); 1220 rb.Push(ResultSuccess);
1223} 1221}
1224 1222
1225void Hid::MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx) { 1223void Hid::MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx) {
@@ -1412,8 +1410,11 @@ void Hid::ClearNpadCaptureButtonAssignment(Kernel::HLERequestContext& ctx) {
1412void Hid::GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) { 1410void Hid::GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) {
1413 IPC::RequestParser rp{ctx}; 1411 IPC::RequestParser rp{ctx};
1414 const auto vibration_device_handle{rp.PopRaw<Core::HID::VibrationDeviceHandle>()}; 1412 const auto vibration_device_handle{rp.PopRaw<Core::HID::VibrationDeviceHandle>()};
1413 const auto& controller =
1414 GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
1415 1415
1416 Core::HID::VibrationDeviceInfo vibration_device_info; 1416 Core::HID::VibrationDeviceInfo vibration_device_info;
1417 bool check_device_index = false;
1417 1418
1418 switch (vibration_device_handle.npad_type) { 1419 switch (vibration_device_handle.npad_type) {
1419 case Core::HID::NpadStyleIndex::ProController: 1420 case Core::HID::NpadStyleIndex::ProController:
@@ -1421,34 +1422,46 @@ void Hid::GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) {
1421 case Core::HID::NpadStyleIndex::JoyconDual: 1422 case Core::HID::NpadStyleIndex::JoyconDual:
1422 case Core::HID::NpadStyleIndex::JoyconLeft: 1423 case Core::HID::NpadStyleIndex::JoyconLeft:
1423 case Core::HID::NpadStyleIndex::JoyconRight: 1424 case Core::HID::NpadStyleIndex::JoyconRight:
1424 default:
1425 vibration_device_info.type = Core::HID::VibrationDeviceType::LinearResonantActuator; 1425 vibration_device_info.type = Core::HID::VibrationDeviceType::LinearResonantActuator;
1426 check_device_index = true;
1426 break; 1427 break;
1427 case Core::HID::NpadStyleIndex::GameCube: 1428 case Core::HID::NpadStyleIndex::GameCube:
1428 vibration_device_info.type = Core::HID::VibrationDeviceType::GcErm; 1429 vibration_device_info.type = Core::HID::VibrationDeviceType::GcErm;
1429 break; 1430 break;
1430 case Core::HID::NpadStyleIndex::Pokeball: 1431 case Core::HID::NpadStyleIndex::N64:
1432 vibration_device_info.type = Core::HID::VibrationDeviceType::N64;
1433 break;
1434 default:
1431 vibration_device_info.type = Core::HID::VibrationDeviceType::Unknown; 1435 vibration_device_info.type = Core::HID::VibrationDeviceType::Unknown;
1432 break; 1436 break;
1433 } 1437 }
1434 1438
1435 switch (vibration_device_handle.device_index) { 1439 vibration_device_info.position = Core::HID::VibrationDevicePosition::None;
1436 case Core::HID::DeviceIndex::Left: 1440 if (check_device_index) {
1437 vibration_device_info.position = Core::HID::VibrationDevicePosition::Left; 1441 switch (vibration_device_handle.device_index) {
1438 break; 1442 case Core::HID::DeviceIndex::Left:
1439 case Core::HID::DeviceIndex::Right: 1443 vibration_device_info.position = Core::HID::VibrationDevicePosition::Left;
1440 vibration_device_info.position = Core::HID::VibrationDevicePosition::Right; 1444 break;
1441 break; 1445 case Core::HID::DeviceIndex::Right:
1442 case Core::HID::DeviceIndex::None: 1446 vibration_device_info.position = Core::HID::VibrationDevicePosition::Right;
1443 default: 1447 break;
1444 ASSERT_MSG(false, "DeviceIndex should never be None!"); 1448 case Core::HID::DeviceIndex::None:
1445 vibration_device_info.position = Core::HID::VibrationDevicePosition::None; 1449 default:
1446 break; 1450 ASSERT_MSG(false, "DeviceIndex should never be None!");
1451 break;
1452 }
1447 } 1453 }
1448 1454
1449 LOG_DEBUG(Service_HID, "called, vibration_device_type={}, vibration_device_position={}", 1455 LOG_DEBUG(Service_HID, "called, vibration_device_type={}, vibration_device_position={}",
1450 vibration_device_info.type, vibration_device_info.position); 1456 vibration_device_info.type, vibration_device_info.position);
1451 1457
1458 const auto result = controller.IsDeviceHandleValid(vibration_device_handle);
1459 if (result.IsError()) {
1460 IPC::ResponseBuilder rb{ctx, 2};
1461 rb.Push(result);
1462 return;
1463 }
1464
1452 IPC::ResponseBuilder rb{ctx, 4}; 1465 IPC::ResponseBuilder rb{ctx, 4};
1453 rb.Push(ResultSuccess); 1466 rb.Push(ResultSuccess);
1454 rb.PushRaw(vibration_device_info); 1467 rb.PushRaw(vibration_device_info);
diff --git a/src/tests/common/fibers.cpp b/src/tests/common/fibers.cpp
index cfc84d423..4e29f9199 100644
--- a/src/tests/common/fibers.cpp
+++ b/src/tests/common/fibers.cpp
@@ -43,7 +43,15 @@ class TestControl1 {
43public: 43public:
44 TestControl1() = default; 44 TestControl1() = default;
45 45
46 void DoWork(); 46 void DoWork() {
47 const u32 id = thread_ids.Get();
48 u32 value = items[id];
49 for (u32 i = 0; i < id; i++) {
50 value++;
51 }
52 results[id] = value;
53 Fiber::YieldTo(work_fibers[id], *thread_fibers[id]);
54 }
47 55
48 void ExecuteThread(u32 id); 56 void ExecuteThread(u32 id);
49 57
@@ -54,35 +62,16 @@ public:
54 std::vector<u32> results; 62 std::vector<u32> results;
55}; 63};
56 64
57static void WorkControl1(void* control) {
58 auto* test_control = static_cast<TestControl1*>(control);
59 test_control->DoWork();
60}
61
62void TestControl1::DoWork() {
63 const u32 id = thread_ids.Get();
64 u32 value = items[id];
65 for (u32 i = 0; i < id; i++) {
66 value++;
67 }
68 results[id] = value;
69 Fiber::YieldTo(work_fibers[id], *thread_fibers[id]);
70}
71
72void TestControl1::ExecuteThread(u32 id) { 65void TestControl1::ExecuteThread(u32 id) {
73 thread_ids.Register(id); 66 thread_ids.Register(id);
74 auto thread_fiber = Fiber::ThreadToFiber(); 67 auto thread_fiber = Fiber::ThreadToFiber();
75 thread_fibers[id] = thread_fiber; 68 thread_fibers[id] = thread_fiber;
76 work_fibers[id] = std::make_shared<Fiber>(std::function<void(void*)>{WorkControl1}, this); 69 work_fibers[id] = std::make_shared<Fiber>([this] { DoWork(); });
77 items[id] = rand() % 256; 70 items[id] = rand() % 256;
78 Fiber::YieldTo(thread_fibers[id], *work_fibers[id]); 71 Fiber::YieldTo(thread_fibers[id], *work_fibers[id]);
79 thread_fibers[id]->Exit(); 72 thread_fibers[id]->Exit();
80} 73}
81 74
82static void ThreadStart1(u32 id, TestControl1& test_control) {
83 test_control.ExecuteThread(id);
84}
85
86/** This test checks for fiber setup configuration and validates that fibers are 75/** This test checks for fiber setup configuration and validates that fibers are
87 * doing all the work required. 76 * doing all the work required.
88 */ 77 */
@@ -95,7 +84,7 @@ TEST_CASE("Fibers::Setup", "[common]") {
95 test_control.results.resize(num_threads, 0); 84 test_control.results.resize(num_threads, 0);
96 std::vector<std::thread> threads; 85 std::vector<std::thread> threads;
97 for (u32 i = 0; i < num_threads; i++) { 86 for (u32 i = 0; i < num_threads; i++) {
98 threads.emplace_back(ThreadStart1, i, std::ref(test_control)); 87 threads.emplace_back([&test_control, i] { test_control.ExecuteThread(i); });
99 } 88 }
100 for (u32 i = 0; i < num_threads; i++) { 89 for (u32 i = 0; i < num_threads; i++) {
101 threads[i].join(); 90 threads[i].join();
@@ -167,21 +156,6 @@ public:
167 std::shared_ptr<Common::Fiber> fiber3; 156 std::shared_ptr<Common::Fiber> fiber3;
168}; 157};
169 158
170static void WorkControl2_1(void* control) {
171 auto* test_control = static_cast<TestControl2*>(control);
172 test_control->DoWork1();
173}
174
175static void WorkControl2_2(void* control) {
176 auto* test_control = static_cast<TestControl2*>(control);
177 test_control->DoWork2();
178}
179
180static void WorkControl2_3(void* control) {
181 auto* test_control = static_cast<TestControl2*>(control);
182 test_control->DoWork3();
183}
184
185void TestControl2::ExecuteThread(u32 id) { 159void TestControl2::ExecuteThread(u32 id) {
186 thread_ids.Register(id); 160 thread_ids.Register(id);
187 auto thread_fiber = Fiber::ThreadToFiber(); 161 auto thread_fiber = Fiber::ThreadToFiber();
@@ -193,18 +167,6 @@ void TestControl2::Exit() {
193 thread_fibers[id]->Exit(); 167 thread_fibers[id]->Exit();
194} 168}
195 169
196static void ThreadStart2_1(u32 id, TestControl2& test_control) {
197 test_control.ExecuteThread(id);
198 test_control.CallFiber1();
199 test_control.Exit();
200}
201
202static void ThreadStart2_2(u32 id, TestControl2& test_control) {
203 test_control.ExecuteThread(id);
204 test_control.CallFiber2();
205 test_control.Exit();
206}
207
208/** This test checks for fiber thread exchange configuration and validates that fibers are 170/** This test checks for fiber thread exchange configuration and validates that fibers are
209 * that a fiber has been successfully transferred from one thread to another and that the TLS 171 * that a fiber has been successfully transferred from one thread to another and that the TLS
210 * region of the thread is kept while changing fibers. 172 * region of the thread is kept while changing fibers.
@@ -212,14 +174,19 @@ static void ThreadStart2_2(u32 id, TestControl2& test_control) {
212TEST_CASE("Fibers::InterExchange", "[common]") { 174TEST_CASE("Fibers::InterExchange", "[common]") {
213 TestControl2 test_control{}; 175 TestControl2 test_control{};
214 test_control.thread_fibers.resize(2); 176 test_control.thread_fibers.resize(2);
215 test_control.fiber1 = 177 test_control.fiber1 = std::make_shared<Fiber>([&test_control] { test_control.DoWork1(); });
216 std::make_shared<Fiber>(std::function<void(void*)>{WorkControl2_1}, &test_control); 178 test_control.fiber2 = std::make_shared<Fiber>([&test_control] { test_control.DoWork2(); });
217 test_control.fiber2 = 179 test_control.fiber3 = std::make_shared<Fiber>([&test_control] { test_control.DoWork3(); });
218 std::make_shared<Fiber>(std::function<void(void*)>{WorkControl2_2}, &test_control); 180 std::thread thread1{[&test_control] {
219 test_control.fiber3 = 181 test_control.ExecuteThread(0);
220 std::make_shared<Fiber>(std::function<void(void*)>{WorkControl2_3}, &test_control); 182 test_control.CallFiber1();
221 std::thread thread1(ThreadStart2_1, 0, std::ref(test_control)); 183 test_control.Exit();
222 std::thread thread2(ThreadStart2_2, 1, std::ref(test_control)); 184 }};
185 std::thread thread2{[&test_control] {
186 test_control.ExecuteThread(1);
187 test_control.CallFiber2();
188 test_control.Exit();
189 }};
223 thread1.join(); 190 thread1.join();
224 thread2.join(); 191 thread2.join();
225 REQUIRE(test_control.assert1); 192 REQUIRE(test_control.assert1);
@@ -270,16 +237,6 @@ public:
270 std::shared_ptr<Common::Fiber> fiber2; 237 std::shared_ptr<Common::Fiber> fiber2;
271}; 238};
272 239
273static void WorkControl3_1(void* control) {
274 auto* test_control = static_cast<TestControl3*>(control);
275 test_control->DoWork1();
276}
277
278static void WorkControl3_2(void* control) {
279 auto* test_control = static_cast<TestControl3*>(control);
280 test_control->DoWork2();
281}
282
283void TestControl3::ExecuteThread(u32 id) { 240void TestControl3::ExecuteThread(u32 id) {
284 thread_ids.Register(id); 241 thread_ids.Register(id);
285 auto thread_fiber = Fiber::ThreadToFiber(); 242 auto thread_fiber = Fiber::ThreadToFiber();
@@ -291,12 +248,6 @@ void TestControl3::Exit() {
291 thread_fibers[id]->Exit(); 248 thread_fibers[id]->Exit();
292} 249}
293 250
294static void ThreadStart3(u32 id, TestControl3& test_control) {
295 test_control.ExecuteThread(id);
296 test_control.CallFiber1();
297 test_control.Exit();
298}
299
300/** This test checks for one two threads racing for starting the same fiber. 251/** This test checks for one two threads racing for starting the same fiber.
301 * It checks execution occurred in an ordered manner and by no time there were 252 * It checks execution occurred in an ordered manner and by no time there were
302 * two contexts at the same time. 253 * two contexts at the same time.
@@ -304,12 +255,15 @@ static void ThreadStart3(u32 id, TestControl3& test_control) {
304TEST_CASE("Fibers::StartRace", "[common]") { 255TEST_CASE("Fibers::StartRace", "[common]") {
305 TestControl3 test_control{}; 256 TestControl3 test_control{};
306 test_control.thread_fibers.resize(2); 257 test_control.thread_fibers.resize(2);
307 test_control.fiber1 = 258 test_control.fiber1 = std::make_shared<Fiber>([&test_control] { test_control.DoWork1(); });
308 std::make_shared<Fiber>(std::function<void(void*)>{WorkControl3_1}, &test_control); 259 test_control.fiber2 = std::make_shared<Fiber>([&test_control] { test_control.DoWork2(); });
309 test_control.fiber2 = 260 const auto race_function{[&test_control](u32 id) {
310 std::make_shared<Fiber>(std::function<void(void*)>{WorkControl3_2}, &test_control); 261 test_control.ExecuteThread(id);
311 std::thread thread1(ThreadStart3, 0, std::ref(test_control)); 262 test_control.CallFiber1();
312 std::thread thread2(ThreadStart3, 1, std::ref(test_control)); 263 test_control.Exit();
264 }};
265 std::thread thread1([&] { race_function(0); });
266 std::thread thread2([&] { race_function(1); });
313 thread1.join(); 267 thread1.join();
314 thread2.join(); 268 thread2.join();
315 REQUIRE(test_control.value1 == 1); 269 REQUIRE(test_control.value1 == 1);
@@ -319,12 +273,10 @@ TEST_CASE("Fibers::StartRace", "[common]") {
319 273
320class TestControl4; 274class TestControl4;
321 275
322static void WorkControl4(void* control);
323
324class TestControl4 { 276class TestControl4 {
325public: 277public:
326 TestControl4() { 278 TestControl4() {
327 fiber1 = std::make_shared<Fiber>(std::function<void(void*)>{WorkControl4}, this); 279 fiber1 = std::make_shared<Fiber>([this] { DoWork(); });
328 goal_reached = false; 280 goal_reached = false;
329 rewinded = false; 281 rewinded = false;
330 } 282 }
@@ -336,7 +288,7 @@ public:
336 } 288 }
337 289
338 void DoWork() { 290 void DoWork() {
339 fiber1->SetRewindPoint(std::function<void(void*)>{WorkControl4}, this); 291 fiber1->SetRewindPoint([this] { DoWork(); });
340 if (rewinded) { 292 if (rewinded) {
341 goal_reached = true; 293 goal_reached = true;
342 Fiber::YieldTo(fiber1, *thread_fiber); 294 Fiber::YieldTo(fiber1, *thread_fiber);
@@ -351,11 +303,6 @@ public:
351 bool rewinded; 303 bool rewinded;
352}; 304};
353 305
354static void WorkControl4(void* control) {
355 auto* test_control = static_cast<TestControl4*>(control);
356 test_control->DoWork();
357}
358
359TEST_CASE("Fibers::Rewind", "[common]") { 306TEST_CASE("Fibers::Rewind", "[common]") {
360 TestControl4 test_control{}; 307 TestControl4 test_control{};
361 test_control.Execute(); 308 test_control.Execute();
diff --git a/src/yuzu/applets/qt_web_browser.cpp b/src/yuzu/applets/qt_web_browser.cpp
index 283c04cd5..790edbb2a 100644
--- a/src/yuzu/applets/qt_web_browser.cpp
+++ b/src/yuzu/applets/qt_web_browser.cpp
@@ -52,8 +52,8 @@ QtNXWebEngineView::QtNXWebEngineView(QWidget* parent, Core::System& system,
52 : QWebEngineView(parent), input_subsystem{input_subsystem_}, 52 : QWebEngineView(parent), input_subsystem{input_subsystem_},
53 url_interceptor(std::make_unique<UrlRequestInterceptor>()), 53 url_interceptor(std::make_unique<UrlRequestInterceptor>()),
54 input_interpreter(std::make_unique<InputInterpreter>(system)), 54 input_interpreter(std::make_unique<InputInterpreter>(system)),
55 default_profile{QWebEngineProfile::defaultProfile()}, 55 default_profile{QWebEngineProfile::defaultProfile()}, global_settings{
56 global_settings{QWebEngineSettings::globalSettings()} { 56 default_profile->settings()} {
57 default_profile->setPersistentStoragePath(QString::fromStdString(Common::FS::PathToUTF8String( 57 default_profile->setPersistentStoragePath(QString::fromStdString(Common::FS::PathToUTF8String(
58 Common::FS::GetYuzuPath(Common::FS::YuzuPath::YuzuDir) / "qtwebengine"))); 58 Common::FS::GetYuzuPath(Common::FS::YuzuPath::YuzuDir) / "qtwebengine")));
59 59
@@ -78,7 +78,7 @@ QtNXWebEngineView::QtNXWebEngineView(QWidget* parent, Core::System& system,
78 default_profile->scripts()->insert(gamepad); 78 default_profile->scripts()->insert(gamepad);
79 default_profile->scripts()->insert(window_nx); 79 default_profile->scripts()->insert(window_nx);
80 80
81 default_profile->setRequestInterceptor(url_interceptor.get()); 81 default_profile->setUrlRequestInterceptor(url_interceptor.get());
82 82
83 global_settings->setAttribute(QWebEngineSettings::LocalContentCanAccessRemoteUrls, true); 83 global_settings->setAttribute(QWebEngineSettings::LocalContentCanAccessRemoteUrls, true);
84 global_settings->setAttribute(QWebEngineSettings::FullScreenSupportEnabled, true); 84 global_settings->setAttribute(QWebEngineSettings::FullScreenSupportEnabled, true);
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index 9df4752be..9686412d0 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -133,7 +133,7 @@ void Config::Initialize(const std::string& config_name) {
133// Explicit std::string definition: Qt can't implicitly convert a std::string to a QVariant, nor 133// Explicit std::string definition: Qt can't implicitly convert a std::string to a QVariant, nor
134// can it implicitly convert a QVariant back to a {std::,Q}string 134// can it implicitly convert a QVariant back to a {std::,Q}string
135template <> 135template <>
136void Config::ReadBasicSetting(Settings::BasicSetting<std::string>& setting) { 136void Config::ReadBasicSetting(Settings::Setting<std::string>& setting) {
137 const QString name = QString::fromStdString(setting.GetLabel()); 137 const QString name = QString::fromStdString(setting.GetLabel());
138 const auto default_value = QString::fromStdString(setting.GetDefault()); 138 const auto default_value = QString::fromStdString(setting.GetDefault());
139 if (qt_config->value(name + QStringLiteral("/default"), false).toBool()) { 139 if (qt_config->value(name + QStringLiteral("/default"), false).toBool()) {
@@ -144,7 +144,7 @@ void Config::ReadBasicSetting(Settings::BasicSetting<std::string>& setting) {
144} 144}
145 145
146template <typename Type> 146template <typename Type>
147void Config::ReadBasicSetting(Settings::BasicSetting<Type>& setting) { 147void Config::ReadBasicSetting(Settings::Setting<Type>& 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()) {
@@ -157,7 +157,7 @@ void Config::ReadBasicSetting(Settings::BasicSetting<Type>& setting) {
157 157
158// Explicit std::string definition: Qt can't implicitly convert a std::string to a QVariant 158// Explicit std::string definition: Qt can't implicitly convert a std::string to a QVariant
159template <> 159template <>
160void Config::WriteBasicSetting(const Settings::BasicSetting<std::string>& setting) { 160void Config::WriteBasicSetting(const Settings::Setting<std::string>& setting) {
161 const QString name = QString::fromStdString(setting.GetLabel()); 161 const QString name = QString::fromStdString(setting.GetLabel());
162 const std::string& value = setting.GetValue(); 162 const std::string& value = setting.GetValue();
163 qt_config->setValue(name + QStringLiteral("/default"), value == setting.GetDefault()); 163 qt_config->setValue(name + QStringLiteral("/default"), value == setting.GetDefault());
@@ -165,7 +165,7 @@ void Config::WriteBasicSetting(const Settings::BasicSetting<std::string>& settin
165} 165}
166 166
167template <typename Type> 167template <typename Type>
168void Config::WriteBasicSetting(const Settings::BasicSetting<Type>& setting) { 168void Config::WriteBasicSetting(const Settings::Setting<Type>& 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());
@@ -173,7 +173,7 @@ void Config::WriteBasicSetting(const Settings::BasicSetting<Type>& setting) {
173} 173}
174 174
175template <typename Type> 175template <typename Type>
176void Config::WriteGlobalSetting(const Settings::Setting<Type>& setting) { 176void Config::WriteGlobalSetting(const Settings::SwitchableSetting<Type>& 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) {
@@ -1422,7 +1422,7 @@ QVariant Config::ReadSetting(const QString& name, const QVariant& default_value)
1422} 1422}
1423 1423
1424template <typename Type> 1424template <typename Type>
1425void Config::ReadGlobalSetting(Settings::Setting<Type>& setting) { 1425void Config::ReadGlobalSetting(Settings::SwitchableSetting<Type>& setting) {
1426 QString name = QString::fromStdString(setting.GetLabel()); 1426 QString name = QString::fromStdString(setting.GetLabel());
1427 const bool use_global = qt_config->value(name + QStringLiteral("/use_global"), true).toBool(); 1427 const bool use_global = qt_config->value(name + QStringLiteral("/use_global"), true).toBool();
1428 setting.SetGlobal(use_global); 1428 setting.SetGlobal(use_global);
diff --git a/src/yuzu/configuration/config.h b/src/yuzu/configuration/config.h
index f0ab6bdaa..9ca878d23 100644
--- a/src/yuzu/configuration/config.h
+++ b/src/yuzu/configuration/config.h
@@ -160,7 +160,7 @@ private:
160 * @param The setting 160 * @param The setting
161 */ 161 */
162 template <typename Type> 162 template <typename Type>
163 void ReadGlobalSetting(Settings::Setting<Type>& setting); 163 void ReadGlobalSetting(Settings::SwitchableSetting<Type>& 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
@@ -169,7 +169,7 @@ private:
169 * @param The setting 169 * @param The setting
170 */ 170 */
171 template <typename Type> 171 template <typename Type>
172 void WriteGlobalSetting(const Settings::Setting<Type>& setting); 172 void WriteGlobalSetting(const Settings::SwitchableSetting<Type>& 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
@@ -178,14 +178,14 @@ private:
178 * @param The setting 178 * @param The setting
179 */ 179 */
180 template <typename Type> 180 template <typename Type>
181 void ReadBasicSetting(Settings::BasicSetting<Type>& setting); 181 void ReadBasicSetting(Settings::Setting<Type>& 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>
188 void WriteBasicSetting(const Settings::BasicSetting<Type>& setting); 188 void WriteBasicSetting(const Settings::Setting<Type>& 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.cpp b/src/yuzu/configuration/configuration_shared.cpp
index 5190bd18b..dd4959417 100644
--- a/src/yuzu/configuration/configuration_shared.cpp
+++ b/src/yuzu/configuration/configuration_shared.cpp
@@ -9,7 +9,7 @@
9#include "yuzu/configuration/configuration_shared.h" 9#include "yuzu/configuration/configuration_shared.h"
10#include "yuzu/configuration/configure_per_game.h" 10#include "yuzu/configuration/configure_per_game.h"
11 11
12void ConfigurationShared::ApplyPerGameSetting(Settings::Setting<bool>* setting, 12void ConfigurationShared::ApplyPerGameSetting(Settings::SwitchableSetting<bool>* setting,
13 const QCheckBox* checkbox, 13 const QCheckBox* checkbox,
14 const CheckState& tracker) { 14 const CheckState& tracker) {
15 if (Settings::IsConfiguringGlobal() && setting->UsingGlobal()) { 15 if (Settings::IsConfiguringGlobal() && setting->UsingGlobal()) {
@@ -25,7 +25,7 @@ void ConfigurationShared::ApplyPerGameSetting(Settings::Setting<bool>* setting,
25} 25}
26 26
27void ConfigurationShared::SetPerGameSetting(QCheckBox* checkbox, 27void ConfigurationShared::SetPerGameSetting(QCheckBox* checkbox,
28 const Settings::Setting<bool>* setting) { 28 const Settings::SwitchableSetting<bool>* setting) {
29 if (setting->UsingGlobal()) { 29 if (setting->UsingGlobal()) {
30 checkbox->setCheckState(Qt::PartiallyChecked); 30 checkbox->setCheckState(Qt::PartiallyChecked);
31 } else { 31 } else {
@@ -45,7 +45,7 @@ void ConfigurationShared::SetHighlight(QWidget* widget, bool highlighted) {
45} 45}
46 46
47void ConfigurationShared::SetColoredTristate(QCheckBox* checkbox, 47void ConfigurationShared::SetColoredTristate(QCheckBox* checkbox,
48 const Settings::Setting<bool>& setting, 48 const Settings::SwitchableSetting<bool>& setting,
49 CheckState& tracker) { 49 CheckState& tracker) {
50 if (setting.UsingGlobal()) { 50 if (setting.UsingGlobal()) {
51 tracker = CheckState::Global; 51 tracker = CheckState::Global;
diff --git a/src/yuzu/configuration/configuration_shared.h b/src/yuzu/configuration/configuration_shared.h
index 903a9baae..77802a367 100644
--- a/src/yuzu/configuration/configuration_shared.h
+++ b/src/yuzu/configuration/configuration_shared.h
@@ -25,10 +25,10 @@ enum class CheckState {
25// Global-aware apply and set functions 25// Global-aware apply and set functions
26 26
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::Setting<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>
31void ApplyPerGameSetting(Settings::Setting<Type>* setting, const QComboBox* combobox) { 31void ApplyPerGameSetting(Settings::SwitchableSetting<Type>* setting, const QComboBox* combobox) {
32 if (Settings::IsConfiguringGlobal() && setting->UsingGlobal()) { 32 if (Settings::IsConfiguringGlobal() && setting->UsingGlobal()) {
33 setting->SetValue(static_cast<Type>(combobox->currentIndex())); 33 setting->SetValue(static_cast<Type>(combobox->currentIndex()));
34 } else if (!Settings::IsConfiguringGlobal()) { 34 } else if (!Settings::IsConfiguringGlobal()) {
@@ -43,10 +43,10 @@ void ApplyPerGameSetting(Settings::Setting<Type>* setting, const QComboBox* comb
43} 43}
44 44
45// Sets a Qt UI element given a Settings::Setting 45// Sets a Qt UI element given a Settings::Setting
46void SetPerGameSetting(QCheckBox* checkbox, const Settings::Setting<bool>* setting); 46void SetPerGameSetting(QCheckBox* checkbox, const Settings::SwitchableSetting<bool>* setting);
47 47
48template <typename Type> 48template <typename Type>
49void SetPerGameSetting(QComboBox* combobox, const Settings::Setting<Type>* setting) { 49void SetPerGameSetting(QComboBox* combobox, const Settings::SwitchableSetting<Type>* setting) {
50 combobox->setCurrentIndex(setting->UsingGlobal() ? ConfigurationShared::USE_GLOBAL_INDEX 50 combobox->setCurrentIndex(setting->UsingGlobal() ? ConfigurationShared::USE_GLOBAL_INDEX
51 : static_cast<int>(setting->GetValue()) + 51 : static_cast<int>(setting->GetValue()) +
52 ConfigurationShared::USE_GLOBAL_OFFSET); 52 ConfigurationShared::USE_GLOBAL_OFFSET);
@@ -56,7 +56,7 @@ void SetPerGameSetting(QComboBox* combobox, const Settings::Setting<Type>* setti
56void SetHighlight(QWidget* widget, bool highlighted); 56void SetHighlight(QWidget* widget, bool highlighted);
57 57
58// Sets up a QCheckBox like a tristate one, given a Setting 58// Sets up a QCheckBox like a tristate one, given a Setting
59void SetColoredTristate(QCheckBox* checkbox, const Settings::Setting<bool>& setting, 59void SetColoredTristate(QCheckBox* checkbox, const Settings::SwitchableSetting<bool>& setting,
60 CheckState& tracker); 60 CheckState& tracker);
61void SetColoredTristate(QCheckBox* checkbox, bool global, bool state, bool global_state, 61void SetColoredTristate(QCheckBox* checkbox, bool global, bool state, bool global_state,
62 CheckState& tracker); 62 CheckState& tracker);
diff --git a/src/yuzu/uisettings.h b/src/yuzu/uisettings.h
index c64d87ace..044d88ca6 100644
--- a/src/yuzu/uisettings.h
+++ b/src/yuzu/uisettings.h
@@ -64,28 +64,28 @@ struct Values {
64 QByteArray gamelist_header_state; 64 QByteArray gamelist_header_state;
65 65
66 QByteArray microprofile_geometry; 66 QByteArray microprofile_geometry;
67 Settings::BasicSetting<bool> microprofile_visible{false, "microProfileDialogVisible"}; 67 Settings::Setting<bool> microprofile_visible{false, "microProfileDialogVisible"};
68 68
69 Settings::BasicSetting<bool> single_window_mode{true, "singleWindowMode"}; 69 Settings::Setting<bool> single_window_mode{true, "singleWindowMode"};
70 Settings::BasicSetting<bool> fullscreen{false, "fullscreen"}; 70 Settings::Setting<bool> fullscreen{false, "fullscreen"};
71 Settings::BasicSetting<bool> display_titlebar{true, "displayTitleBars"}; 71 Settings::Setting<bool> display_titlebar{true, "displayTitleBars"};
72 Settings::BasicSetting<bool> show_filter_bar{true, "showFilterBar"}; 72 Settings::Setting<bool> show_filter_bar{true, "showFilterBar"};
73 Settings::BasicSetting<bool> show_status_bar{true, "showStatusBar"}; 73 Settings::Setting<bool> show_status_bar{true, "showStatusBar"};
74 74
75 Settings::BasicSetting<bool> confirm_before_closing{true, "confirmClose"}; 75 Settings::Setting<bool> confirm_before_closing{true, "confirmClose"};
76 Settings::BasicSetting<bool> first_start{true, "firstStart"}; 76 Settings::Setting<bool> first_start{true, "firstStart"};
77 Settings::BasicSetting<bool> pause_when_in_background{false, "pauseWhenInBackground"}; 77 Settings::Setting<bool> pause_when_in_background{false, "pauseWhenInBackground"};
78 Settings::BasicSetting<bool> mute_when_in_background{false, "muteWhenInBackground"}; 78 Settings::Setting<bool> mute_when_in_background{false, "muteWhenInBackground"};
79 Settings::BasicSetting<bool> hide_mouse{true, "hideInactiveMouse"}; 79 Settings::Setting<bool> hide_mouse{true, "hideInactiveMouse"};
80 // Set when Vulkan is known to crash the application 80 // Set when Vulkan is known to crash the application
81 Settings::BasicSetting<bool> has_broken_vulkan{false, "has_broken_vulkan"}; 81 Settings::Setting<bool> has_broken_vulkan{false, "has_broken_vulkan"};
82 82
83 Settings::BasicSetting<bool> select_user_on_boot{false, "select_user_on_boot"}; 83 Settings::Setting<bool> select_user_on_boot{false, "select_user_on_boot"};
84 84
85 // Discord RPC 85 // Discord RPC
86 Settings::BasicSetting<bool> enable_discord_presence{true, "enable_discord_presence"}; 86 Settings::Setting<bool> enable_discord_presence{true, "enable_discord_presence"};
87 87
88 Settings::BasicSetting<bool> enable_screenshot_save_as{true, "enable_screenshot_save_as"}; 88 Settings::Setting<bool> enable_screenshot_save_as{true, "enable_screenshot_save_as"};
89 89
90 QString roms_path; 90 QString roms_path;
91 QString symbols_path; 91 QString symbols_path;
@@ -100,25 +100,25 @@ struct Values {
100 // Shortcut name <Shortcut, context> 100 // Shortcut name <Shortcut, context>
101 std::vector<Shortcut> shortcuts; 101 std::vector<Shortcut> shortcuts;
102 102
103 Settings::BasicSetting<uint32_t> callout_flags{0, "calloutFlags"}; 103 Settings::Setting<uint32_t> callout_flags{0, "calloutFlags"};
104 104
105 // logging 105 // logging
106 Settings::BasicSetting<bool> show_console{false, "showConsole"}; 106 Settings::Setting<bool> show_console{false, "showConsole"};
107 107
108 // Game List 108 // Game List
109 Settings::BasicSetting<bool> show_add_ons{true, "show_add_ons"}; 109 Settings::Setting<bool> show_add_ons{true, "show_add_ons"};
110 Settings::BasicSetting<uint32_t> game_icon_size{64, "game_icon_size"}; 110 Settings::Setting<uint32_t> game_icon_size{64, "game_icon_size"};
111 Settings::BasicSetting<uint32_t> folder_icon_size{48, "folder_icon_size"}; 111 Settings::Setting<uint32_t> folder_icon_size{48, "folder_icon_size"};
112 Settings::BasicSetting<uint8_t> row_1_text_id{3, "row_1_text_id"}; 112 Settings::Setting<uint8_t> row_1_text_id{3, "row_1_text_id"};
113 Settings::BasicSetting<uint8_t> row_2_text_id{2, "row_2_text_id"}; 113 Settings::Setting<uint8_t> row_2_text_id{2, "row_2_text_id"};
114 std::atomic_bool is_game_list_reload_pending{false}; 114 std::atomic_bool is_game_list_reload_pending{false};
115 Settings::BasicSetting<bool> cache_game_list{true, "cache_game_list"}; 115 Settings::Setting<bool> cache_game_list{true, "cache_game_list"};
116 Settings::BasicSetting<bool> favorites_expanded{true, "favorites_expanded"}; 116 Settings::Setting<bool> favorites_expanded{true, "favorites_expanded"};
117 QVector<u64> favorited_ids; 117 QVector<u64> favorited_ids;
118 118
119 bool configuration_applied; 119 bool configuration_applied;
120 bool reset_to_defaults; 120 bool reset_to_defaults;
121 Settings::BasicSetting<bool> disable_web_applet{true, "disable_web_applet"}; 121 Settings::Setting<bool> disable_web_applet{true, "disable_web_applet"};
122}; 122};
123 123
124extern Values values; 124extern Values values;
diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp
index fc4744fb0..903e02297 100644
--- a/src/yuzu_cmd/config.cpp
+++ b/src/yuzu_cmd/config.cpp
@@ -90,17 +90,17 @@ static const std::array<std::array<int, 5>, Settings::NativeAnalog::NumAnalogs>
90}}; 90}};
91 91
92template <> 92template <>
93void Config::ReadSetting(const std::string& group, Settings::BasicSetting<std::string>& setting) { 93void Config::ReadSetting(const std::string& group, Settings::Setting<std::string>& setting) {
94 setting = sdl2_config->Get(group, setting.GetLabel(), setting.GetDefault()); 94 setting = sdl2_config->Get(group, setting.GetLabel(), setting.GetDefault());
95} 95}
96 96
97template <> 97template <>
98void Config::ReadSetting(const std::string& group, Settings::BasicSetting<bool>& setting) { 98void Config::ReadSetting(const std::string& group, Settings::Setting<bool>& setting) {
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>
103void Config::ReadSetting(const std::string& group, Settings::BasicSetting<Type>& setting) { 103void Config::ReadSetting(const std::string& group, Settings::Setting<Type>& 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}
diff --git a/src/yuzu_cmd/config.h b/src/yuzu_cmd/config.h
index f61ba23ec..ccf77d668 100644
--- a/src/yuzu_cmd/config.h
+++ b/src/yuzu_cmd/config.h
@@ -28,11 +28,11 @@ public:
28 28
29private: 29private:
30 /** 30 /**
31 * Applies a value read from the sdl2_config to a BasicSetting. 31 * Applies a value read from the sdl2_config to a Setting.
32 * 32 *
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>
37 void ReadSetting(const std::string& group, Settings::BasicSetting<Type>& setting); 37 void ReadSetting(const std::string& group, Settings::Setting<Type>& setting);
38}; 38};