diff options
Diffstat (limited to 'src/common')
| -rw-r--r-- | src/common/atomic_ops.h | 90 | ||||
| -rw-r--r-- | src/common/fiber.cpp | 5 | ||||
| -rw-r--r-- | src/common/host_memory.cpp | 4 | ||||
| -rw-r--r-- | src/common/logging/filter.cpp | 2 | ||||
| -rw-r--r-- | src/common/logging/types.h | 2 | ||||
| -rw-r--r-- | src/common/math_util.h | 50 | ||||
| -rw-r--r-- | src/common/settings.h | 6 | ||||
| -rw-r--r-- | src/common/settings_input.h | 1 | ||||
| -rw-r--r-- | src/common/thread.h | 2 | ||||
| -rw-r--r-- | src/common/threadsafe_queue.h | 4 | ||||
| -rw-r--r-- | src/common/x64/native_clock.cpp | 59 |
11 files changed, 194 insertions, 31 deletions
diff --git a/src/common/atomic_ops.h b/src/common/atomic_ops.h index b94d73c7a..69fde8421 100644 --- a/src/common/atomic_ops.h +++ b/src/common/atomic_ops.h | |||
| @@ -46,6 +46,50 @@ namespace Common { | |||
| 46 | reinterpret_cast<__int64*>(expected.data())) != 0; | 46 | reinterpret_cast<__int64*>(expected.data())) != 0; |
| 47 | } | 47 | } |
| 48 | 48 | ||
| 49 | [[nodiscard]] inline bool AtomicCompareAndSwap(volatile u8* pointer, u8 value, u8 expected, | ||
| 50 | u8& actual) { | ||
| 51 | actual = | ||
| 52 | _InterlockedCompareExchange8(reinterpret_cast<volatile char*>(pointer), value, expected); | ||
| 53 | return actual == expected; | ||
| 54 | } | ||
| 55 | |||
| 56 | [[nodiscard]] inline bool AtomicCompareAndSwap(volatile u16* pointer, u16 value, u16 expected, | ||
| 57 | u16& actual) { | ||
| 58 | actual = | ||
| 59 | _InterlockedCompareExchange16(reinterpret_cast<volatile short*>(pointer), value, expected); | ||
| 60 | return actual == expected; | ||
| 61 | } | ||
| 62 | |||
| 63 | [[nodiscard]] inline bool AtomicCompareAndSwap(volatile u32* pointer, u32 value, u32 expected, | ||
| 64 | u32& actual) { | ||
| 65 | actual = | ||
| 66 | _InterlockedCompareExchange(reinterpret_cast<volatile long*>(pointer), value, expected); | ||
| 67 | return actual == expected; | ||
| 68 | } | ||
| 69 | |||
| 70 | [[nodiscard]] inline bool AtomicCompareAndSwap(volatile u64* pointer, u64 value, u64 expected, | ||
| 71 | u64& actual) { | ||
| 72 | actual = _InterlockedCompareExchange64(reinterpret_cast<volatile __int64*>(pointer), value, | ||
| 73 | expected); | ||
| 74 | return actual == expected; | ||
| 75 | } | ||
| 76 | |||
| 77 | [[nodiscard]] inline bool AtomicCompareAndSwap(volatile u64* pointer, u128 value, u128 expected, | ||
| 78 | u128& actual) { | ||
| 79 | const bool result = | ||
| 80 | _InterlockedCompareExchange128(reinterpret_cast<volatile __int64*>(pointer), value[1], | ||
| 81 | value[0], reinterpret_cast<__int64*>(expected.data())) != 0; | ||
| 82 | actual = expected; | ||
| 83 | return result; | ||
| 84 | } | ||
| 85 | |||
| 86 | [[nodiscard]] inline u128 AtomicLoad128(volatile u64* pointer) { | ||
| 87 | u128 result{}; | ||
| 88 | _InterlockedCompareExchange128(reinterpret_cast<volatile __int64*>(pointer), result[1], | ||
| 89 | result[0], reinterpret_cast<__int64*>(result.data())); | ||
| 90 | return result; | ||
| 91 | } | ||
| 92 | |||
| 49 | #else | 93 | #else |
| 50 | 94 | ||
| 51 | [[nodiscard]] inline bool AtomicCompareAndSwap(volatile u8* pointer, u8 value, u8 expected) { | 95 | [[nodiscard]] inline bool AtomicCompareAndSwap(volatile u8* pointer, u8 value, u8 expected) { |
| @@ -72,6 +116,52 @@ namespace Common { | |||
| 72 | return __sync_bool_compare_and_swap((unsigned __int128*)pointer, expected_a, value_a); | 116 | return __sync_bool_compare_and_swap((unsigned __int128*)pointer, expected_a, value_a); |
| 73 | } | 117 | } |
| 74 | 118 | ||
| 119 | [[nodiscard]] inline bool AtomicCompareAndSwap(volatile u8* pointer, u8 value, u8 expected, | ||
| 120 | u8& actual) { | ||
| 121 | actual = __sync_val_compare_and_swap(pointer, expected, value); | ||
| 122 | return actual == expected; | ||
| 123 | } | ||
| 124 | |||
| 125 | [[nodiscard]] inline bool AtomicCompareAndSwap(volatile u16* pointer, u16 value, u16 expected, | ||
| 126 | u16& actual) { | ||
| 127 | actual = __sync_val_compare_and_swap(pointer, expected, value); | ||
| 128 | return actual == expected; | ||
| 129 | } | ||
| 130 | |||
| 131 | [[nodiscard]] inline bool AtomicCompareAndSwap(volatile u32* pointer, u32 value, u32 expected, | ||
| 132 | u32& actual) { | ||
| 133 | actual = __sync_val_compare_and_swap(pointer, expected, value); | ||
| 134 | return actual == expected; | ||
| 135 | } | ||
| 136 | |||
| 137 | [[nodiscard]] inline bool AtomicCompareAndSwap(volatile u64* pointer, u64 value, u64 expected, | ||
| 138 | u64& actual) { | ||
| 139 | actual = __sync_val_compare_and_swap(pointer, expected, value); | ||
| 140 | return actual == expected; | ||
| 141 | } | ||
| 142 | |||
| 143 | [[nodiscard]] inline bool AtomicCompareAndSwap(volatile u64* pointer, u128 value, u128 expected, | ||
| 144 | u128& actual) { | ||
| 145 | unsigned __int128 value_a; | ||
| 146 | unsigned __int128 expected_a; | ||
| 147 | unsigned __int128 actual_a; | ||
| 148 | std::memcpy(&value_a, value.data(), sizeof(u128)); | ||
| 149 | std::memcpy(&expected_a, expected.data(), sizeof(u128)); | ||
| 150 | actual_a = __sync_val_compare_and_swap((unsigned __int128*)pointer, expected_a, value_a); | ||
| 151 | std::memcpy(actual.data(), &actual_a, sizeof(u128)); | ||
| 152 | return actual_a == expected_a; | ||
| 153 | } | ||
| 154 | |||
| 155 | [[nodiscard]] inline u128 AtomicLoad128(volatile u64* pointer) { | ||
| 156 | unsigned __int128 zeros_a = 0; | ||
| 157 | unsigned __int128 result_a = | ||
| 158 | __sync_val_compare_and_swap((unsigned __int128*)pointer, zeros_a, zeros_a); | ||
| 159 | |||
| 160 | u128 result; | ||
| 161 | std::memcpy(result.data(), &result_a, sizeof(u128)); | ||
| 162 | return result; | ||
| 163 | } | ||
| 164 | |||
| 75 | #endif | 165 | #endif |
| 76 | 166 | ||
| 77 | } // namespace Common | 167 | } // namespace Common |
diff --git a/src/common/fiber.cpp b/src/common/fiber.cpp index 81b212e4b..177a74deb 100644 --- a/src/common/fiber.cpp +++ b/src/common/fiber.cpp | |||
| @@ -2,9 +2,10 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <mutex> | ||
| 6 | |||
| 5 | #include "common/assert.h" | 7 | #include "common/assert.h" |
| 6 | #include "common/fiber.h" | 8 | #include "common/fiber.h" |
| 7 | #include "common/spin_lock.h" | ||
| 8 | #include "common/virtual_buffer.h" | 9 | #include "common/virtual_buffer.h" |
| 9 | 10 | ||
| 10 | #include <boost/context/detail/fcontext.hpp> | 11 | #include <boost/context/detail/fcontext.hpp> |
| @@ -19,7 +20,7 @@ struct Fiber::FiberImpl { | |||
| 19 | VirtualBuffer<u8> stack; | 20 | VirtualBuffer<u8> stack; |
| 20 | VirtualBuffer<u8> rewind_stack; | 21 | VirtualBuffer<u8> rewind_stack; |
| 21 | 22 | ||
| 22 | SpinLock guard{}; | 23 | std::mutex guard; |
| 23 | std::function<void(void*)> entry_point; | 24 | std::function<void(void*)> entry_point; |
| 24 | std::function<void(void*)> rewind_point; | 25 | std::function<void(void*)> rewind_point; |
| 25 | void* rewind_parameter{}; | 26 | void* rewind_parameter{}; |
diff --git a/src/common/host_memory.cpp b/src/common/host_memory.cpp index e829af1ac..802943eb7 100644 --- a/src/common/host_memory.cpp +++ b/src/common/host_memory.cpp | |||
| @@ -149,7 +149,7 @@ public: | |||
| 149 | } | 149 | } |
| 150 | 150 | ||
| 151 | void Unmap(size_t virtual_offset, size_t length) { | 151 | void Unmap(size_t virtual_offset, size_t length) { |
| 152 | std::lock_guard lock{placeholder_mutex}; | 152 | std::scoped_lock lock{placeholder_mutex}; |
| 153 | 153 | ||
| 154 | // Unmap until there are no more placeholders | 154 | // Unmap until there are no more placeholders |
| 155 | while (UnmapOnePlaceholder(virtual_offset, length)) { | 155 | while (UnmapOnePlaceholder(virtual_offset, length)) { |
| @@ -169,7 +169,7 @@ public: | |||
| 169 | } | 169 | } |
| 170 | const size_t virtual_end = virtual_offset + length; | 170 | const size_t virtual_end = virtual_offset + length; |
| 171 | 171 | ||
| 172 | std::lock_guard lock{placeholder_mutex}; | 172 | std::scoped_lock lock{placeholder_mutex}; |
| 173 | auto [it, end] = placeholders.equal_range({virtual_offset, virtual_end}); | 173 | auto [it, end] = placeholders.equal_range({virtual_offset, virtual_end}); |
| 174 | while (it != end) { | 174 | while (it != end) { |
| 175 | const size_t offset = std::max(it->lower(), virtual_offset); | 175 | const size_t offset = std::max(it->lower(), virtual_offset); |
diff --git a/src/common/logging/filter.cpp b/src/common/logging/filter.cpp index 4afc1369a..4acbff649 100644 --- a/src/common/logging/filter.cpp +++ b/src/common/logging/filter.cpp | |||
| @@ -101,6 +101,7 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) { | |||
| 101 | SUB(Service, GRC) \ | 101 | SUB(Service, GRC) \ |
| 102 | SUB(Service, HID) \ | 102 | SUB(Service, HID) \ |
| 103 | SUB(Service, IRS) \ | 103 | SUB(Service, IRS) \ |
| 104 | SUB(Service, JIT) \ | ||
| 104 | SUB(Service, LBL) \ | 105 | SUB(Service, LBL) \ |
| 105 | SUB(Service, LDN) \ | 106 | SUB(Service, LDN) \ |
| 106 | SUB(Service, LDR) \ | 107 | SUB(Service, LDR) \ |
| @@ -119,6 +120,7 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) { | |||
| 119 | SUB(Service, NPNS) \ | 120 | SUB(Service, NPNS) \ |
| 120 | SUB(Service, NS) \ | 121 | SUB(Service, NS) \ |
| 121 | SUB(Service, NVDRV) \ | 122 | SUB(Service, NVDRV) \ |
| 123 | SUB(Service, NVFlinger) \ | ||
| 122 | SUB(Service, OLSC) \ | 124 | SUB(Service, OLSC) \ |
| 123 | SUB(Service, PCIE) \ | 125 | SUB(Service, PCIE) \ |
| 124 | SUB(Service, PCTL) \ | 126 | SUB(Service, PCTL) \ |
diff --git a/src/common/logging/types.h b/src/common/logging/types.h index 2b6e4daa7..99c15fa96 100644 --- a/src/common/logging/types.h +++ b/src/common/logging/types.h | |||
| @@ -69,6 +69,7 @@ enum class Class : u8 { | |||
| 69 | Service_GRC, ///< The game recording service | 69 | Service_GRC, ///< The game recording service |
| 70 | Service_HID, ///< The HID (Human interface device) service | 70 | Service_HID, ///< The HID (Human interface device) service |
| 71 | Service_IRS, ///< The IRS service | 71 | Service_IRS, ///< The IRS service |
| 72 | Service_JIT, ///< The JIT service | ||
| 72 | Service_LBL, ///< The LBL (LCD backlight) service | 73 | Service_LBL, ///< The LBL (LCD backlight) service |
| 73 | Service_LDN, ///< The LDN (Local domain network) service | 74 | Service_LDN, ///< The LDN (Local domain network) service |
| 74 | Service_LDR, ///< The loader service | 75 | Service_LDR, ///< The loader service |
| @@ -87,6 +88,7 @@ enum class Class : u8 { | |||
| 87 | Service_NPNS, ///< The NPNS service | 88 | Service_NPNS, ///< The NPNS service |
| 88 | Service_NS, ///< The NS services | 89 | Service_NS, ///< The NS services |
| 89 | Service_NVDRV, ///< The NVDRV (Nvidia driver) service | 90 | Service_NVDRV, ///< The NVDRV (Nvidia driver) service |
| 91 | Service_NVFlinger, ///< The NVFlinger service | ||
| 90 | Service_OLSC, ///< The OLSC service | 92 | Service_OLSC, ///< The OLSC service |
| 91 | Service_PCIE, ///< The PCIe service | 93 | Service_PCIE, ///< The PCIe service |
| 92 | Service_PCTL, ///< The PCTL (Parental control) service | 94 | Service_PCTL, ///< The PCTL (Parental control) service |
diff --git a/src/common/math_util.h b/src/common/math_util.h index 510c4e56d..54485bf53 100644 --- a/src/common/math_util.h +++ b/src/common/math_util.h | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <algorithm> | ||
| 7 | #include <cstdlib> | 8 | #include <cstdlib> |
| 8 | #include <type_traits> | 9 | #include <type_traits> |
| 9 | 10 | ||
| @@ -20,10 +21,32 @@ struct Rectangle { | |||
| 20 | 21 | ||
| 21 | constexpr Rectangle() = default; | 22 | constexpr Rectangle() = default; |
| 22 | 23 | ||
| 24 | constexpr Rectangle(T width, T height) : right(width), bottom(height) {} | ||
| 25 | |||
| 23 | constexpr Rectangle(T left_, T top_, T right_, T bottom_) | 26 | constexpr Rectangle(T left_, T top_, T right_, T bottom_) |
| 24 | : left(left_), top(top_), right(right_), bottom(bottom_) {} | 27 | : left(left_), top(top_), right(right_), bottom(bottom_) {} |
| 25 | 28 | ||
| 26 | [[nodiscard]] T GetWidth() const { | 29 | [[nodiscard]] constexpr T Left() const { |
| 30 | return left; | ||
| 31 | } | ||
| 32 | |||
| 33 | [[nodiscard]] constexpr T Top() const { | ||
| 34 | return top; | ||
| 35 | } | ||
| 36 | |||
| 37 | [[nodiscard]] constexpr T Right() const { | ||
| 38 | return right; | ||
| 39 | } | ||
| 40 | |||
| 41 | [[nodiscard]] constexpr T Bottom() const { | ||
| 42 | return bottom; | ||
| 43 | } | ||
| 44 | |||
| 45 | [[nodiscard]] constexpr bool IsEmpty() const { | ||
| 46 | return (GetWidth() <= 0) || (GetHeight() <= 0); | ||
| 47 | } | ||
| 48 | |||
| 49 | [[nodiscard]] constexpr T GetWidth() const { | ||
| 27 | if constexpr (std::is_floating_point_v<T>) { | 50 | if constexpr (std::is_floating_point_v<T>) { |
| 28 | return std::abs(right - left); | 51 | return std::abs(right - left); |
| 29 | } else { | 52 | } else { |
| @@ -31,7 +54,7 @@ struct Rectangle { | |||
| 31 | } | 54 | } |
| 32 | } | 55 | } |
| 33 | 56 | ||
| 34 | [[nodiscard]] T GetHeight() const { | 57 | [[nodiscard]] constexpr T GetHeight() const { |
| 35 | if constexpr (std::is_floating_point_v<T>) { | 58 | if constexpr (std::is_floating_point_v<T>) { |
| 36 | return std::abs(bottom - top); | 59 | return std::abs(bottom - top); |
| 37 | } else { | 60 | } else { |
| @@ -39,18 +62,35 @@ struct Rectangle { | |||
| 39 | } | 62 | } |
| 40 | } | 63 | } |
| 41 | 64 | ||
| 42 | [[nodiscard]] Rectangle<T> TranslateX(const T x) const { | 65 | [[nodiscard]] constexpr Rectangle<T> TranslateX(const T x) const { |
| 43 | return Rectangle{left + x, top, right + x, bottom}; | 66 | return Rectangle{left + x, top, right + x, bottom}; |
| 44 | } | 67 | } |
| 45 | 68 | ||
| 46 | [[nodiscard]] Rectangle<T> TranslateY(const T y) const { | 69 | [[nodiscard]] constexpr Rectangle<T> TranslateY(const T y) const { |
| 47 | return Rectangle{left, top + y, right, bottom + y}; | 70 | return Rectangle{left, top + y, right, bottom + y}; |
| 48 | } | 71 | } |
| 49 | 72 | ||
| 50 | [[nodiscard]] Rectangle<T> Scale(const float s) const { | 73 | [[nodiscard]] constexpr Rectangle<T> Scale(const float s) const { |
| 51 | return Rectangle{left, top, static_cast<T>(static_cast<float>(left + GetWidth()) * s), | 74 | return Rectangle{left, top, static_cast<T>(static_cast<float>(left + GetWidth()) * s), |
| 52 | static_cast<T>(static_cast<float>(top + GetHeight()) * s)}; | 75 | static_cast<T>(static_cast<float>(top + GetHeight()) * s)}; |
| 53 | } | 76 | } |
| 77 | |||
| 78 | [[nodiscard]] constexpr bool operator==(const Rectangle<T>& rhs) const { | ||
| 79 | return (left == rhs.left) && (top == rhs.top) && (right == rhs.right) && | ||
| 80 | (bottom == rhs.bottom); | ||
| 81 | } | ||
| 82 | |||
| 83 | [[nodiscard]] constexpr bool operator!=(const Rectangle<T>& rhs) const { | ||
| 84 | return !operator==(rhs); | ||
| 85 | } | ||
| 86 | |||
| 87 | [[nodiscard]] constexpr bool Intersect(const Rectangle<T>& with, Rectangle<T>* result) const { | ||
| 88 | result->left = std::max(left, with.left); | ||
| 89 | result->top = std::max(top, with.top); | ||
| 90 | result->right = std::min(right, with.right); | ||
| 91 | result->bottom = std::min(bottom, with.bottom); | ||
| 92 | return !result->IsEmpty(); | ||
| 93 | } | ||
| 54 | }; | 94 | }; |
| 55 | 95 | ||
| 56 | template <typename T> | 96 | template <typename T> |
diff --git a/src/common/settings.h b/src/common/settings.h index a37d83fb3..3b7be63b3 100644 --- a/src/common/settings.h +++ b/src/common/settings.h | |||
| @@ -38,6 +38,7 @@ enum class CPUAccuracy : u32 { | |||
| 38 | Auto = 0, | 38 | Auto = 0, |
| 39 | Accurate = 1, | 39 | Accurate = 1, |
| 40 | Unsafe = 2, | 40 | Unsafe = 2, |
| 41 | Paranoid = 3, | ||
| 41 | }; | 42 | }; |
| 42 | 43 | ||
| 43 | enum class FullscreenMode : u32 { | 44 | enum class FullscreenMode : u32 { |
| @@ -470,7 +471,7 @@ struct Values { | |||
| 470 | 471 | ||
| 471 | // Cpu | 472 | // Cpu |
| 472 | RangedSetting<CPUAccuracy> cpu_accuracy{CPUAccuracy::Auto, CPUAccuracy::Auto, | 473 | RangedSetting<CPUAccuracy> cpu_accuracy{CPUAccuracy::Auto, CPUAccuracy::Auto, |
| 473 | CPUAccuracy::Unsafe, "cpu_accuracy"}; | 474 | CPUAccuracy::Paranoid, "cpu_accuracy"}; |
| 474 | // TODO: remove cpu_accuracy_first_time, migration setting added 8 July 2021 | 475 | // TODO: remove cpu_accuracy_first_time, migration setting added 8 July 2021 |
| 475 | BasicSetting<bool> cpu_accuracy_first_time{true, "cpu_accuracy_first_time"}; | 476 | BasicSetting<bool> cpu_accuracy_first_time{true, "cpu_accuracy_first_time"}; |
| 476 | BasicSetting<bool> cpu_debug_mode{false, "cpu_debug_mode"}; | 477 | BasicSetting<bool> cpu_debug_mode{false, "cpu_debug_mode"}; |
| @@ -589,6 +590,9 @@ struct Values { | |||
| 589 | BasicSetting<int> touch_from_button_map_index{0, "touch_from_button_map"}; | 590 | BasicSetting<int> touch_from_button_map_index{0, "touch_from_button_map"}; |
| 590 | std::vector<TouchFromButtonMap> touch_from_button_maps; | 591 | std::vector<TouchFromButtonMap> touch_from_button_maps; |
| 591 | 592 | ||
| 593 | BasicSetting<bool> enable_ring_controller{true, "enable_ring_controller"}; | ||
| 594 | RingconRaw ringcon_analogs; | ||
| 595 | |||
| 592 | // Data Storage | 596 | // Data Storage |
| 593 | BasicSetting<bool> use_virtual_sd{true, "use_virtual_sd"}; | 597 | BasicSetting<bool> use_virtual_sd{true, "use_virtual_sd"}; |
| 594 | BasicSetting<bool> gamecard_inserted{false, "gamecard_inserted"}; | 598 | BasicSetting<bool> gamecard_inserted{false, "gamecard_inserted"}; |
diff --git a/src/common/settings_input.h b/src/common/settings_input.h index 4ff37e186..6f42346bc 100644 --- a/src/common/settings_input.h +++ b/src/common/settings_input.h | |||
| @@ -357,6 +357,7 @@ constexpr int NUM_KEYBOARD_MODS_HID = NumKeyboardMods; | |||
| 357 | using AnalogsRaw = std::array<std::string, NativeAnalog::NumAnalogs>; | 357 | using AnalogsRaw = std::array<std::string, NativeAnalog::NumAnalogs>; |
| 358 | using ButtonsRaw = std::array<std::string, NativeButton::NumButtons>; | 358 | using ButtonsRaw = std::array<std::string, NativeButton::NumButtons>; |
| 359 | using MotionsRaw = std::array<std::string, NativeMotion::NumMotions>; | 359 | using MotionsRaw = std::array<std::string, NativeMotion::NumMotions>; |
| 360 | using RingconRaw = std::string; | ||
| 360 | 361 | ||
| 361 | constexpr u32 JOYCON_BODY_NEON_RED = 0xFF3C28; | 362 | constexpr u32 JOYCON_BODY_NEON_RED = 0xFF3C28; |
| 362 | constexpr u32 JOYCON_BUTTONS_NEON_RED = 0x1E0A0A; | 363 | constexpr u32 JOYCON_BUTTONS_NEON_RED = 0x1E0A0A; |
diff --git a/src/common/thread.h b/src/common/thread.h index a8c17c71a..626609372 100644 --- a/src/common/thread.h +++ b/src/common/thread.h | |||
| @@ -17,7 +17,7 @@ namespace Common { | |||
| 17 | class Event { | 17 | class Event { |
| 18 | public: | 18 | public: |
| 19 | void Set() { | 19 | void Set() { |
| 20 | std::lock_guard lk{mutex}; | 20 | std::scoped_lock lk{mutex}; |
| 21 | if (!is_set) { | 21 | if (!is_set) { |
| 22 | is_set = true; | 22 | is_set = true; |
| 23 | condvar.notify_one(); | 23 | condvar.notify_one(); |
diff --git a/src/common/threadsafe_queue.h b/src/common/threadsafe_queue.h index 2c8c2b90e..7272ac6e8 100644 --- a/src/common/threadsafe_queue.h +++ b/src/common/threadsafe_queue.h | |||
| @@ -52,7 +52,7 @@ public: | |||
| 52 | // line before cv.wait | 52 | // line before cv.wait |
| 53 | // TODO(bunnei): This can be replaced with C++20 waitable atomics when properly supported. | 53 | // TODO(bunnei): This can be replaced with C++20 waitable atomics when properly supported. |
| 54 | // See discussion on https://github.com/yuzu-emu/yuzu/pull/3173 for details. | 54 | // See discussion on https://github.com/yuzu-emu/yuzu/pull/3173 for details. |
| 55 | std::lock_guard lock{cv_mutex}; | 55 | std::scoped_lock lock{cv_mutex}; |
| 56 | cv.notify_one(); | 56 | cv.notify_one(); |
| 57 | } | 57 | } |
| 58 | 58 | ||
| @@ -159,7 +159,7 @@ public: | |||
| 159 | 159 | ||
| 160 | template <typename Arg> | 160 | template <typename Arg> |
| 161 | void Push(Arg&& t) { | 161 | void Push(Arg&& t) { |
| 162 | std::lock_guard lock{write_lock}; | 162 | std::scoped_lock lock{write_lock}; |
| 163 | spsc_queue.Push(t); | 163 | spsc_queue.Push(t); |
| 164 | } | 164 | } |
| 165 | 165 | ||
diff --git a/src/common/x64/native_clock.cpp b/src/common/x64/native_clock.cpp index 347e41efc..7fd9d22f8 100644 --- a/src/common/x64/native_clock.cpp +++ b/src/common/x64/native_clock.cpp | |||
| @@ -10,25 +10,49 @@ | |||
| 10 | #include "common/uint128.h" | 10 | #include "common/uint128.h" |
| 11 | #include "common/x64/native_clock.h" | 11 | #include "common/x64/native_clock.h" |
| 12 | 12 | ||
| 13 | #ifdef _MSC_VER | ||
| 14 | #include <intrin.h> | ||
| 15 | #endif | ||
| 16 | |||
| 13 | namespace Common { | 17 | namespace Common { |
| 14 | 18 | ||
| 19 | #ifdef _MSC_VER | ||
| 20 | __forceinline static u64 FencedRDTSC() { | ||
| 21 | _mm_lfence(); | ||
| 22 | _ReadWriteBarrier(); | ||
| 23 | const u64 result = __rdtsc(); | ||
| 24 | _mm_lfence(); | ||
| 25 | _ReadWriteBarrier(); | ||
| 26 | return result; | ||
| 27 | } | ||
| 28 | #else | ||
| 29 | static u64 FencedRDTSC() { | ||
| 30 | u64 result; | ||
| 31 | asm volatile("lfence\n\t" | ||
| 32 | "rdtsc\n\t" | ||
| 33 | "shl $32, %%rdx\n\t" | ||
| 34 | "or %%rdx, %0\n\t" | ||
| 35 | "lfence" | ||
| 36 | : "=a"(result) | ||
| 37 | : | ||
| 38 | : "rdx", "memory", "cc"); | ||
| 39 | return result; | ||
| 40 | } | ||
| 41 | #endif | ||
| 42 | |||
| 15 | u64 EstimateRDTSCFrequency() { | 43 | u64 EstimateRDTSCFrequency() { |
| 16 | // Discard the first result measuring the rdtsc. | 44 | // Discard the first result measuring the rdtsc. |
| 17 | _mm_mfence(); | 45 | FencedRDTSC(); |
| 18 | __rdtsc(); | ||
| 19 | std::this_thread::sleep_for(std::chrono::milliseconds{1}); | 46 | std::this_thread::sleep_for(std::chrono::milliseconds{1}); |
| 20 | _mm_mfence(); | 47 | FencedRDTSC(); |
| 21 | __rdtsc(); | ||
| 22 | 48 | ||
| 23 | // Get the current time. | 49 | // Get the current time. |
| 24 | const auto start_time = std::chrono::steady_clock::now(); | 50 | const auto start_time = std::chrono::steady_clock::now(); |
| 25 | _mm_mfence(); | 51 | const u64 tsc_start = FencedRDTSC(); |
| 26 | const u64 tsc_start = __rdtsc(); | ||
| 27 | // Wait for 200 milliseconds. | 52 | // Wait for 200 milliseconds. |
| 28 | std::this_thread::sleep_for(std::chrono::milliseconds{200}); | 53 | std::this_thread::sleep_for(std::chrono::milliseconds{200}); |
| 29 | const auto end_time = std::chrono::steady_clock::now(); | 54 | const auto end_time = std::chrono::steady_clock::now(); |
| 30 | _mm_mfence(); | 55 | const u64 tsc_end = FencedRDTSC(); |
| 31 | const u64 tsc_end = __rdtsc(); | ||
| 32 | // Calculate differences. | 56 | // Calculate differences. |
| 33 | const u64 timer_diff = static_cast<u64>( | 57 | const u64 timer_diff = static_cast<u64>( |
| 34 | std::chrono::duration_cast<std::chrono::nanoseconds>(end_time - start_time).count()); | 58 | std::chrono::duration_cast<std::chrono::nanoseconds>(end_time - start_time).count()); |
| @@ -42,8 +66,7 @@ NativeClock::NativeClock(u64 emulated_cpu_frequency_, u64 emulated_clock_frequen | |||
| 42 | u64 rtsc_frequency_) | 66 | u64 rtsc_frequency_) |
| 43 | : WallClock(emulated_cpu_frequency_, emulated_clock_frequency_, true), rtsc_frequency{ | 67 | : WallClock(emulated_cpu_frequency_, emulated_clock_frequency_, true), rtsc_frequency{ |
| 44 | rtsc_frequency_} { | 68 | rtsc_frequency_} { |
| 45 | _mm_mfence(); | 69 | time_point.inner.last_measure = FencedRDTSC(); |
| 46 | time_point.inner.last_measure = __rdtsc(); | ||
| 47 | time_point.inner.accumulated_ticks = 0U; | 70 | time_point.inner.accumulated_ticks = 0U; |
| 48 | ns_rtsc_factor = GetFixedPoint64Factor(NS_RATIO, rtsc_frequency); | 71 | ns_rtsc_factor = GetFixedPoint64Factor(NS_RATIO, rtsc_frequency); |
| 49 | us_rtsc_factor = GetFixedPoint64Factor(US_RATIO, rtsc_frequency); | 72 | us_rtsc_factor = GetFixedPoint64Factor(US_RATIO, rtsc_frequency); |
| @@ -55,10 +78,10 @@ NativeClock::NativeClock(u64 emulated_cpu_frequency_, u64 emulated_clock_frequen | |||
| 55 | u64 NativeClock::GetRTSC() { | 78 | u64 NativeClock::GetRTSC() { |
| 56 | TimePoint new_time_point{}; | 79 | TimePoint new_time_point{}; |
| 57 | TimePoint current_time_point{}; | 80 | TimePoint current_time_point{}; |
| 81 | |||
| 82 | current_time_point.pack = Common::AtomicLoad128(time_point.pack.data()); | ||
| 58 | do { | 83 | do { |
| 59 | current_time_point.pack = time_point.pack; | 84 | const u64 current_measure = FencedRDTSC(); |
| 60 | _mm_mfence(); | ||
| 61 | const u64 current_measure = __rdtsc(); | ||
| 62 | u64 diff = current_measure - current_time_point.inner.last_measure; | 85 | u64 diff = current_measure - current_time_point.inner.last_measure; |
| 63 | diff = diff & ~static_cast<u64>(static_cast<s64>(diff) >> 63); // max(diff, 0) | 86 | diff = diff & ~static_cast<u64>(static_cast<s64>(diff) >> 63); // max(diff, 0) |
| 64 | new_time_point.inner.last_measure = current_measure > current_time_point.inner.last_measure | 87 | new_time_point.inner.last_measure = current_measure > current_time_point.inner.last_measure |
| @@ -66,7 +89,7 @@ u64 NativeClock::GetRTSC() { | |||
| 66 | : current_time_point.inner.last_measure; | 89 | : current_time_point.inner.last_measure; |
| 67 | new_time_point.inner.accumulated_ticks = current_time_point.inner.accumulated_ticks + diff; | 90 | new_time_point.inner.accumulated_ticks = current_time_point.inner.accumulated_ticks + diff; |
| 68 | } while (!Common::AtomicCompareAndSwap(time_point.pack.data(), new_time_point.pack, | 91 | } while (!Common::AtomicCompareAndSwap(time_point.pack.data(), new_time_point.pack, |
| 69 | current_time_point.pack)); | 92 | current_time_point.pack, current_time_point.pack)); |
| 70 | /// The clock cannot be more precise than the guest timer, remove the lower bits | 93 | /// The clock cannot be more precise than the guest timer, remove the lower bits |
| 71 | return new_time_point.inner.accumulated_ticks & inaccuracy_mask; | 94 | return new_time_point.inner.accumulated_ticks & inaccuracy_mask; |
| 72 | } | 95 | } |
| @@ -75,13 +98,13 @@ void NativeClock::Pause(bool is_paused) { | |||
| 75 | if (!is_paused) { | 98 | if (!is_paused) { |
| 76 | TimePoint current_time_point{}; | 99 | TimePoint current_time_point{}; |
| 77 | TimePoint new_time_point{}; | 100 | TimePoint new_time_point{}; |
| 101 | |||
| 102 | current_time_point.pack = Common::AtomicLoad128(time_point.pack.data()); | ||
| 78 | do { | 103 | do { |
| 79 | current_time_point.pack = time_point.pack; | ||
| 80 | new_time_point.pack = current_time_point.pack; | 104 | new_time_point.pack = current_time_point.pack; |
| 81 | _mm_mfence(); | 105 | new_time_point.inner.last_measure = FencedRDTSC(); |
| 82 | new_time_point.inner.last_measure = __rdtsc(); | ||
| 83 | } while (!Common::AtomicCompareAndSwap(time_point.pack.data(), new_time_point.pack, | 106 | } while (!Common::AtomicCompareAndSwap(time_point.pack.data(), new_time_point.pack, |
| 84 | current_time_point.pack)); | 107 | current_time_point.pack, current_time_point.pack)); |
| 85 | } | 108 | } |
| 86 | } | 109 | } |
| 87 | 110 | ||