diff options
Diffstat (limited to 'src/common')
-rw-r--r-- | src/common/CMakeLists.txt | 19 | ||||
-rw-r--r-- | src/common/arm64/native_clock.cpp | 72 | ||||
-rw-r--r-- | src/common/arm64/native_clock.h | 47 | ||||
-rw-r--r-- | src/common/bounded_threadsafe_queue.h | 4 | ||||
-rw-r--r-- | src/common/common_funcs.h | 4 | ||||
-rw-r--r-- | src/common/elf.h | 8 | ||||
-rw-r--r-- | src/common/fs/fs.cpp | 15 | ||||
-rw-r--r-- | src/common/fs/fs_paths.h | 2 | ||||
-rw-r--r-- | src/common/fs/path_util.cpp | 8 | ||||
-rw-r--r-- | src/common/fs/path_util.h | 2 | ||||
-rw-r--r-- | src/common/logging/filter.cpp | 2 | ||||
-rw-r--r-- | src/common/logging/types.h | 2 | ||||
-rw-r--r-- | src/common/polyfill_thread.h | 39 | ||||
-rw-r--r-- | src/common/settings.cpp | 22 | ||||
-rw-r--r-- | src/common/settings.h | 21 | ||||
-rw-r--r-- | src/common/settings_common.cpp | 1 | ||||
-rw-r--r-- | src/common/settings_common.h | 13 | ||||
-rw-r--r-- | src/common/settings_enums.h | 4 | ||||
-rw-r--r-- | src/common/settings_setting.h | 33 | ||||
-rw-r--r-- | src/common/string_util.cpp | 5 | ||||
-rw-r--r-- | src/common/string_util.h | 1 | ||||
-rw-r--r-- | src/common/swap.h | 5 | ||||
-rw-r--r-- | src/common/wall_clock.cpp | 8 |
23 files changed, 291 insertions, 46 deletions
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index bf97d9ba2..8a1861051 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -26,12 +26,11 @@ add_library(common STATIC assert.h atomic_helpers.h atomic_ops.h - detached_tasks.cpp - detached_tasks.h bit_cast.h bit_field.h bit_set.h bit_util.h + bounded_threadsafe_queue.h cityhash.cpp cityhash.h common_funcs.h @@ -41,6 +40,8 @@ add_library(common STATIC container_hash.h demangle.cpp demangle.h + detached_tasks.cpp + detached_tasks.h div_ceil.h dynamic_library.cpp dynamic_library.h @@ -151,6 +152,10 @@ add_library(common STATIC zstd_compression.h ) +if (YUZU_ENABLE_PORTABLE) + add_compile_definitions(YUZU_ENABLE_PORTABLE) +endif() + if (WIN32) target_sources(common PRIVATE windows/timer_resolution.cpp @@ -184,6 +189,14 @@ if(ARCHITECTURE_x86_64) target_link_libraries(common PRIVATE xbyak::xbyak) endif() +if (ARCHITECTURE_arm64 AND (ANDROID OR LINUX)) + target_sources(common + PRIVATE + arm64/native_clock.cpp + arm64/native_clock.h + ) +endif() + if (MSVC) target_compile_definitions(common PRIVATE # The standard library doesn't provide any replacement for codecvt yet @@ -191,8 +204,6 @@ if (MSVC) _SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING ) target_compile_options(common PRIVATE - /W4 - /we4242 # 'identifier': conversion from 'type1' to 'type2', possible loss of data /we4254 # 'operator': conversion from 'type1:field_bits' to 'type2:field_bits', possible loss of data /we4800 # Implicit conversion from 'type' to bool. Possible information loss diff --git a/src/common/arm64/native_clock.cpp b/src/common/arm64/native_clock.cpp new file mode 100644 index 000000000..88fdba527 --- /dev/null +++ b/src/common/arm64/native_clock.cpp @@ -0,0 +1,72 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/arm64/native_clock.h" + +namespace Common::Arm64 { + +namespace { + +NativeClock::FactorType GetFixedPointFactor(u64 num, u64 den) { + return (static_cast<NativeClock::FactorType>(num) << 64) / den; +} + +u64 MultiplyHigh(u64 m, NativeClock::FactorType factor) { + return static_cast<u64>((m * factor) >> 64); +} + +} // namespace + +NativeClock::NativeClock() { + const u64 host_cntfrq = GetHostCNTFRQ(); + ns_cntfrq_factor = GetFixedPointFactor(NsRatio::den, host_cntfrq); + us_cntfrq_factor = GetFixedPointFactor(UsRatio::den, host_cntfrq); + ms_cntfrq_factor = GetFixedPointFactor(MsRatio::den, host_cntfrq); + guest_cntfrq_factor = GetFixedPointFactor(CNTFRQ, host_cntfrq); + gputick_cntfrq_factor = GetFixedPointFactor(GPUTickFreq, host_cntfrq); +} + +std::chrono::nanoseconds NativeClock::GetTimeNS() const { + return std::chrono::nanoseconds{MultiplyHigh(GetHostTicksElapsed(), ns_cntfrq_factor)}; +} + +std::chrono::microseconds NativeClock::GetTimeUS() const { + return std::chrono::microseconds{MultiplyHigh(GetHostTicksElapsed(), us_cntfrq_factor)}; +} + +std::chrono::milliseconds NativeClock::GetTimeMS() const { + return std::chrono::milliseconds{MultiplyHigh(GetHostTicksElapsed(), ms_cntfrq_factor)}; +} + +u64 NativeClock::GetCNTPCT() const { + return MultiplyHigh(GetHostTicksElapsed(), guest_cntfrq_factor); +} + +u64 NativeClock::GetGPUTick() const { + return MultiplyHigh(GetHostTicksElapsed(), gputick_cntfrq_factor); +} + +u64 NativeClock::GetHostTicksNow() const { + u64 cntvct_el0 = 0; + asm volatile("dsb ish\n\t" + "mrs %[cntvct_el0], cntvct_el0\n\t" + "dsb ish\n\t" + : [cntvct_el0] "=r"(cntvct_el0)); + return cntvct_el0; +} + +u64 NativeClock::GetHostTicksElapsed() const { + return GetHostTicksNow(); +} + +bool NativeClock::IsNative() const { + return true; +} + +u64 NativeClock::GetHostCNTFRQ() { + u64 cntfrq_el0 = 0; + asm("mrs %[cntfrq_el0], cntfrq_el0" : [cntfrq_el0] "=r"(cntfrq_el0)); + return cntfrq_el0; +} + +} // namespace Common::Arm64 diff --git a/src/common/arm64/native_clock.h b/src/common/arm64/native_clock.h new file mode 100644 index 000000000..a28b419f2 --- /dev/null +++ b/src/common/arm64/native_clock.h @@ -0,0 +1,47 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/wall_clock.h" + +namespace Common::Arm64 { + +class NativeClock final : public WallClock { +public: + explicit NativeClock(); + + std::chrono::nanoseconds GetTimeNS() const override; + + std::chrono::microseconds GetTimeUS() const override; + + std::chrono::milliseconds GetTimeMS() const override; + + u64 GetCNTPCT() const override; + + u64 GetGPUTick() const override; + + u64 GetHostTicksNow() const override; + + u64 GetHostTicksElapsed() const override; + + bool IsNative() const override; + + static u64 GetHostCNTFRQ(); + +public: + using FactorType = unsigned __int128; + + FactorType GetGuestCNTFRQFactor() const { + return guest_cntfrq_factor; + } + +private: + FactorType ns_cntfrq_factor; + FactorType us_cntfrq_factor; + FactorType ms_cntfrq_factor; + FactorType guest_cntfrq_factor; + FactorType gputick_cntfrq_factor; +}; + +} // namespace Common::Arm64 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: } T PopWait() { - T t; + T t{}; Pop<PopMode::Wait>(t); return t; } T PopWait(std::stop_token stop_token) { - T t; + T t{}; Pop<PopMode::WaitWithStopToken>(t, stop_token); return t; } diff --git a/src/common/common_funcs.h b/src/common/common_funcs.h index 0dad9338a..47d028d48 100644 --- a/src/common/common_funcs.h +++ b/src/common/common_funcs.h @@ -39,8 +39,12 @@ #define Crash() exit(1) #endif +#define LTO_NOINLINE __attribute__((noinline)) + #else // _MSC_VER +#define LTO_NOINLINE + // Locale Cross-Compatibility #define locale_t _locale_t diff --git a/src/common/elf.h b/src/common/elf.h index 14a5e9597..0b728dc54 100644 --- a/src/common/elf.h +++ b/src/common/elf.h @@ -211,6 +211,11 @@ struct Elf64_Rela { Elf64_Sxword r_addend; /* Addend */ }; +/* RELR relocation table entry */ + +using Elf32_Relr = Elf32_Word; +using Elf64_Relr = Elf64_Xword; + /* How to extract and insert information held in the r_info field. */ static inline u32 Elf32RelSymIndex(Elf32_Word r_info) { @@ -328,6 +333,9 @@ constexpr u32 ElfDtFiniArray = 26; /* Array with addresses of fini fct */ constexpr u32 ElfDtInitArraySz = 27; /* Size in bytes of DT_INIT_ARRAY */ constexpr u32 ElfDtFiniArraySz = 28; /* Size in bytes of DT_FINI_ARRAY */ constexpr u32 ElfDtSymtabShndx = 34; /* Address of SYMTAB_SHNDX section */ +constexpr u32 ElfDtRelrsz = 35; /* Size of RELR relative relocations */ +constexpr u32 ElfDtRelr = 36; /* Address of RELR relative relocations */ +constexpr u32 ElfDtRelrent = 37; /* Size of one RELR relative relocation */ } // namespace ELF } // namespace Common 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, // Generic Filesystem Operations bool Exists(const fs::path& path) { + std::error_code ec; #ifdef ANDROID if (Android::IsContentUri(path)) { return Android::Exists(path); } else { - return fs::exists(path); + return fs::exists(path, ec); } #else - return fs::exists(path); + return fs::exists(path, ec); #endif } bool IsFile(const fs::path& path) { + std::error_code ec; #ifdef ANDROID if (Android::IsContentUri(path)) { return !Android::IsDirectory(path); } else { - return fs::is_regular_file(path); + return fs::is_regular_file(path, ec); } #else - return fs::is_regular_file(path); + return fs::is_regular_file(path, ec); #endif } bool IsDir(const fs::path& path) { + std::error_code ec; #ifdef ANDROID if (Android::IsContentUri(path)) { return Android::IsDirectory(path); } else { - return fs::is_directory(path); + return fs::is_directory(path, ec); } #else - return fs::is_directory(path); + return fs::is_directory(path, ec); #endif } diff --git a/src/common/fs/fs_paths.h b/src/common/fs/fs_paths.h index 61bac9eba..441c8af97 100644 --- a/src/common/fs/fs_paths.h +++ b/src/common/fs/fs_paths.h @@ -18,10 +18,12 @@ #define LOAD_DIR "load" #define LOG_DIR "log" #define NAND_DIR "nand" +#define PLAY_TIME_DIR "play_time" #define SCREENSHOTS_DIR "screenshots" #define SDMC_DIR "sdmc" #define SHADER_DIR "shader" #define TAS_DIR "tas" +#define ICONS_DIR "icons" // yuzu-specific files diff --git a/src/common/fs/path_util.cpp b/src/common/fs/path_util.cpp index d71cfacc6..0abd81a45 100644 --- a/src/common/fs/path_util.cpp +++ b/src/common/fs/path_util.cpp @@ -88,8 +88,9 @@ public: fs::path yuzu_path_config; #ifdef _WIN32 +#ifdef YUZU_ENABLE_PORTABLE yuzu_path = GetExeDirectory() / PORTABLE_DIR; - +#endif if (!IsDir(yuzu_path)) { yuzu_path = GetAppDataRoamingDirectory() / YUZU_DIR; } @@ -101,8 +102,9 @@ public: yuzu_path_cache = yuzu_path / CACHE_DIR; yuzu_path_config = yuzu_path / CONFIG_DIR; #else +#ifdef YUZU_ENABLE_PORTABLE yuzu_path = GetCurrentDir() / PORTABLE_DIR; - +#endif if (Exists(yuzu_path) && IsDir(yuzu_path)) { yuzu_path_cache = yuzu_path / CACHE_DIR; yuzu_path_config = yuzu_path / CONFIG_DIR; @@ -122,10 +124,12 @@ public: GenerateYuzuPath(YuzuPath::LoadDir, yuzu_path / LOAD_DIR); GenerateYuzuPath(YuzuPath::LogDir, yuzu_path / LOG_DIR); GenerateYuzuPath(YuzuPath::NANDDir, yuzu_path / NAND_DIR); + GenerateYuzuPath(YuzuPath::PlayTimeDir, yuzu_path / PLAY_TIME_DIR); GenerateYuzuPath(YuzuPath::ScreenshotsDir, yuzu_path / SCREENSHOTS_DIR); GenerateYuzuPath(YuzuPath::SDMCDir, yuzu_path / SDMC_DIR); GenerateYuzuPath(YuzuPath::ShaderDir, yuzu_path / SHADER_DIR); GenerateYuzuPath(YuzuPath::TASDir, yuzu_path / TAS_DIR); + GenerateYuzuPath(YuzuPath::IconsDir, yuzu_path / ICONS_DIR); } private: diff --git a/src/common/fs/path_util.h b/src/common/fs/path_util.h index ba28964d0..63801c924 100644 --- a/src/common/fs/path_util.h +++ b/src/common/fs/path_util.h @@ -20,10 +20,12 @@ enum class YuzuPath { LoadDir, // Where cheat/mod files are stored. LogDir, // Where log files are stored. NANDDir, // Where the emulated NAND is stored. + PlayTimeDir, // Where play time data is stored. ScreenshotsDir, // Where yuzu screenshots are stored. SDMCDir, // Where the emulated SDMC is stored. ShaderDir, // Where shaders are stored. TASDir, // Where TAS scripts are stored. + IconsDir, // Where Icons for Windows shortcuts are stored. }; /** 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) { SUB(Service, NCM) \ SUB(Service, NFC) \ SUB(Service, NFP) \ - SUB(Service, NGCT) \ + SUB(Service, NGC) \ SUB(Service, NIFM) \ SUB(Service, NIM) \ 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 { Service_NCM, ///< The NCM service Service_NFC, ///< The NFC (Near-field communication) service Service_NFP, ///< The NFP service - Service_NGCT, ///< The NGCT (No Good Content for Terra) service + Service_NGC, ///< The NGC (No Good Content) service Service_NIFM, ///< The NIFM (Network interface) service Service_NIM, ///< The NIM service Service_NOTIF, ///< The NOTIF (Notification) service diff --git a/src/common/polyfill_thread.h b/src/common/polyfill_thread.h index b5ef055db..12e59a893 100644 --- a/src/common/polyfill_thread.h +++ b/src/common/polyfill_thread.h @@ -15,12 +15,13 @@ #include <condition_variable> #include <stop_token> #include <thread> +#include <utility> namespace Common { template <typename Condvar, typename Lock, typename Pred> -void CondvarWait(Condvar& cv, Lock& lock, std::stop_token token, Pred&& pred) { - cv.wait(lock, token, std::move(pred)); +void CondvarWait(Condvar& cv, std::unique_lock<Lock>& lk, std::stop_token token, Pred&& pred) { + cv.wait(lk, token, std::forward<Pred>(pred)); } template <typename Rep, typename Period> @@ -109,7 +110,7 @@ public: // Insert the callback. stop_state_callback ret = ++m_next_callback; - m_callbacks.emplace(ret, move(f)); + m_callbacks.emplace(ret, std::move(f)); return ret; } @@ -162,7 +163,7 @@ private: friend class stop_source; template <typename Callback> friend class stop_callback; - stop_token(shared_ptr<polyfill::stop_state> stop_state) : m_stop_state(move(stop_state)) {} + stop_token(shared_ptr<polyfill::stop_state> stop_state) : m_stop_state(std::move(stop_state)) {} private: shared_ptr<polyfill::stop_state> m_stop_state; @@ -198,7 +199,7 @@ public: private: friend class jthread; explicit stop_source(shared_ptr<polyfill::stop_state> stop_state) - : m_stop_state(move(stop_state)) {} + : m_stop_state(std::move(stop_state)) {} private: shared_ptr<polyfill::stop_state> m_stop_state; @@ -218,16 +219,16 @@ public: C&& cb) noexcept(is_nothrow_constructible_v<Callback, C>) : m_stop_state(st.m_stop_state) { if (m_stop_state) { - m_callback = m_stop_state->insert_callback(move(cb)); + m_callback = m_stop_state->insert_callback(std::move(cb)); } } template <typename C> requires constructible_from<Callback, C> explicit stop_callback(stop_token&& st, C&& cb) noexcept(is_nothrow_constructible_v<Callback, C>) - : m_stop_state(move(st.m_stop_state)) { + : m_stop_state(std::move(st.m_stop_state)) { if (m_stop_state) { - m_callback = m_stop_state->insert_callback(move(cb)); + m_callback = m_stop_state->insert_callback(std::move(cb)); } } ~stop_callback() { @@ -260,7 +261,7 @@ public: typename = enable_if_t<!is_same_v<remove_cvref_t<F>, jthread>>> explicit jthread(F&& f, Args&&... args) : m_stop_state(make_shared<polyfill::stop_state>()), - m_thread(make_thread(move(f), move(args)...)) {} + m_thread(make_thread(std::forward<F>(f), std::forward<Args>(args)...)) {} ~jthread() { if (joinable()) { @@ -317,9 +318,9 @@ private: template <typename F, typename... Args> thread make_thread(F&& f, Args&&... args) { if constexpr (is_invocable_v<decay_t<F>, stop_token, decay_t<Args>...>) { - return thread(move(f), get_stop_token(), move(args)...); + return thread(std::forward<F>(f), get_stop_token(), std::forward<Args>(args)...); } else { - return thread(move(f), move(args)...); + return thread(std::forward<F>(f), std::forward<Args>(args)...); } } @@ -332,13 +333,17 @@ private: namespace Common { template <typename Condvar, typename Lock, typename Pred> -void CondvarWait(Condvar& cv, Lock& lock, std::stop_token token, Pred pred) { +void CondvarWait(Condvar& cv, std::unique_lock<Lock>& lk, std::stop_token token, Pred pred) { if (token.stop_requested()) { return; } - std::stop_callback callback(token, [&] { cv.notify_all(); }); - cv.wait(lock, [&] { return pred() || token.stop_requested(); }); + std::stop_callback callback(token, [&] { + { std::scoped_lock lk2{*lk.mutex()}; } + cv.notify_all(); + }); + + cv.wait(lk, [&] { return pred() || token.stop_requested(); }); } template <typename Rep, typename Period> @@ -353,8 +358,10 @@ bool StoppableTimedWait(std::stop_token token, const std::chrono::duration<Rep, std::stop_callback cb(token, [&] { // Wake up the waiting thread. - std::unique_lock lk{m}; - stop_requested = true; + { + std::scoped_lock lk{m}; + stop_requested = true; + } cv.notify_one(); }); diff --git a/src/common/settings.cpp b/src/common/settings.cpp index 16a58a750..98b43e49c 100644 --- a/src/common/settings.cpp +++ b/src/common/settings.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include <version> +#include "common/settings_enums.h" #if __cpp_lib_chrono >= 201907L #include <chrono> #include <exception> @@ -44,6 +45,7 @@ SWITCHABLE(CpuAccuracy, true); SWITCHABLE(FullscreenMode, true); SWITCHABLE(GpuAccuracy, true); SWITCHABLE(Language, true); +SWITCHABLE(MemoryLayout, true); SWITCHABLE(NvdecEmulation, false); SWITCHABLE(Region, true); SWITCHABLE(RendererBackend, true); @@ -60,6 +62,10 @@ SWITCHABLE(u32, false); SWITCHABLE(u8, false); SWITCHABLE(u8, true); +// Used in UISettings +// TODO see if we can move this to uisettings.cpp +SWITCHABLE(ConfirmStop, true); + #undef SETTING #undef SWITCHABLE #endif @@ -129,13 +135,17 @@ void LogSettings() { log_path("DataStorage_SDMCDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::SDMCDir)); } +void UpdateGPUAccuracy() { + values.current_gpu_accuracy = values.gpu_accuracy.GetValue(); +} + bool IsGPULevelExtreme() { - return values.gpu_accuracy.GetValue() == GpuAccuracy::Extreme; + return values.current_gpu_accuracy == GpuAccuracy::Extreme; } bool IsGPULevelHigh() { - return values.gpu_accuracy.GetValue() == GpuAccuracy::Extreme || - values.gpu_accuracy.GetValue() == GpuAccuracy::High; + return values.current_gpu_accuracy == GpuAccuracy::Extreme || + values.current_gpu_accuracy == GpuAccuracy::High; } bool IsFastmemEnabled() { @@ -145,6 +155,10 @@ bool IsFastmemEnabled() { return true; } +bool IsDockedMode() { + return values.use_docked_mode.GetValue() == Settings::ConsoleMode::Docked; +} + float Volume() { if (values.audio_muted) { return 0.0f; @@ -154,6 +168,8 @@ float Volume() { const char* TranslateCategory(Category category) { switch (category) { + case Category::Android: + return "Android"; case Category::Audio: return "Audio"; case Category::Core: diff --git a/src/common/settings.h b/src/common/settings.h index 4407c1e6d..236e33bee 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -67,6 +67,7 @@ SWITCHABLE(CpuAccuracy, true); SWITCHABLE(FullscreenMode, true); SWITCHABLE(GpuAccuracy, true); SWITCHABLE(Language, true); +SWITCHABLE(MemoryLayout, true); SWITCHABLE(NvdecEmulation, false); SWITCHABLE(Region, true); SWITCHABLE(RendererBackend, true); @@ -83,6 +84,10 @@ SWITCHABLE(u32, false); SWITCHABLE(u8, false); SWITCHABLE(u8, true); +// Used in UISettings +// TODO see if we can move this to uisettings.h +SWITCHABLE(ConfirmStop, true); + #undef SETTING #undef SWITCHABLE #endif @@ -307,6 +312,7 @@ struct Values { Specialization::Default, true, true}; + GpuAccuracy current_gpu_accuracy{GpuAccuracy::High}; SwitchableSetting<AnisotropyMode, true> max_anisotropy{ linkage, AnisotropyMode::Automatic, AnisotropyMode::Automatic, AnisotropyMode::X16, "max_anisotropy", Category::RendererAdvanced}; @@ -348,6 +354,10 @@ struct Values { Category::RendererDebug}; Setting<bool> disable_shader_loop_safety_checks{ linkage, false, "disable_shader_loop_safety_checks", Category::RendererDebug}; + Setting<bool> enable_renderdoc_hotkey{linkage, false, "renderdoc_hotkey", + Category::RendererDebug}; + // TODO: remove this once AMDVLK supports VK_EXT_depth_bias_control + bool renderer_amdvlk_depth_bias_workaround{}; // System SwitchableSetting<Language, true> language_index{linkage, @@ -379,7 +389,13 @@ struct Values { Setting<s32> current_user{linkage, 0, "current_user", Category::System}; - SwitchableSetting<bool> use_docked_mode{linkage, true, "use_docked_mode", Category::System}; + SwitchableSetting<ConsoleMode> use_docked_mode{linkage, + ConsoleMode::Docked, + "use_docked_mode", + Category::System, + Specialization::Radio, + true, + true}; // Controls InputSetting<std::array<PlayerInput, 10>> players; @@ -514,11 +530,14 @@ struct Values { extern Values values; +void UpdateGPUAccuracy(); bool IsGPULevelExtreme(); bool IsGPULevelHigh(); bool IsFastmemEnabled(); +bool IsDockedMode(); + float Volume(); std::string GetTimeZoneString(TimeZone time_zone); diff --git a/src/common/settings_common.cpp b/src/common/settings_common.cpp index 137b65d5f..5960b78aa 100644 --- a/src/common/settings_common.cpp +++ b/src/common/settings_common.cpp @@ -14,6 +14,7 @@ BasicSetting::BasicSetting(Linkage& linkage, const std::string& name, enum Categ : label{name}, category{category_}, id{linkage.count}, save{save_}, runtime_modifiable{runtime_modifiable_}, specialization{specialization_}, other_setting{other_setting_} { + linkage.by_key.insert({name, this}); linkage.by_category[category].push_back(this); linkage.count++; } 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 @@ namespace Settings { enum class Category : u32 { + Android, Audio, Core, Cpu, @@ -56,6 +57,7 @@ enum Specialization : u8 { Scalar = 5, // Values are continuous Countable = 6, // Can be stepped through Paired = 7, // Another setting is associated with this setting + Radio = 8, // Setting should be presented in a radio group Percentage = (1 << SpecializationAttributeOffset), // Should be represented as a percentage }; @@ -67,6 +69,7 @@ public: explicit Linkage(u32 initial_count = 0); ~Linkage(); std::map<Category, std::vector<BasicSetting*>> by_category{}; + std::map<std::string, Settings::BasicSetting*> by_key{}; std::vector<std::function<void()>> restore_functions{}; u32 count; }; @@ -222,6 +225,16 @@ public: */ [[nodiscard]] virtual constexpr u32 EnumIndex() const = 0; + /** + * @returns True if the underlying type is a floating point storage + */ + [[nodiscard]] virtual constexpr bool IsFloatingPoint() const = 0; + + /** + * @returns True if the underlying type is an integer storage + */ + [[nodiscard]] virtual constexpr bool IsIntegral() const = 0; + /* * Switchable settings */ diff --git a/src/common/settings_enums.h b/src/common/settings_enums.h index e7cb59ea5..11429d7a8 100644 --- a/src/common/settings_enums.h +++ b/src/common/settings_enums.h @@ -133,6 +133,8 @@ ENUM(CpuAccuracy, Auto, Accurate, Unsafe, Paranoid); ENUM(MemoryLayout, Memory_4Gb, Memory_6Gb, Memory_8Gb); +ENUM(ConfirmStop, Ask_Always, Ask_Based_On_Game, Ask_Never); + ENUM(FullscreenMode, Borderless, Exclusive); ENUM(NvdecEmulation, Off, Cpu, Gpu); @@ -146,6 +148,8 @@ ENUM(AntiAliasing, None, Fxaa, Smaa, MaxEnum); ENUM(AspectRatio, R16_9, R4_3, R21_9, R16_10, Stretch); +ENUM(ConsoleMode, Handheld, Docked); + template <typename Type> inline std::string CanonicalizeEnum(Type id) { const auto group = EnumMetadata<Type>::Canonicalizations(); diff --git a/src/common/settings_setting.h b/src/common/settings_setting.h index e10843c73..3175ab07d 100644 --- a/src/common/settings_setting.h +++ b/src/common/settings_setting.h @@ -10,6 +10,7 @@ #include <string> #include <typeindex> #include <typeinfo> +#include <fmt/core.h> #include "common/common_types.h" #include "common/settings_common.h" #include "common/settings_enums.h" @@ -115,8 +116,12 @@ protected: } else if constexpr (std::is_same_v<Type, AudioEngine>) { // Compatibility with old AudioEngine setting being a string return CanonicalizeEnum(value_); + } else if constexpr (std::is_floating_point_v<Type>) { + return fmt::format("{:f}", value_); + } else if constexpr (std::is_enum_v<Type>) { + return std::to_string(static_cast<u32>(value_)); } else { - return std::to_string(static_cast<u64>(value_)); + return std::to_string(value_); } } @@ -180,13 +185,17 @@ public: this->SetValue(static_cast<u32>(std::stoul(input))); } else if constexpr (std::is_same_v<Type, bool>) { this->SetValue(input == "true"); + } else if constexpr (std::is_same_v<Type, float>) { + this->SetValue(std::stof(input)); } else if constexpr (std::is_same_v<Type, AudioEngine>) { - this->SetValue(ToEnum<Type>(input)); + this->SetValue(ToEnum<AudioEngine>(input)); } else { this->SetValue(static_cast<Type>(std::stoll(input))); } } catch (std::invalid_argument&) { this->SetValue(this->GetDefault()); + } catch (std::out_of_range&) { + this->SetValue(this->GetDefault()); } } @@ -215,11 +224,27 @@ public: } } + [[nodiscard]] constexpr bool IsFloatingPoint() const final { + return std::is_floating_point_v<Type>; + } + + [[nodiscard]] constexpr bool IsIntegral() const final { + return std::is_integral_v<Type>; + } + [[nodiscard]] std::string MinVal() const override final { - return this->ToString(minimum); + if constexpr (std::is_arithmetic_v<Type> && !ranged) { + return this->ToString(std::numeric_limits<Type>::min()); + } else { + return this->ToString(minimum); + } } [[nodiscard]] std::string MaxVal() const override final { - return this->ToString(maximum); + if constexpr (std::is_arithmetic_v<Type> && !ranged) { + return this->ToString(std::numeric_limits<Type>::max()); + } else { + return this->ToString(maximum); + } } [[nodiscard]] constexpr bool Ranged() const override { diff --git a/src/common/string_util.cpp b/src/common/string_util.cpp index feab1653d..4c7aba3f5 100644 --- a/src/common/string_util.cpp +++ b/src/common/string_util.cpp @@ -135,6 +135,11 @@ std::u16string UTF8ToUTF16(std::string_view input) { return convert.from_bytes(input.data(), input.data() + input.size()); } +std::u32string UTF8ToUTF32(std::string_view input) { + std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> convert; + return convert.from_bytes(input.data(), input.data() + input.size()); +} + #ifdef _WIN32 static std::wstring CPToUTF16(u32 code_page, std::string_view input) { const auto size = diff --git a/src/common/string_util.h b/src/common/string_util.h index c351f1a0c..9da1ca4e9 100644 --- a/src/common/string_util.h +++ b/src/common/string_util.h @@ -38,6 +38,7 @@ bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _ [[nodiscard]] std::string UTF16ToUTF8(std::u16string_view input); [[nodiscard]] std::u16string UTF8ToUTF16(std::string_view input); +[[nodiscard]] std::u32string UTF8ToUTF32(std::string_view input); #ifdef _WIN32 [[nodiscard]] std::string UTF16ToUTF8(std::wstring_view input); 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) { return i & v.swap(); } -template <typename S, typename T, typename F> -S operator&(const swap_struct_t<T, F> v, const S& i) { - return static_cast<S>(v.swap() & i); -} - // Comparison template <typename S, typename T, typename F> bool operator<(const S& p, const swap_struct_t<T, F> v) { diff --git a/src/common/wall_clock.cpp b/src/common/wall_clock.cpp index 71e15ab4c..caca9a123 100644 --- a/src/common/wall_clock.cpp +++ b/src/common/wall_clock.cpp @@ -10,6 +10,10 @@ #include "common/x64/rdtsc.h" #endif +#if defined(ARCHITECTURE_arm64) && defined(__linux__) +#include "common/arm64/native_clock.h" +#endif + namespace Common { class StandardWallClock final : public WallClock { @@ -53,7 +57,7 @@ private: }; std::unique_ptr<WallClock> CreateOptimalClock() { -#ifdef ARCHITECTURE_x86_64 +#if defined(ARCHITECTURE_x86_64) const auto& caps = GetCPUCaps(); if (caps.invariant_tsc && caps.tsc_frequency >= std::nano::den) { @@ -64,6 +68,8 @@ std::unique_ptr<WallClock> CreateOptimalClock() { // - Is not more precise than 1 GHz (1ns resolution) return std::make_unique<StandardWallClock>(); } +#elif defined(ARCHITECTURE_arm64) && defined(__linux__) + return std::make_unique<Arm64::NativeClock>(); #else return std::make_unique<StandardWallClock>(); #endif |