summaryrefslogtreecommitdiffstats
path: root/src/common
diff options
context:
space:
mode:
Diffstat (limited to 'src/common')
-rw-r--r--src/common/CMakeLists.txt5
-rw-r--r--src/common/bit_field.h9
-rw-r--r--src/common/common_funcs.h10
-rw-r--r--src/common/logging/filter.cpp2
-rw-r--r--src/common/logging/types.h2
-rw-r--r--src/common/settings.cpp1
-rw-r--r--src/common/settings.h67
-rw-r--r--src/common/wall_clock.cpp2
-rw-r--r--src/common/x64/cpu_detect.cpp16
-rw-r--r--src/common/x64/cpu_detect.h5
10 files changed, 74 insertions, 45 deletions
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index 73bf626d4..566695fde 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -182,8 +182,9 @@ create_target_directory_groups(common)
target_link_libraries(common PUBLIC ${Boost_LIBRARIES} fmt::fmt microprofile Threads::Threads)
target_link_libraries(common PRIVATE lz4::lz4 xbyak)
-if (MSVC)
+if (TARGET zstd::zstd)
target_link_libraries(common PRIVATE zstd::zstd)
else()
- target_link_libraries(common PRIVATE zstd)
+ target_link_libraries(common PRIVATE
+ $<IF:$<TARGET_EXISTS:zstd::libzstd_shared>,zstd::libzstd_shared,zstd::libzstd_static>)
endif()
diff --git a/src/common/bit_field.h b/src/common/bit_field.h
index 16d805694..7e1df62b1 100644
--- a/src/common/bit_field.h
+++ b/src/common/bit_field.h
@@ -146,7 +146,16 @@ public:
}
constexpr void Assign(const T& value) {
+#ifdef _MSC_VER
storage = static_cast<StorageType>((storage & ~mask) | FormatValue(value));
+#else
+ // Explicitly reload with memcpy to avoid compiler aliasing quirks
+ // regarding optimization: GCC/Clang clobber chained stores to
+ // different bitfields in the same struct with the last value.
+ StorageTypeWithEndian storage_;
+ std::memcpy(&storage_, &storage, sizeof(storage_));
+ storage = static_cast<StorageType>((storage_ & ~mask) | FormatValue(value));
+#endif
}
[[nodiscard]] constexpr T Value() const {
diff --git a/src/common/common_funcs.h b/src/common/common_funcs.h
index adc31c758..e1e2a90fc 100644
--- a/src/common/common_funcs.h
+++ b/src/common/common_funcs.h
@@ -18,14 +18,16 @@
/// Helper macros to insert unused bytes or words to properly align structs. These values will be
/// zero-initialized.
#define INSERT_PADDING_BYTES(num_bytes) \
- std::array<u8, num_bytes> CONCAT2(pad, __LINE__) {}
+ [[maybe_unused]] std::array<u8, num_bytes> CONCAT2(pad, __LINE__) {}
#define INSERT_PADDING_WORDS(num_words) \
- std::array<u32, num_words> CONCAT2(pad, __LINE__) {}
+ [[maybe_unused]] std::array<u32, num_words> CONCAT2(pad, __LINE__) {}
/// These are similar to the INSERT_PADDING_* macros but do not zero-initialize the contents.
/// This keeps the structure trivial to construct.
-#define INSERT_PADDING_BYTES_NOINIT(num_bytes) std::array<u8, num_bytes> CONCAT2(pad, __LINE__)
-#define INSERT_PADDING_WORDS_NOINIT(num_words) std::array<u32, num_words> CONCAT2(pad, __LINE__)
+#define INSERT_PADDING_BYTES_NOINIT(num_bytes) \
+ [[maybe_unused]] std::array<u8, num_bytes> CONCAT2(pad, __LINE__)
+#define INSERT_PADDING_WORDS_NOINIT(num_words) \
+ [[maybe_unused]] std::array<u32, num_words> CONCAT2(pad, __LINE__)
#ifndef _MSC_VER
diff --git a/src/common/logging/filter.cpp b/src/common/logging/filter.cpp
index 4acbff649..6de9bacbf 100644
--- a/src/common/logging/filter.cpp
+++ b/src/common/logging/filter.cpp
@@ -128,7 +128,7 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) {
SUB(Service, PM) \
SUB(Service, PREPO) \
SUB(Service, PSC) \
- SUB(Service, PSM) \
+ SUB(Service, PTM) \
SUB(Service, SET) \
SUB(Service, SM) \
SUB(Service, SPL) \
diff --git a/src/common/logging/types.h b/src/common/logging/types.h
index cabb4db8e..595c15ada 100644
--- a/src/common/logging/types.h
+++ b/src/common/logging/types.h
@@ -95,7 +95,7 @@ enum class Class : u8 {
Service_PM, ///< The PM service
Service_PREPO, ///< The PREPO (Play report) service
Service_PSC, ///< The PSC service
- Service_PSM, ///< The PSM service
+ Service_PTM, ///< The PTM service
Service_SET, ///< The SET (Settings) service
Service_SM, ///< The SM (Service manager) service
Service_SPL, ///< The SPL service
diff --git a/src/common/settings.cpp b/src/common/settings.cpp
index 751549583..d4c52989a 100644
--- a/src/common/settings.cpp
+++ b/src/common/settings.cpp
@@ -185,7 +185,6 @@ void RestoreGlobalState(bool is_powered_on) {
values.max_anisotropy.SetGlobal(true);
values.use_speed_limit.SetGlobal(true);
values.speed_limit.SetGlobal(true);
- values.fps_cap.SetGlobal(true);
values.use_disk_shader_cache.SetGlobal(true);
values.gpu_accuracy.SetGlobal(true);
values.use_asynchronous_gpu_emulation.SetGlobal(true);
diff --git a/src/common/settings.h b/src/common/settings.h
index 3583a2e70..2bccb8642 100644
--- a/src/common/settings.h
+++ b/src/common/settings.h
@@ -106,7 +106,7 @@ struct ResolutionScalingInfo {
* configurations. Specifying a default value and label is required. A minimum and maximum range can
* be specified for sanitization.
*/
-template <typename Type>
+template <typename Type, bool ranged = false>
class Setting {
protected:
Setting() = default;
@@ -126,8 +126,8 @@ public:
* @param default_val Intial value of the setting, and default value of the setting
* @param name Label for the setting
*/
- explicit Setting(const Type& default_val, const std::string& name)
- : value{default_val}, default_value{default_val}, ranged{false}, label{name} {}
+ explicit Setting(const Type& default_val, const std::string& name) requires(!ranged)
+ : value{default_val}, default_value{default_val}, label{name} {}
virtual ~Setting() = default;
/**
@@ -139,9 +139,9 @@ public:
* @param name Label for the setting
*/
explicit Setting(const Type& default_val, const Type& min_val, const Type& max_val,
- const std::string& name)
- : value{default_val}, default_value{default_val}, maximum{max_val}, minimum{min_val},
- ranged{true}, label{name} {}
+ const std::string& name) requires(ranged)
+ : value{default_val},
+ default_value{default_val}, maximum{max_val}, minimum{min_val}, label{name} {}
/**
* Returns a reference to the setting's value.
@@ -158,7 +158,7 @@ public:
* @param val The desired value
*/
virtual void SetValue(const Type& val) {
- Type temp{(ranged) ? std::clamp(val, minimum, maximum) : val};
+ Type temp{ranged ? std::clamp(val, minimum, maximum) : val};
std::swap(value, temp);
}
@@ -188,7 +188,7 @@ public:
* @returns A reference to the setting
*/
virtual const Type& operator=(const Type& val) {
- Type temp{(ranged) ? std::clamp(val, minimum, maximum) : val};
+ Type temp{ranged ? std::clamp(val, minimum, maximum) : val};
std::swap(value, temp);
return value;
}
@@ -207,7 +207,6 @@ protected:
const Type default_value{}; ///< The default value
const Type maximum{}; ///< Maximum allowed value of the setting
const Type minimum{}; ///< Minimum allowed value of the setting
- const bool ranged; ///< The setting has sanitization ranges
const std::string label{}; ///< The setting's label
};
@@ -219,8 +218,8 @@ protected:
*
* By default, the global setting is used.
*/
-template <typename Type>
-class SwitchableSetting : virtual public Setting<Type> {
+template <typename Type, bool ranged = false>
+class SwitchableSetting : virtual public Setting<Type, ranged> {
public:
/**
* Sets a default value, label, and setting value.
@@ -228,7 +227,7 @@ public:
* @param default_val Intial value of the setting, and default value of the setting
* @param name Label for the setting
*/
- explicit SwitchableSetting(const Type& default_val, const std::string& name)
+ explicit SwitchableSetting(const Type& default_val, const std::string& name) requires(!ranged)
: Setting<Type>{default_val, name} {}
virtual ~SwitchableSetting() = default;
@@ -241,8 +240,8 @@ public:
* @param name Label for the setting
*/
explicit SwitchableSetting(const Type& default_val, const Type& min_val, const Type& max_val,
- const std::string& name)
- : Setting<Type>{default_val, min_val, max_val, name} {}
+ const std::string& name) requires(ranged)
+ : Setting<Type, true>{default_val, min_val, max_val, name} {}
/**
* Tells this setting to represent either the global or custom setting when other member
@@ -290,7 +289,7 @@ public:
* @param val The new value
*/
void SetValue(const Type& val) override {
- Type temp{(this->ranged) ? std::clamp(val, this->minimum, this->maximum) : val};
+ Type temp{ranged ? std::clamp(val, this->minimum, this->maximum) : val};
if (use_global) {
std::swap(this->value, temp);
} else {
@@ -306,7 +305,7 @@ public:
* @returns A reference to the current setting value
*/
const Type& operator=(const Type& val) override {
- Type temp{(this->ranged) ? std::clamp(val, this->minimum, this->maximum) : val};
+ Type temp{ranged ? std::clamp(val, this->minimum, this->maximum) : val};
if (use_global) {
std::swap(this->value, temp);
return this->value;
@@ -374,15 +373,15 @@ struct Values {
Setting<std::string> audio_device_id{"auto", "output_device"};
Setting<std::string> sink_id{"auto", "output_engine"};
Setting<bool> audio_muted{false, "audio_muted"};
- SwitchableSetting<u8> volume{100, 0, 100, "volume"};
+ SwitchableSetting<u8, true> volume{100, 0, 100, "volume"};
// Core
SwitchableSetting<bool> use_multi_core{true, "use_multi_core"};
SwitchableSetting<bool> use_extended_memory_layout{false, "use_extended_memory_layout"};
// Cpu
- SwitchableSetting<CPUAccuracy> cpu_accuracy{CPUAccuracy::Auto, CPUAccuracy::Auto,
- CPUAccuracy::Paranoid, "cpu_accuracy"};
+ SwitchableSetting<CPUAccuracy, true> cpu_accuracy{CPUAccuracy::Auto, CPUAccuracy::Auto,
+ CPUAccuracy::Paranoid, "cpu_accuracy"};
// TODO: remove cpu_accuracy_first_time, migration setting added 8 July 2021
Setting<bool> cpu_accuracy_first_time{true, "cpu_accuracy_first_time"};
Setting<bool> cpu_debug_mode{false, "cpu_debug_mode"};
@@ -409,7 +408,7 @@ struct Values {
true, "cpuopt_unsafe_ignore_global_monitor"};
// Renderer
- SwitchableSetting<RendererBackend> renderer_backend{
+ SwitchableSetting<RendererBackend, true> renderer_backend{
RendererBackend::Vulkan, RendererBackend::OpenGL, RendererBackend::Vulkan, "backend"};
Setting<bool> renderer_debug{false, "debug"};
Setting<bool> renderer_shader_feedback{false, "shader_feedback"};
@@ -423,28 +422,26 @@ struct Values {
SwitchableSetting<AntiAliasing> anti_aliasing{AntiAliasing::None, "anti_aliasing"};
// *nix platforms may have issues with the borderless windowed fullscreen mode.
// Default to exclusive fullscreen on these platforms for now.
- SwitchableSetting<FullscreenMode> fullscreen_mode{
+ SwitchableSetting<FullscreenMode, true> fullscreen_mode{
#ifdef _WIN32
FullscreenMode::Borderless,
#else
FullscreenMode::Exclusive,
#endif
FullscreenMode::Borderless, FullscreenMode::Exclusive, "fullscreen_mode"};
- SwitchableSetting<int> aspect_ratio{0, 0, 3, "aspect_ratio"};
- SwitchableSetting<int> max_anisotropy{0, 0, 5, "max_anisotropy"};
+ SwitchableSetting<int, true> aspect_ratio{0, 0, 3, "aspect_ratio"};
+ SwitchableSetting<int, true> max_anisotropy{0, 0, 5, "max_anisotropy"};
SwitchableSetting<bool> use_speed_limit{true, "use_speed_limit"};
- SwitchableSetting<u16> speed_limit{100, 0, 9999, "speed_limit"};
+ SwitchableSetting<u16, true> speed_limit{100, 0, 9999, "speed_limit"};
SwitchableSetting<bool> use_disk_shader_cache{true, "use_disk_shader_cache"};
- SwitchableSetting<GPUAccuracy> gpu_accuracy{GPUAccuracy::High, GPUAccuracy::Normal,
- GPUAccuracy::Extreme, "gpu_accuracy"};
+ SwitchableSetting<GPUAccuracy, true> gpu_accuracy{GPUAccuracy::High, GPUAccuracy::Normal,
+ GPUAccuracy::Extreme, "gpu_accuracy"};
SwitchableSetting<bool> use_asynchronous_gpu_emulation{true, "use_asynchronous_gpu_emulation"};
SwitchableSetting<NvdecEmulation> nvdec_emulation{NvdecEmulation::GPU, "nvdec_emulation"};
SwitchableSetting<bool> accelerate_astc{true, "accelerate_astc"};
SwitchableSetting<bool> use_vsync{true, "use_vsync"};
- SwitchableSetting<u16> fps_cap{1000, 1, 1000, "fps_cap"};
- Setting<bool> disable_fps_limit{false, "disable_fps_limit"};
- SwitchableSetting<ShaderBackend> shader_backend{ShaderBackend::GLASM, ShaderBackend::GLSL,
- ShaderBackend::SPIRV, "shader_backend"};
+ SwitchableSetting<ShaderBackend, true> shader_backend{ShaderBackend::GLASM, ShaderBackend::GLSL,
+ ShaderBackend::SPIRV, "shader_backend"};
SwitchableSetting<bool> use_asynchronous_shaders{false, "use_asynchronous_shaders"};
SwitchableSetting<bool> use_fast_gpu_time{true, "use_fast_gpu_time"};
@@ -460,10 +457,10 @@ struct Values {
s64 custom_rtc_differential;
Setting<s32> current_user{0, "current_user"};
- SwitchableSetting<s32> language_index{1, 0, 17, "language_index"};
- SwitchableSetting<s32> region_index{1, 0, 6, "region_index"};
- SwitchableSetting<s32> time_zone_index{0, 0, 45, "time_zone_index"};
- SwitchableSetting<s32> sound_index{1, 0, 2, "sound_index"};
+ SwitchableSetting<s32, true> language_index{1, 0, 17, "language_index"};
+ SwitchableSetting<s32, true> region_index{1, 0, 6, "region_index"};
+ SwitchableSetting<s32, true> time_zone_index{0, 0, 45, "time_zone_index"};
+ SwitchableSetting<s32, true> sound_index{1, 0, 2, "sound_index"};
// Controls
InputSetting<std::array<PlayerInput, 10>> players;
@@ -485,7 +482,7 @@ struct Values {
Setting<bool> tas_loop{false, "tas_loop"};
Setting<bool> mouse_panning{false, "mouse_panning"};
- Setting<u8> mouse_panning_sensitivity{10, 1, 100, "mouse_panning_sensitivity"};
+ Setting<u8, true> mouse_panning_sensitivity{10, 1, 100, "mouse_panning_sensitivity"};
Setting<bool> mouse_enabled{false, "mouse_enabled"};
Setting<bool> emulate_analog_keyboard{false, "emulate_analog_keyboard"};
diff --git a/src/common/wall_clock.cpp b/src/common/wall_clock.cpp
index b4fb3a59f..ae07f2811 100644
--- a/src/common/wall_clock.cpp
+++ b/src/common/wall_clock.cpp
@@ -67,7 +67,7 @@ std::unique_ptr<WallClock> CreateBestMatchingClock(u64 emulated_cpu_frequency,
const auto& caps = GetCPUCaps();
u64 rtsc_frequency = 0;
if (caps.invariant_tsc) {
- rtsc_frequency = EstimateRDTSCFrequency();
+ rtsc_frequency = caps.tsc_frequency ? caps.tsc_frequency : EstimateRDTSCFrequency();
}
// Fallback to StandardWallClock if the hardware TSC does not have the precision greater than:
diff --git a/src/common/x64/cpu_detect.cpp b/src/common/x64/cpu_detect.cpp
index 322aa1f08..1a27532d4 100644
--- a/src/common/x64/cpu_detect.cpp
+++ b/src/common/x64/cpu_detect.cpp
@@ -161,6 +161,22 @@ static CPUCaps Detect() {
caps.invariant_tsc = Common::Bit<8>(cpu_id[3]);
}
+ if (max_std_fn >= 0x15) {
+ __cpuid(cpu_id, 0x15);
+ caps.tsc_crystal_ratio_denominator = cpu_id[0];
+ caps.tsc_crystal_ratio_numerator = cpu_id[1];
+ caps.crystal_frequency = cpu_id[2];
+ // Some CPU models might not return a crystal frequency.
+ // The CPU model can be detected to use the values from turbostat
+ // https://github.com/torvalds/linux/blob/master/tools/power/x86/turbostat/turbostat.c#L5569
+ // but it's easier to just estimate the TSC tick rate for these cases.
+ if (caps.tsc_crystal_ratio_denominator) {
+ caps.tsc_frequency = static_cast<u64>(caps.crystal_frequency) *
+ caps.tsc_crystal_ratio_numerator /
+ caps.tsc_crystal_ratio_denominator;
+ }
+ }
+
if (max_std_fn >= 0x16) {
__cpuid(cpu_id, 0x16);
caps.base_frequency = cpu_id[0];
diff --git a/src/common/x64/cpu_detect.h b/src/common/x64/cpu_detect.h
index 9bdc9dbfa..6830f3795 100644
--- a/src/common/x64/cpu_detect.h
+++ b/src/common/x64/cpu_detect.h
@@ -30,6 +30,11 @@ struct CPUCaps {
u32 max_frequency;
u32 bus_frequency;
+ u32 tsc_crystal_ratio_denominator;
+ u32 tsc_crystal_ratio_numerator;
+ u32 crystal_frequency;
+ u64 tsc_frequency; // Derived from the above three values
+
bool sse : 1;
bool sse2 : 1;
bool sse3 : 1;