summaryrefslogtreecommitdiff
path: root/src/common
diff options
context:
space:
mode:
Diffstat (limited to 'src/common')
-rw-r--r--src/common/CMakeLists.txt11
-rw-r--r--src/common/alignment.h37
-rw-r--r--src/common/bounded_threadsafe_queue.h4
-rw-r--r--src/common/fs/fs.cpp15
-rw-r--r--src/common/fs/path_util.cpp6
-rw-r--r--src/common/logging/filter.cpp2
-rw-r--r--src/common/logging/types.h2
-rw-r--r--src/common/lz4_compression.cpp6
-rw-r--r--src/common/lz4_compression.h2
-rw-r--r--src/common/polyfill_thread.h20
-rw-r--r--src/common/settings.cpp17
-rw-r--r--src/common/settings.h13
-rw-r--r--src/common/settings_common.cpp3
-rw-r--r--src/common/settings_common.h13
-rw-r--r--src/common/settings_enums.h18
-rw-r--r--src/common/settings_setting.h43
-rw-r--r--src/common/swap.h5
17 files changed, 163 insertions, 54 deletions
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index bf97d9ba2..416203c59 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -26,12 +26,11 @@ add_library(common STATIC
26 assert.h 26 assert.h
27 atomic_helpers.h 27 atomic_helpers.h
28 atomic_ops.h 28 atomic_ops.h
29 detached_tasks.cpp
30 detached_tasks.h
31 bit_cast.h 29 bit_cast.h
32 bit_field.h 30 bit_field.h
33 bit_set.h 31 bit_set.h
34 bit_util.h 32 bit_util.h
33 bounded_threadsafe_queue.h
35 cityhash.cpp 34 cityhash.cpp
36 cityhash.h 35 cityhash.h
37 common_funcs.h 36 common_funcs.h
@@ -41,6 +40,8 @@ add_library(common STATIC
41 container_hash.h 40 container_hash.h
42 demangle.cpp 41 demangle.cpp
43 demangle.h 42 demangle.h
43 detached_tasks.cpp
44 detached_tasks.h
44 div_ceil.h 45 div_ceil.h
45 dynamic_library.cpp 46 dynamic_library.cpp
46 dynamic_library.h 47 dynamic_library.h
@@ -151,6 +152,10 @@ add_library(common STATIC
151 zstd_compression.h 152 zstd_compression.h
152) 153)
153 154
155if (YUZU_ENABLE_PORTABLE)
156 add_compile_definitions(YUZU_ENABLE_PORTABLE)
157endif()
158
154if (WIN32) 159if (WIN32)
155 target_sources(common PRIVATE 160 target_sources(common PRIVATE
156 windows/timer_resolution.cpp 161 windows/timer_resolution.cpp
@@ -191,8 +196,6 @@ if (MSVC)
191 _SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING 196 _SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING
192 ) 197 )
193 target_compile_options(common PRIVATE 198 target_compile_options(common PRIVATE
194 /W4
195
196 /we4242 # 'identifier': conversion from 'type1' to 'type2', possible loss of data 199 /we4242 # 'identifier': conversion from 'type1' to 'type2', possible loss of data
197 /we4254 # 'operator': conversion from 'type1:field_bits' to 'type2:field_bits', possible loss of data 200 /we4254 # 'operator': conversion from 'type1:field_bits' to 'type2:field_bits', possible loss of data
198 /we4800 # Implicit conversion from 'type' to bool. Possible information loss 201 /we4800 # Implicit conversion from 'type' to bool. Possible information loss
diff --git a/src/common/alignment.h b/src/common/alignment.h
index fa715d497..fc5c26898 100644
--- a/src/common/alignment.h
+++ b/src/common/alignment.h
@@ -3,6 +3,7 @@
3 3
4#pragma once 4#pragma once
5 5
6#include <bit>
6#include <cstddef> 7#include <cstddef>
7#include <new> 8#include <new>
8#include <type_traits> 9#include <type_traits>
@@ -10,8 +11,10 @@
10namespace Common { 11namespace Common {
11 12
12template <typename T> 13template <typename T>
13 requires std::is_unsigned_v<T> 14 requires std::is_integral_v<T>
14[[nodiscard]] constexpr T AlignUp(T value, size_t size) { 15[[nodiscard]] constexpr T AlignUp(T value_, size_t size) {
16 using U = typename std::make_unsigned_t<T>;
17 auto value{static_cast<U>(value_)};
15 auto mod{static_cast<T>(value % size)}; 18 auto mod{static_cast<T>(value % size)};
16 value -= mod; 19 value -= mod;
17 return static_cast<T>(mod == T{0} ? value : value + size); 20 return static_cast<T>(mod == T{0} ? value : value + size);
@@ -24,8 +27,10 @@ template <typename T>
24} 27}
25 28
26template <typename T> 29template <typename T>
27 requires std::is_unsigned_v<T> 30 requires std::is_integral_v<T>
28[[nodiscard]] constexpr T AlignDown(T value, size_t size) { 31[[nodiscard]] constexpr T AlignDown(T value_, size_t size) {
32 using U = typename std::make_unsigned_t<T>;
33 const auto value{static_cast<U>(value_)};
29 return static_cast<T>(value - value % size); 34 return static_cast<T>(value - value % size);
30} 35}
31 36
@@ -55,6 +60,30 @@ template <typename T, typename U>
55 return (x + (y - 1)) / y; 60 return (x + (y - 1)) / y;
56} 61}
57 62
63template <typename T>
64 requires std::is_integral_v<T>
65[[nodiscard]] constexpr T LeastSignificantOneBit(T x) {
66 return x & ~(x - 1);
67}
68
69template <typename T>
70 requires std::is_integral_v<T>
71[[nodiscard]] constexpr T ResetLeastSignificantOneBit(T x) {
72 return x & (x - 1);
73}
74
75template <typename T>
76 requires std::is_integral_v<T>
77[[nodiscard]] constexpr bool IsPowerOfTwo(T x) {
78 return x > 0 && ResetLeastSignificantOneBit(x) == 0;
79}
80
81template <typename T>
82 requires std::is_integral_v<T>
83[[nodiscard]] constexpr T FloorPowerOfTwo(T x) {
84 return T{1} << (sizeof(T) * 8 - std::countl_zero(x) - 1);
85}
86
58template <typename T, size_t Align = 16> 87template <typename T, size_t Align = 16>
59class AlignmentAllocator { 88class AlignmentAllocator {
60public: 89public:
diff --git a/src/common/bounded_threadsafe_queue.h b/src/common/bounded_threadsafe_queue.h
index bd87aa09b..b36fc1de9 100644
--- a/src/common/bounded_threadsafe_queue.h
+++ b/src/common/bounded_threadsafe_queue.h
@@ -45,13 +45,13 @@ public:
45 } 45 }
46 46
47 T PopWait() { 47 T PopWait() {
48 T t; 48 T t{};
49 Pop<PopMode::Wait>(t); 49 Pop<PopMode::Wait>(t);
50 return t; 50 return t;
51 } 51 }
52 52
53 T PopWait(std::stop_token stop_token) { 53 T PopWait(std::stop_token stop_token) {
54 T t; 54 T t{};
55 Pop<PopMode::WaitWithStopToken>(t, stop_token); 55 Pop<PopMode::WaitWithStopToken>(t, stop_token);
56 return t; 56 return t;
57 } 57 }
diff --git a/src/common/fs/fs.cpp b/src/common/fs/fs.cpp
index 36e67c145..174aed49b 100644
--- a/src/common/fs/fs.cpp
+++ b/src/common/fs/fs.cpp
@@ -528,38 +528,41 @@ void IterateDirEntriesRecursively(const std::filesystem::path& path,
528// Generic Filesystem Operations 528// Generic Filesystem Operations
529 529
530bool Exists(const fs::path& path) { 530bool Exists(const fs::path& path) {
531 std::error_code ec;
531#ifdef ANDROID 532#ifdef ANDROID
532 if (Android::IsContentUri(path)) { 533 if (Android::IsContentUri(path)) {
533 return Android::Exists(path); 534 return Android::Exists(path);
534 } else { 535 } else {
535 return fs::exists(path); 536 return fs::exists(path, ec);
536 } 537 }
537#else 538#else
538 return fs::exists(path); 539 return fs::exists(path, ec);
539#endif 540#endif
540} 541}
541 542
542bool IsFile(const fs::path& path) { 543bool IsFile(const fs::path& path) {
544 std::error_code ec;
543#ifdef ANDROID 545#ifdef ANDROID
544 if (Android::IsContentUri(path)) { 546 if (Android::IsContentUri(path)) {
545 return !Android::IsDirectory(path); 547 return !Android::IsDirectory(path);
546 } else { 548 } else {
547 return fs::is_regular_file(path); 549 return fs::is_regular_file(path, ec);
548 } 550 }
549#else 551#else
550 return fs::is_regular_file(path); 552 return fs::is_regular_file(path, ec);
551#endif 553#endif
552} 554}
553 555
554bool IsDir(const fs::path& path) { 556bool IsDir(const fs::path& path) {
557 std::error_code ec;
555#ifdef ANDROID 558#ifdef ANDROID
556 if (Android::IsContentUri(path)) { 559 if (Android::IsContentUri(path)) {
557 return Android::IsDirectory(path); 560 return Android::IsDirectory(path);
558 } else { 561 } else {
559 return fs::is_directory(path); 562 return fs::is_directory(path, ec);
560 } 563 }
561#else 564#else
562 return fs::is_directory(path); 565 return fs::is_directory(path, ec);
563#endif 566#endif
564} 567}
565 568
diff --git a/src/common/fs/path_util.cpp b/src/common/fs/path_util.cpp
index d71cfacc6..dce219fcf 100644
--- a/src/common/fs/path_util.cpp
+++ b/src/common/fs/path_util.cpp
@@ -88,8 +88,9 @@ public:
88 fs::path yuzu_path_config; 88 fs::path yuzu_path_config;
89 89
90#ifdef _WIN32 90#ifdef _WIN32
91#ifdef YUZU_ENABLE_PORTABLE
91 yuzu_path = GetExeDirectory() / PORTABLE_DIR; 92 yuzu_path = GetExeDirectory() / PORTABLE_DIR;
92 93#endif
93 if (!IsDir(yuzu_path)) { 94 if (!IsDir(yuzu_path)) {
94 yuzu_path = GetAppDataRoamingDirectory() / YUZU_DIR; 95 yuzu_path = GetAppDataRoamingDirectory() / YUZU_DIR;
95 } 96 }
@@ -101,8 +102,9 @@ public:
101 yuzu_path_cache = yuzu_path / CACHE_DIR; 102 yuzu_path_cache = yuzu_path / CACHE_DIR;
102 yuzu_path_config = yuzu_path / CONFIG_DIR; 103 yuzu_path_config = yuzu_path / CONFIG_DIR;
103#else 104#else
105#ifdef YUZU_ENABLE_PORTABLE
104 yuzu_path = GetCurrentDir() / PORTABLE_DIR; 106 yuzu_path = GetCurrentDir() / PORTABLE_DIR;
105 107#endif
106 if (Exists(yuzu_path) && IsDir(yuzu_path)) { 108 if (Exists(yuzu_path) && IsDir(yuzu_path)) {
107 yuzu_path_cache = yuzu_path / CACHE_DIR; 109 yuzu_path_cache = yuzu_path / CACHE_DIR;
108 yuzu_path_config = yuzu_path / CONFIG_DIR; 110 yuzu_path_config = yuzu_path / CONFIG_DIR;
diff --git a/src/common/logging/filter.cpp b/src/common/logging/filter.cpp
index c95909561..4e3a614a4 100644
--- a/src/common/logging/filter.cpp
+++ b/src/common/logging/filter.cpp
@@ -112,7 +112,7 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) {
112 SUB(Service, NCM) \ 112 SUB(Service, NCM) \
113 SUB(Service, NFC) \ 113 SUB(Service, NFC) \
114 SUB(Service, NFP) \ 114 SUB(Service, NFP) \
115 SUB(Service, NGCT) \ 115 SUB(Service, NGC) \
116 SUB(Service, NIFM) \ 116 SUB(Service, NIFM) \
117 SUB(Service, NIM) \ 117 SUB(Service, NIM) \
118 SUB(Service, NOTIF) \ 118 SUB(Service, NOTIF) \
diff --git a/src/common/logging/types.h b/src/common/logging/types.h
index 8356e3183..08af50ee0 100644
--- a/src/common/logging/types.h
+++ b/src/common/logging/types.h
@@ -80,7 +80,7 @@ enum class Class : u8 {
80 Service_NCM, ///< The NCM service 80 Service_NCM, ///< The NCM service
81 Service_NFC, ///< The NFC (Near-field communication) service 81 Service_NFC, ///< The NFC (Near-field communication) service
82 Service_NFP, ///< The NFP service 82 Service_NFP, ///< The NFP service
83 Service_NGCT, ///< The NGCT (No Good Content for Terra) service 83 Service_NGC, ///< The NGC (No Good Content) service
84 Service_NIFM, ///< The NIFM (Network interface) service 84 Service_NIFM, ///< The NIFM (Network interface) service
85 Service_NIM, ///< The NIM service 85 Service_NIM, ///< The NIM service
86 Service_NOTIF, ///< The NOTIF (Notification) service 86 Service_NOTIF, ///< The NOTIF (Notification) service
diff --git a/src/common/lz4_compression.cpp b/src/common/lz4_compression.cpp
index ffb32fecf..d85ab1742 100644
--- a/src/common/lz4_compression.cpp
+++ b/src/common/lz4_compression.cpp
@@ -71,4 +71,10 @@ std::vector<u8> DecompressDataLZ4(std::span<const u8> compressed, std::size_t un
71 return uncompressed; 71 return uncompressed;
72} 72}
73 73
74int DecompressDataLZ4(void* dst, size_t dst_size, const void* src, size_t src_size) {
75 // This is just a thin wrapper around LZ4.
76 return LZ4_decompress_safe(reinterpret_cast<const char*>(src), reinterpret_cast<char*>(dst),
77 static_cast<int>(src_size), static_cast<int>(dst_size));
78}
79
74} // namespace Common::Compression 80} // namespace Common::Compression
diff --git a/src/common/lz4_compression.h b/src/common/lz4_compression.h
index 7fd53a960..3ae17c2bb 100644
--- a/src/common/lz4_compression.h
+++ b/src/common/lz4_compression.h
@@ -56,4 +56,6 @@ namespace Common::Compression {
56[[nodiscard]] std::vector<u8> DecompressDataLZ4(std::span<const u8> compressed, 56[[nodiscard]] std::vector<u8> DecompressDataLZ4(std::span<const u8> compressed,
57 std::size_t uncompressed_size); 57 std::size_t uncompressed_size);
58 58
59[[nodiscard]] int DecompressDataLZ4(void* dst, size_t dst_size, const void* src, size_t src_size);
60
59} // namespace Common::Compression 61} // namespace Common::Compression
diff --git a/src/common/polyfill_thread.h b/src/common/polyfill_thread.h
index b5ef055db..41cbb9ed5 100644
--- a/src/common/polyfill_thread.h
+++ b/src/common/polyfill_thread.h
@@ -19,8 +19,8 @@
19namespace Common { 19namespace Common {
20 20
21template <typename Condvar, typename Lock, typename Pred> 21template <typename Condvar, typename Lock, typename Pred>
22void CondvarWait(Condvar& cv, Lock& lock, std::stop_token token, Pred&& pred) { 22void CondvarWait(Condvar& cv, std::unique_lock<Lock>& lk, std::stop_token token, Pred&& pred) {
23 cv.wait(lock, token, std::move(pred)); 23 cv.wait(lk, token, std::move(pred));
24} 24}
25 25
26template <typename Rep, typename Period> 26template <typename Rep, typename Period>
@@ -332,13 +332,17 @@ private:
332namespace Common { 332namespace Common {
333 333
334template <typename Condvar, typename Lock, typename Pred> 334template <typename Condvar, typename Lock, typename Pred>
335void CondvarWait(Condvar& cv, Lock& lock, std::stop_token token, Pred pred) { 335void CondvarWait(Condvar& cv, std::unique_lock<Lock>& lk, std::stop_token token, Pred pred) {
336 if (token.stop_requested()) { 336 if (token.stop_requested()) {
337 return; 337 return;
338 } 338 }
339 339
340 std::stop_callback callback(token, [&] { cv.notify_all(); }); 340 std::stop_callback callback(token, [&] {
341 cv.wait(lock, [&] { return pred() || token.stop_requested(); }); 341 { std::scoped_lock lk2{*lk.mutex()}; }
342 cv.notify_all();
343 });
344
345 cv.wait(lk, [&] { return pred() || token.stop_requested(); });
342} 346}
343 347
344template <typename Rep, typename Period> 348template <typename Rep, typename Period>
@@ -353,8 +357,10 @@ bool StoppableTimedWait(std::stop_token token, const std::chrono::duration<Rep,
353 357
354 std::stop_callback cb(token, [&] { 358 std::stop_callback cb(token, [&] {
355 // Wake up the waiting thread. 359 // Wake up the waiting thread.
356 std::unique_lock lk{m}; 360 {
357 stop_requested = true; 361 std::scoped_lock lk{m};
362 stop_requested = true;
363 }
358 cv.notify_one(); 364 cv.notify_one();
359 }); 365 });
360 366
diff --git a/src/common/settings.cpp b/src/common/settings.cpp
index 15fd2e222..4ecaf550b 100644
--- a/src/common/settings.cpp
+++ b/src/common/settings.cpp
@@ -2,6 +2,7 @@
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include <version> 4#include <version>
5#include "common/settings_enums.h"
5#if __cpp_lib_chrono >= 201907L 6#if __cpp_lib_chrono >= 201907L
6#include <chrono> 7#include <chrono>
7#include <exception> 8#include <exception>
@@ -145,6 +146,10 @@ bool IsFastmemEnabled() {
145 return true; 146 return true;
146} 147}
147 148
149bool IsDockedMode() {
150 return values.use_docked_mode.GetValue() == Settings::ConsoleMode::Docked;
151}
152
148float Volume() { 153float Volume() {
149 if (values.audio_muted) { 154 if (values.audio_muted) {
150 return 0.0f; 155 return 0.0f;
@@ -154,6 +159,8 @@ float Volume() {
154 159
155const char* TranslateCategory(Category category) { 160const char* TranslateCategory(Category category) {
156 switch (category) { 161 switch (category) {
162 case Category::Android:
163 return "Android";
157 case Category::Audio: 164 case Category::Audio:
158 return "Audio"; 165 return "Audio";
159 case Category::Core: 166 case Category::Core:
@@ -207,9 +214,7 @@ const char* TranslateCategory(Category category) {
207 return "Miscellaneous"; 214 return "Miscellaneous";
208} 215}
209 216
210void UpdateRescalingInfo() { 217void TranslateResolutionInfo(ResolutionSetup setup, ResolutionScalingInfo& info) {
211 const auto setup = values.resolution_setup.GetValue();
212 auto& info = values.resolution_info;
213 info.downscale = false; 218 info.downscale = false;
214 switch (setup) { 219 switch (setup) {
215 case ResolutionSetup::Res1_2X: 220 case ResolutionSetup::Res1_2X:
@@ -269,6 +274,12 @@ void UpdateRescalingInfo() {
269 info.active = info.up_scale != 1 || info.down_shift != 0; 274 info.active = info.up_scale != 1 || info.down_shift != 0;
270} 275}
271 276
277void UpdateRescalingInfo() {
278 const auto setup = values.resolution_setup.GetValue();
279 auto& info = values.resolution_info;
280 TranslateResolutionInfo(setup, info);
281}
282
272void RestoreGlobalState(bool is_powered_on) { 283void RestoreGlobalState(bool is_powered_on) {
273 // If a game is running, DO NOT restore the global settings state 284 // If a game is running, DO NOT restore the global settings state
274 if (is_powered_on) { 285 if (is_powered_on) {
diff --git a/src/common/settings.h b/src/common/settings.h
index b0bc6519a..82ec9077e 100644
--- a/src/common/settings.h
+++ b/src/common/settings.h
@@ -348,6 +348,8 @@ struct Values {
348 Category::RendererDebug}; 348 Category::RendererDebug};
349 Setting<bool> disable_shader_loop_safety_checks{ 349 Setting<bool> disable_shader_loop_safety_checks{
350 linkage, false, "disable_shader_loop_safety_checks", Category::RendererDebug}; 350 linkage, false, "disable_shader_loop_safety_checks", Category::RendererDebug};
351 Setting<bool> enable_renderdoc_hotkey{linkage, false, "renderdoc_hotkey",
352 Category::RendererDebug};
351 353
352 // System 354 // System
353 SwitchableSetting<Language, true> language_index{linkage, 355 SwitchableSetting<Language, true> language_index{linkage,
@@ -379,7 +381,13 @@ struct Values {
379 381
380 Setting<s32> current_user{linkage, 0, "current_user", Category::System}; 382 Setting<s32> current_user{linkage, 0, "current_user", Category::System};
381 383
382 SwitchableSetting<bool> use_docked_mode{linkage, true, "use_docked_mode", Category::System}; 384 SwitchableSetting<ConsoleMode> use_docked_mode{linkage,
385 ConsoleMode::Docked,
386 "use_docked_mode",
387 Category::System,
388 Specialization::Radio,
389 true,
390 true};
383 391
384 // Controls 392 // Controls
385 InputSetting<std::array<PlayerInput, 10>> players; 393 InputSetting<std::array<PlayerInput, 10>> players;
@@ -519,12 +527,15 @@ bool IsGPULevelHigh();
519 527
520bool IsFastmemEnabled(); 528bool IsFastmemEnabled();
521 529
530bool IsDockedMode();
531
522float Volume(); 532float Volume();
523 533
524std::string GetTimeZoneString(TimeZone time_zone); 534std::string GetTimeZoneString(TimeZone time_zone);
525 535
526void LogSettings(); 536void LogSettings();
527 537
538void TranslateResolutionInfo(ResolutionSetup setup, ResolutionScalingInfo& info);
528void UpdateRescalingInfo(); 539void UpdateRescalingInfo();
529 540
530// Restore the global state of all applicable settings in the Values struct 541// Restore the global state of all applicable settings in the Values struct
diff --git a/src/common/settings_common.cpp b/src/common/settings_common.cpp
index dedf5ef90..5960b78aa 100644
--- a/src/common/settings_common.cpp
+++ b/src/common/settings_common.cpp
@@ -1,7 +1,9 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include <functional>
4#include <string> 5#include <string>
6#include <vector>
5#include "common/settings_common.h" 7#include "common/settings_common.h"
6 8
7namespace Settings { 9namespace Settings {
@@ -12,6 +14,7 @@ BasicSetting::BasicSetting(Linkage& linkage, const std::string& name, enum Categ
12 : label{name}, category{category_}, id{linkage.count}, save{save_}, 14 : label{name}, category{category_}, id{linkage.count}, save{save_},
13 runtime_modifiable{runtime_modifiable_}, specialization{specialization_}, 15 runtime_modifiable{runtime_modifiable_}, specialization{specialization_},
14 other_setting{other_setting_} { 16 other_setting{other_setting_} {
17 linkage.by_key.insert({name, this});
15 linkage.by_category[category].push_back(this); 18 linkage.by_category[category].push_back(this);
16 linkage.count++; 19 linkage.count++;
17} 20}
diff --git a/src/common/settings_common.h b/src/common/settings_common.h
index 2efb329b0..1800ab10d 100644
--- a/src/common/settings_common.h
+++ b/src/common/settings_common.h
@@ -12,6 +12,7 @@
12namespace Settings { 12namespace Settings {
13 13
14enum class Category : u32 { 14enum class Category : u32 {
15 Android,
15 Audio, 16 Audio,
16 Core, 17 Core,
17 Cpu, 18 Cpu,
@@ -56,6 +57,7 @@ enum Specialization : u8 {
56 Scalar = 5, // Values are continuous 57 Scalar = 5, // Values are continuous
57 Countable = 6, // Can be stepped through 58 Countable = 6, // Can be stepped through
58 Paired = 7, // Another setting is associated with this setting 59 Paired = 7, // Another setting is associated with this setting
60 Radio = 8, // Setting should be presented in a radio group
59 61
60 Percentage = (1 << SpecializationAttributeOffset), // Should be represented as a percentage 62 Percentage = (1 << SpecializationAttributeOffset), // Should be represented as a percentage
61}; 63};
@@ -67,6 +69,7 @@ public:
67 explicit Linkage(u32 initial_count = 0); 69 explicit Linkage(u32 initial_count = 0);
68 ~Linkage(); 70 ~Linkage();
69 std::map<Category, std::vector<BasicSetting*>> by_category{}; 71 std::map<Category, std::vector<BasicSetting*>> by_category{};
72 std::map<std::string, Settings::BasicSetting*> by_key{};
70 std::vector<std::function<void()>> restore_functions{}; 73 std::vector<std::function<void()>> restore_functions{};
71 u32 count; 74 u32 count;
72}; 75};
@@ -222,6 +225,16 @@ public:
222 */ 225 */
223 [[nodiscard]] virtual constexpr u32 EnumIndex() const = 0; 226 [[nodiscard]] virtual constexpr u32 EnumIndex() const = 0;
224 227
228 /**
229 * @returns True if the underlying type is a floating point storage
230 */
231 [[nodiscard]] virtual constexpr bool IsFloatingPoint() const = 0;
232
233 /**
234 * @returns True if the underlying type is an integer storage
235 */
236 [[nodiscard]] virtual constexpr bool IsIntegral() const = 0;
237
225 /* 238 /*
226 * Switchable settings 239 * Switchable settings
227 */ 240 */
diff --git a/src/common/settings_enums.h b/src/common/settings_enums.h
index a1a29ebf6..815cafe15 100644
--- a/src/common/settings_enums.h
+++ b/src/common/settings_enums.h
@@ -12,8 +12,8 @@ namespace Settings {
12 12
13template <typename T> 13template <typename T>
14struct EnumMetadata { 14struct EnumMetadata {
15 static constexpr std::vector<std::pair<std::string, T>> Canonicalizations(); 15 static std::vector<std::pair<std::string, T>> Canonicalizations();
16 static constexpr u32 Index(); 16 static u32 Index();
17}; 17};
18 18
19#define PAIR_45(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_46(N, __VA_ARGS__)) 19#define PAIR_45(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_46(N, __VA_ARGS__))
@@ -66,11 +66,11 @@ struct EnumMetadata {
66#define ENUM(NAME, ...) \ 66#define ENUM(NAME, ...) \
67 enum class NAME : u32 { __VA_ARGS__ }; \ 67 enum class NAME : u32 { __VA_ARGS__ }; \
68 template <> \ 68 template <> \
69 constexpr std::vector<std::pair<std::string, NAME>> EnumMetadata<NAME>::Canonicalizations() { \ 69 inline std::vector<std::pair<std::string, NAME>> EnumMetadata<NAME>::Canonicalizations() { \
70 return {PAIR(NAME, __VA_ARGS__)}; \ 70 return {PAIR(NAME, __VA_ARGS__)}; \
71 } \ 71 } \
72 template <> \ 72 template <> \
73 constexpr u32 EnumMetadata<NAME>::Index() { \ 73 inline u32 EnumMetadata<NAME>::Index() { \
74 return __COUNTER__; \ 74 return __COUNTER__; \
75 } 75 }
76 76
@@ -85,7 +85,7 @@ enum class AudioEngine : u32 {
85}; 85};
86 86
87template <> 87template <>
88constexpr std::vector<std::pair<std::string, AudioEngine>> 88inline std::vector<std::pair<std::string, AudioEngine>>
89EnumMetadata<AudioEngine>::Canonicalizations() { 89EnumMetadata<AudioEngine>::Canonicalizations() {
90 return { 90 return {
91 {"auto", AudioEngine::Auto}, 91 {"auto", AudioEngine::Auto},
@@ -96,7 +96,7 @@ EnumMetadata<AudioEngine>::Canonicalizations() {
96} 96}
97 97
98template <> 98template <>
99constexpr u32 EnumMetadata<AudioEngine>::Index() { 99inline u32 EnumMetadata<AudioEngine>::Index() {
100 // This is just a sufficiently large number that is more than the number of other enums declared 100 // This is just a sufficiently large number that is more than the number of other enums declared
101 // here 101 // here
102 return 100; 102 return 100;
@@ -146,8 +146,10 @@ ENUM(AntiAliasing, None, Fxaa, Smaa, MaxEnum);
146 146
147ENUM(AspectRatio, R16_9, R4_3, R21_9, R16_10, Stretch); 147ENUM(AspectRatio, R16_9, R4_3, R21_9, R16_10, Stretch);
148 148
149ENUM(ConsoleMode, Handheld, Docked);
150
149template <typename Type> 151template <typename Type>
150constexpr std::string CanonicalizeEnum(Type id) { 152inline std::string CanonicalizeEnum(Type id) {
151 const auto group = EnumMetadata<Type>::Canonicalizations(); 153 const auto group = EnumMetadata<Type>::Canonicalizations();
152 for (auto& [name, value] : group) { 154 for (auto& [name, value] : group) {
153 if (value == id) { 155 if (value == id) {
@@ -158,7 +160,7 @@ constexpr std::string CanonicalizeEnum(Type id) {
158} 160}
159 161
160template <typename Type> 162template <typename Type>
161constexpr Type ToEnum(const std::string& canonicalization) { 163inline Type ToEnum(const std::string& canonicalization) {
162 const auto group = EnumMetadata<Type>::Canonicalizations(); 164 const auto group = EnumMetadata<Type>::Canonicalizations();
163 for (auto& [name, value] : group) { 165 for (auto& [name, value] : group) {
164 if (name == canonicalization) { 166 if (name == canonicalization) {
diff --git a/src/common/settings_setting.h b/src/common/settings_setting.h
index a8beb06e9..7be6f26f7 100644
--- a/src/common/settings_setting.h
+++ b/src/common/settings_setting.h
@@ -10,6 +10,7 @@
10#include <string> 10#include <string>
11#include <typeindex> 11#include <typeindex>
12#include <typeinfo> 12#include <typeinfo>
13#include <fmt/core.h>
13#include "common/common_types.h" 14#include "common/common_types.h"
14#include "common/settings_common.h" 15#include "common/settings_common.h"
15#include "common/settings_enums.h" 16#include "common/settings_enums.h"
@@ -115,8 +116,12 @@ protected:
115 } else if constexpr (std::is_same_v<Type, AudioEngine>) { 116 } else if constexpr (std::is_same_v<Type, AudioEngine>) {
116 // Compatibility with old AudioEngine setting being a string 117 // Compatibility with old AudioEngine setting being a string
117 return CanonicalizeEnum(value_); 118 return CanonicalizeEnum(value_);
119 } else if constexpr (std::is_floating_point_v<Type>) {
120 return fmt::format("{:f}", value_);
121 } else if constexpr (std::is_enum_v<Type>) {
122 return std::to_string(static_cast<u32>(value_));
118 } else { 123 } else {
119 return std::to_string(static_cast<u64>(value_)); 124 return std::to_string(value_);
120 } 125 }
121 } 126 }
122 127
@@ -180,17 +185,19 @@ public:
180 this->SetValue(static_cast<u32>(std::stoul(input))); 185 this->SetValue(static_cast<u32>(std::stoul(input)));
181 } else if constexpr (std::is_same_v<Type, bool>) { 186 } else if constexpr (std::is_same_v<Type, bool>) {
182 this->SetValue(input == "true"); 187 this->SetValue(input == "true");
183 } else if constexpr (std::is_same_v<Type, AudioEngine>) { 188 } else if constexpr (std::is_same_v<Type, float>) {
184 this->SetValue(ToEnum<Type>(input)); 189 this->SetValue(std::stof(input));
185 } else { 190 } else {
186 this->SetValue(static_cast<Type>(std::stoll(input))); 191 this->SetValue(static_cast<Type>(std::stoll(input)));
187 } 192 }
188 } catch (std::invalid_argument&) { 193 } catch (std::invalid_argument&) {
189 this->SetValue(this->GetDefault()); 194 this->SetValue(this->GetDefault());
195 } catch (std::out_of_range&) {
196 this->SetValue(this->GetDefault());
190 } 197 }
191 } 198 }
192 199
193 [[nodiscard]] std::string constexpr Canonicalize() const override final { 200 [[nodiscard]] std::string Canonicalize() const override final {
194 if constexpr (std::is_enum_v<Type>) { 201 if constexpr (std::is_enum_v<Type>) {
195 return CanonicalizeEnum(this->GetValue()); 202 return CanonicalizeEnum(this->GetValue());
196 } else { 203 } else {
@@ -215,11 +222,27 @@ public:
215 } 222 }
216 } 223 }
217 224
225 [[nodiscard]] constexpr bool IsFloatingPoint() const final {
226 return std::is_floating_point_v<Type>;
227 }
228
229 [[nodiscard]] constexpr bool IsIntegral() const final {
230 return std::is_integral_v<Type>;
231 }
232
218 [[nodiscard]] std::string MinVal() const override final { 233 [[nodiscard]] std::string MinVal() const override final {
219 return this->ToString(minimum); 234 if constexpr (std::is_arithmetic_v<Type> && !ranged) {
235 return this->ToString(std::numeric_limits<Type>::min());
236 } else {
237 return this->ToString(minimum);
238 }
220 } 239 }
221 [[nodiscard]] std::string MaxVal() const override final { 240 [[nodiscard]] std::string MaxVal() const override final {
222 return this->ToString(maximum); 241 if constexpr (std::is_arithmetic_v<Type> && !ranged) {
242 return this->ToString(std::numeric_limits<Type>::max());
243 } else {
244 return this->ToString(maximum);
245 }
223 } 246 }
224 247
225 [[nodiscard]] constexpr bool Ranged() const override { 248 [[nodiscard]] constexpr bool Ranged() const override {
@@ -256,11 +279,11 @@ public:
256 * @param runtime_modifiable_ Suggests whether this is modifiable while a guest is loaded 279 * @param runtime_modifiable_ Suggests whether this is modifiable while a guest is loaded
257 * @param other_setting_ A second Setting to associate to this one in metadata 280 * @param other_setting_ A second Setting to associate to this one in metadata
258 */ 281 */
282 template <typename T = BasicSetting>
259 explicit SwitchableSetting(Linkage& linkage, const Type& default_val, const std::string& name, 283 explicit SwitchableSetting(Linkage& linkage, const Type& default_val, const std::string& name,
260 Category category_, u32 specialization_ = Specialization::Default, 284 Category category_, u32 specialization_ = Specialization::Default,
261 bool save_ = true, bool runtime_modifiable_ = false, 285 bool save_ = true, bool runtime_modifiable_ = false,
262 BasicSetting* other_setting_ = nullptr) 286 typename std::enable_if<!ranged, T*>::type other_setting_ = nullptr)
263 requires(!ranged)
264 : Setting<Type, false>{ 287 : Setting<Type, false>{
265 linkage, default_val, name, category_, specialization_, 288 linkage, default_val, name, category_, specialization_,
266 save_, runtime_modifiable_, other_setting_} { 289 save_, runtime_modifiable_, other_setting_} {
@@ -282,12 +305,12 @@ public:
282 * @param runtime_modifiable_ Suggests whether this is modifiable while a guest is loaded 305 * @param runtime_modifiable_ Suggests whether this is modifiable while a guest is loaded
283 * @param other_setting_ A second Setting to associate to this one in metadata 306 * @param other_setting_ A second Setting to associate to this one in metadata
284 */ 307 */
308 template <typename T = BasicSetting>
285 explicit SwitchableSetting(Linkage& linkage, const Type& default_val, const Type& min_val, 309 explicit SwitchableSetting(Linkage& linkage, const Type& default_val, const Type& min_val,
286 const Type& max_val, const std::string& name, Category category_, 310 const Type& max_val, const std::string& name, Category category_,
287 u32 specialization_ = Specialization::Default, bool save_ = true, 311 u32 specialization_ = Specialization::Default, bool save_ = true,
288 bool runtime_modifiable_ = false, 312 bool runtime_modifiable_ = false,
289 BasicSetting* other_setting_ = nullptr) 313 typename std::enable_if<ranged, T*>::type other_setting_ = nullptr)
290 requires(ranged)
291 : Setting<Type, true>{linkage, default_val, min_val, 314 : Setting<Type, true>{linkage, default_val, min_val,
292 max_val, name, category_, 315 max_val, name, category_,
293 specialization_, save_, runtime_modifiable_, 316 specialization_, save_, runtime_modifiable_,
diff --git a/src/common/swap.h b/src/common/swap.h
index 085baaf9a..fde343e45 100644
--- a/src/common/swap.h
+++ b/src/common/swap.h
@@ -460,11 +460,6 @@ S operator&(const S& i, const swap_struct_t<T, F> v) {
460 return i & v.swap(); 460 return i & v.swap();
461} 461}
462 462
463template <typename S, typename T, typename F>
464S operator&(const swap_struct_t<T, F> v, const S& i) {
465 return static_cast<S>(v.swap() & i);
466}
467
468// Comparison 463// Comparison
469template <typename S, typename T, typename F> 464template <typename S, typename T, typename F>
470bool operator<(const S& p, const swap_struct_t<T, F> v) { 465bool operator<(const S& p, const swap_struct_t<T, F> v) {