diff options
Diffstat (limited to 'src/common')
| -rw-r--r-- | src/common/input.h | 2 | ||||
| -rw-r--r-- | src/common/ring_buffer.h | 2 | ||||
| -rw-r--r-- | src/common/scratch_buffer.h | 46 | ||||
| -rw-r--r-- | src/common/settings.h | 10 | ||||
| -rw-r--r-- | src/common/telemetry.cpp | 1 | ||||
| -rw-r--r-- | src/common/x64/cpu_detect.cpp | 1 | ||||
| -rw-r--r-- | src/common/x64/cpu_detect.h | 1 | ||||
| -rw-r--r-- | src/common/x64/cpu_wait.cpp | 52 |
8 files changed, 74 insertions, 41 deletions
diff --git a/src/common/input.h b/src/common/input.h index ea30770ae..2c4ccea22 100644 --- a/src/common/input.h +++ b/src/common/input.h | |||
| @@ -75,8 +75,10 @@ enum class DriverResult { | |||
| 75 | ErrorWritingData, | 75 | ErrorWritingData, |
| 76 | NoDeviceDetected, | 76 | NoDeviceDetected, |
| 77 | InvalidHandle, | 77 | InvalidHandle, |
| 78 | InvalidParameters, | ||
| 78 | NotSupported, | 79 | NotSupported, |
| 79 | Disabled, | 80 | Disabled, |
| 81 | Delayed, | ||
| 80 | Unknown, | 82 | Unknown, |
| 81 | }; | 83 | }; |
| 82 | 84 | ||
diff --git a/src/common/ring_buffer.h b/src/common/ring_buffer.h index 416680d44..5c961b202 100644 --- a/src/common/ring_buffer.h +++ b/src/common/ring_buffer.h | |||
| @@ -54,7 +54,7 @@ public: | |||
| 54 | return push_count; | 54 | return push_count; |
| 55 | } | 55 | } |
| 56 | 56 | ||
| 57 | std::size_t Push(const std::span<T> input) { | 57 | std::size_t Push(std::span<const T> input) { |
| 58 | return Push(input.data(), input.size()); | 58 | return Push(input.data(), input.size()); |
| 59 | } | 59 | } |
| 60 | 60 | ||
diff --git a/src/common/scratch_buffer.h b/src/common/scratch_buffer.h index 6fe907953..d5961b020 100644 --- a/src/common/scratch_buffer.h +++ b/src/common/scratch_buffer.h | |||
| @@ -5,7 +5,6 @@ | |||
| 5 | 5 | ||
| 6 | #include <iterator> | 6 | #include <iterator> |
| 7 | 7 | ||
| 8 | #include "common/concepts.h" | ||
| 9 | #include "common/make_unique_for_overwrite.h" | 8 | #include "common/make_unique_for_overwrite.h" |
| 10 | 9 | ||
| 11 | namespace Common { | 10 | namespace Common { |
| @@ -19,15 +18,22 @@ namespace Common { | |||
| 19 | template <typename T> | 18 | template <typename T> |
| 20 | class ScratchBuffer { | 19 | class ScratchBuffer { |
| 21 | public: | 20 | public: |
| 22 | using iterator = T*; | ||
| 23 | using const_iterator = const T*; | ||
| 24 | using value_type = T; | ||
| 25 | using element_type = T; | 21 | using element_type = T; |
| 26 | using iterator_category = std::contiguous_iterator_tag; | 22 | using value_type = T; |
| 23 | using size_type = size_t; | ||
| 24 | using difference_type = std::ptrdiff_t; | ||
| 25 | using pointer = T*; | ||
| 26 | using const_pointer = const T*; | ||
| 27 | using reference = T&; | ||
| 28 | using const_reference = const T&; | ||
| 29 | using iterator = pointer; | ||
| 30 | using const_iterator = const_pointer; | ||
| 31 | using iterator_category = std::random_access_iterator_tag; | ||
| 32 | using iterator_concept = std::contiguous_iterator_tag; | ||
| 27 | 33 | ||
| 28 | ScratchBuffer() = default; | 34 | ScratchBuffer() = default; |
| 29 | 35 | ||
| 30 | explicit ScratchBuffer(size_t initial_capacity) | 36 | explicit ScratchBuffer(size_type initial_capacity) |
| 31 | : last_requested_size{initial_capacity}, buffer_capacity{initial_capacity}, | 37 | : last_requested_size{initial_capacity}, buffer_capacity{initial_capacity}, |
| 32 | buffer{Common::make_unique_for_overwrite<T[]>(initial_capacity)} {} | 38 | buffer{Common::make_unique_for_overwrite<T[]>(initial_capacity)} {} |
| 33 | 39 | ||
| @@ -39,7 +45,7 @@ public: | |||
| 39 | 45 | ||
| 40 | /// This will only grow the buffer's capacity if size is greater than the current capacity. | 46 | /// This will only grow the buffer's capacity if size is greater than the current capacity. |
| 41 | /// The previously held data will remain intact. | 47 | /// The previously held data will remain intact. |
| 42 | void resize(size_t size) { | 48 | void resize(size_type size) { |
| 43 | if (size > buffer_capacity) { | 49 | if (size > buffer_capacity) { |
| 44 | auto new_buffer = Common::make_unique_for_overwrite<T[]>(size); | 50 | auto new_buffer = Common::make_unique_for_overwrite<T[]>(size); |
| 45 | std::move(buffer.get(), buffer.get() + buffer_capacity, new_buffer.get()); | 51 | std::move(buffer.get(), buffer.get() + buffer_capacity, new_buffer.get()); |
| @@ -51,7 +57,7 @@ public: | |||
| 51 | 57 | ||
| 52 | /// This will only grow the buffer's capacity if size is greater than the current capacity. | 58 | /// This will only grow the buffer's capacity if size is greater than the current capacity. |
| 53 | /// The previously held data will be destroyed if a reallocation occurs. | 59 | /// The previously held data will be destroyed if a reallocation occurs. |
| 54 | void resize_destructive(size_t size) { | 60 | void resize_destructive(size_type size) { |
| 55 | if (size > buffer_capacity) { | 61 | if (size > buffer_capacity) { |
| 56 | buffer_capacity = size; | 62 | buffer_capacity = size; |
| 57 | buffer = Common::make_unique_for_overwrite<T[]>(buffer_capacity); | 63 | buffer = Common::make_unique_for_overwrite<T[]>(buffer_capacity); |
| @@ -59,43 +65,43 @@ public: | |||
| 59 | last_requested_size = size; | 65 | last_requested_size = size; |
| 60 | } | 66 | } |
| 61 | 67 | ||
| 62 | [[nodiscard]] T* data() noexcept { | 68 | [[nodiscard]] pointer data() noexcept { |
| 63 | return buffer.get(); | 69 | return buffer.get(); |
| 64 | } | 70 | } |
| 65 | 71 | ||
| 66 | [[nodiscard]] const T* data() const noexcept { | 72 | [[nodiscard]] const_pointer data() const noexcept { |
| 67 | return buffer.get(); | 73 | return buffer.get(); |
| 68 | } | 74 | } |
| 69 | 75 | ||
| 70 | [[nodiscard]] T* begin() noexcept { | 76 | [[nodiscard]] iterator begin() noexcept { |
| 71 | return data(); | 77 | return data(); |
| 72 | } | 78 | } |
| 73 | 79 | ||
| 74 | [[nodiscard]] const T* begin() const noexcept { | 80 | [[nodiscard]] const_iterator begin() const noexcept { |
| 75 | return data(); | 81 | return data(); |
| 76 | } | 82 | } |
| 77 | 83 | ||
| 78 | [[nodiscard]] T* end() noexcept { | 84 | [[nodiscard]] iterator end() noexcept { |
| 79 | return data() + last_requested_size; | 85 | return data() + last_requested_size; |
| 80 | } | 86 | } |
| 81 | 87 | ||
| 82 | [[nodiscard]] const T* end() const noexcept { | 88 | [[nodiscard]] const_iterator end() const noexcept { |
| 83 | return data() + last_requested_size; | 89 | return data() + last_requested_size; |
| 84 | } | 90 | } |
| 85 | 91 | ||
| 86 | [[nodiscard]] T& operator[](size_t i) { | 92 | [[nodiscard]] reference operator[](size_type i) { |
| 87 | return buffer[i]; | 93 | return buffer[i]; |
| 88 | } | 94 | } |
| 89 | 95 | ||
| 90 | [[nodiscard]] const T& operator[](size_t i) const { | 96 | [[nodiscard]] const_reference operator[](size_type i) const { |
| 91 | return buffer[i]; | 97 | return buffer[i]; |
| 92 | } | 98 | } |
| 93 | 99 | ||
| 94 | [[nodiscard]] size_t size() const noexcept { | 100 | [[nodiscard]] size_type size() const noexcept { |
| 95 | return last_requested_size; | 101 | return last_requested_size; |
| 96 | } | 102 | } |
| 97 | 103 | ||
| 98 | [[nodiscard]] size_t capacity() const noexcept { | 104 | [[nodiscard]] size_type capacity() const noexcept { |
| 99 | return buffer_capacity; | 105 | return buffer_capacity; |
| 100 | } | 106 | } |
| 101 | 107 | ||
| @@ -106,8 +112,8 @@ public: | |||
| 106 | } | 112 | } |
| 107 | 113 | ||
| 108 | private: | 114 | private: |
| 109 | size_t last_requested_size{}; | 115 | size_type last_requested_size{}; |
| 110 | size_t buffer_capacity{}; | 116 | size_type buffer_capacity{}; |
| 111 | std::unique_ptr<T[]> buffer{}; | 117 | std::unique_ptr<T[]> buffer{}; |
| 112 | }; | 118 | }; |
| 113 | 119 | ||
diff --git a/src/common/settings.h b/src/common/settings.h index ae5ed93d8..59e96e74f 100644 --- a/src/common/settings.h +++ b/src/common/settings.h | |||
| @@ -527,12 +527,10 @@ struct Values { | |||
| 527 | Setting<bool> mouse_panning{false, "mouse_panning"}; | 527 | Setting<bool> mouse_panning{false, "mouse_panning"}; |
| 528 | Setting<u8, true> mouse_panning_x_sensitivity{50, 1, 100, "mouse_panning_x_sensitivity"}; | 528 | Setting<u8, true> mouse_panning_x_sensitivity{50, 1, 100, "mouse_panning_x_sensitivity"}; |
| 529 | Setting<u8, true> mouse_panning_y_sensitivity{50, 1, 100, "mouse_panning_y_sensitivity"}; | 529 | Setting<u8, true> mouse_panning_y_sensitivity{50, 1, 100, "mouse_panning_y_sensitivity"}; |
| 530 | Setting<u8, true> mouse_panning_deadzone_x_counterweight{ | 530 | Setting<u8, true> mouse_panning_deadzone_counterweight{20, 0, 100, |
| 531 | 0, 0, 100, "mouse_panning_deadzone_x_counterweight"}; | 531 | "mouse_panning_deadzone_counterweight"}; |
| 532 | Setting<u8, true> mouse_panning_deadzone_y_counterweight{ | 532 | Setting<u8, true> mouse_panning_decay_strength{18, 0, 100, "mouse_panning_decay_strength"}; |
| 533 | 0, 0, 100, "mouse_panning_deadzone_y_counterweight"}; | 533 | Setting<u8, true> mouse_panning_min_decay{6, 0, 100, "mouse_panning_min_decay"}; |
| 534 | Setting<u8, true> mouse_panning_decay_strength{22, 0, 100, "mouse_panning_decay_strength"}; | ||
| 535 | Setting<u8, true> mouse_panning_min_decay{5, 0, 100, "mouse_panning_min_decay"}; | ||
| 536 | 534 | ||
| 537 | Setting<bool> mouse_enabled{false, "mouse_enabled"}; | 535 | Setting<bool> mouse_enabled{false, "mouse_enabled"}; |
| 538 | Setting<bool> emulate_analog_keyboard{false, "emulate_analog_keyboard"}; | 536 | Setting<bool> emulate_analog_keyboard{false, "emulate_analog_keyboard"}; |
diff --git a/src/common/telemetry.cpp b/src/common/telemetry.cpp index 91352912d..929ed67e4 100644 --- a/src/common/telemetry.cpp +++ b/src/common/telemetry.cpp | |||
| @@ -93,6 +93,7 @@ void AppendCPUInfo(FieldCollection& fc) { | |||
| 93 | add_field("CPU_Extension_x64_GFNI", caps.gfni); | 93 | add_field("CPU_Extension_x64_GFNI", caps.gfni); |
| 94 | add_field("CPU_Extension_x64_INVARIANT_TSC", caps.invariant_tsc); | 94 | add_field("CPU_Extension_x64_INVARIANT_TSC", caps.invariant_tsc); |
| 95 | add_field("CPU_Extension_x64_LZCNT", caps.lzcnt); | 95 | add_field("CPU_Extension_x64_LZCNT", caps.lzcnt); |
| 96 | add_field("CPU_Extension_x64_MONITORX", caps.monitorx); | ||
| 96 | add_field("CPU_Extension_x64_MOVBE", caps.movbe); | 97 | add_field("CPU_Extension_x64_MOVBE", caps.movbe); |
| 97 | add_field("CPU_Extension_x64_PCLMULQDQ", caps.pclmulqdq); | 98 | add_field("CPU_Extension_x64_PCLMULQDQ", caps.pclmulqdq); |
| 98 | add_field("CPU_Extension_x64_POPCNT", caps.popcnt); | 99 | add_field("CPU_Extension_x64_POPCNT", caps.popcnt); |
diff --git a/src/common/x64/cpu_detect.cpp b/src/common/x64/cpu_detect.cpp index c998b1197..780120a5b 100644 --- a/src/common/x64/cpu_detect.cpp +++ b/src/common/x64/cpu_detect.cpp | |||
| @@ -168,6 +168,7 @@ static CPUCaps Detect() { | |||
| 168 | __cpuid(cpu_id, 0x80000001); | 168 | __cpuid(cpu_id, 0x80000001); |
| 169 | caps.lzcnt = Common::Bit<5>(cpu_id[2]); | 169 | caps.lzcnt = Common::Bit<5>(cpu_id[2]); |
| 170 | caps.fma4 = Common::Bit<16>(cpu_id[2]); | 170 | caps.fma4 = Common::Bit<16>(cpu_id[2]); |
| 171 | caps.monitorx = Common::Bit<29>(cpu_id[2]); | ||
| 171 | } | 172 | } |
| 172 | 173 | ||
| 173 | if (max_ex_fn >= 0x80000007) { | 174 | if (max_ex_fn >= 0x80000007) { |
diff --git a/src/common/x64/cpu_detect.h b/src/common/x64/cpu_detect.h index 8253944d6..756459417 100644 --- a/src/common/x64/cpu_detect.h +++ b/src/common/x64/cpu_detect.h | |||
| @@ -63,6 +63,7 @@ struct CPUCaps { | |||
| 63 | bool gfni : 1; | 63 | bool gfni : 1; |
| 64 | bool invariant_tsc : 1; | 64 | bool invariant_tsc : 1; |
| 65 | bool lzcnt : 1; | 65 | bool lzcnt : 1; |
| 66 | bool monitorx : 1; | ||
| 66 | bool movbe : 1; | 67 | bool movbe : 1; |
| 67 | bool pclmulqdq : 1; | 68 | bool pclmulqdq : 1; |
| 68 | bool popcnt : 1; | 69 | bool popcnt : 1; |
diff --git a/src/common/x64/cpu_wait.cpp b/src/common/x64/cpu_wait.cpp index c53dd4945..41d385f59 100644 --- a/src/common/x64/cpu_wait.cpp +++ b/src/common/x64/cpu_wait.cpp | |||
| @@ -13,36 +13,60 @@ | |||
| 13 | 13 | ||
| 14 | namespace Common::X64 { | 14 | namespace Common::X64 { |
| 15 | 15 | ||
| 16 | namespace { | ||
| 17 | |||
| 18 | // 100,000 cycles is a reasonable amount of time to wait to save on CPU resources. | ||
| 19 | // For reference: | ||
| 20 | // At 1 GHz, 100K cycles is 100us | ||
| 21 | // At 2 GHz, 100K cycles is 50us | ||
| 22 | // At 4 GHz, 100K cycles is 25us | ||
| 23 | constexpr auto PauseCycles = 100'000U; | ||
| 24 | |||
| 25 | } // Anonymous namespace | ||
| 26 | |||
| 16 | #ifdef _MSC_VER | 27 | #ifdef _MSC_VER |
| 17 | __forceinline static void TPAUSE() { | 28 | __forceinline static void TPAUSE() { |
| 18 | // 100,000 cycles is a reasonable amount of time to wait to save on CPU resources. | 29 | static constexpr auto RequestC02State = 0U; |
| 19 | // For reference: | 30 | _tpause(RequestC02State, FencedRDTSC() + PauseCycles); |
| 20 | // At 1 GHz, 100K cycles is 100us | 31 | } |
| 21 | // At 2 GHz, 100K cycles is 50us | 32 | |
| 22 | // At 4 GHz, 100K cycles is 25us | 33 | __forceinline static void MWAITX() { |
| 23 | static constexpr auto PauseCycles = 100'000; | 34 | static constexpr auto EnableWaitTimeFlag = 1U << 1; |
| 24 | _tpause(0, FencedRDTSC() + PauseCycles); | 35 | static constexpr auto RequestC1State = 0U; |
| 36 | |||
| 37 | // monitor_var should be aligned to a cache line. | ||
| 38 | alignas(64) u64 monitor_var{}; | ||
| 39 | _mm_monitorx(&monitor_var, 0, 0); | ||
| 40 | _mm_mwaitx(EnableWaitTimeFlag, RequestC1State, PauseCycles); | ||
| 25 | } | 41 | } |
| 26 | #else | 42 | #else |
| 27 | static void TPAUSE() { | 43 | static void TPAUSE() { |
| 28 | // 100,000 cycles is a reasonable amount of time to wait to save on CPU resources. | 44 | static constexpr auto RequestC02State = 0U; |
| 29 | // For reference: | ||
| 30 | // At 1 GHz, 100K cycles is 100us | ||
| 31 | // At 2 GHz, 100K cycles is 50us | ||
| 32 | // At 4 GHz, 100K cycles is 25us | ||
| 33 | static constexpr auto PauseCycles = 100'000; | ||
| 34 | const auto tsc = FencedRDTSC() + PauseCycles; | 45 | const auto tsc = FencedRDTSC() + PauseCycles; |
| 35 | const auto eax = static_cast<u32>(tsc & 0xFFFFFFFF); | 46 | const auto eax = static_cast<u32>(tsc & 0xFFFFFFFF); |
| 36 | const auto edx = static_cast<u32>(tsc >> 32); | 47 | const auto edx = static_cast<u32>(tsc >> 32); |
| 37 | asm volatile("tpause %0" : : "r"(0), "d"(edx), "a"(eax)); | 48 | asm volatile("tpause %0" : : "r"(RequestC02State), "d"(edx), "a"(eax)); |
| 49 | } | ||
| 50 | |||
| 51 | static void MWAITX() { | ||
| 52 | static constexpr auto EnableWaitTimeFlag = 1U << 1; | ||
| 53 | static constexpr auto RequestC1State = 0U; | ||
| 54 | |||
| 55 | // monitor_var should be aligned to a cache line. | ||
| 56 | alignas(64) u64 monitor_var{}; | ||
| 57 | asm volatile("monitorx" : : "a"(&monitor_var), "c"(0), "d"(0)); | ||
| 58 | asm volatile("mwaitx" : : "a"(RequestC1State), "b"(PauseCycles), "c"(EnableWaitTimeFlag)); | ||
| 38 | } | 59 | } |
| 39 | #endif | 60 | #endif |
| 40 | 61 | ||
| 41 | void MicroSleep() { | 62 | void MicroSleep() { |
| 42 | static const bool has_waitpkg = GetCPUCaps().waitpkg; | 63 | static const bool has_waitpkg = GetCPUCaps().waitpkg; |
| 64 | static const bool has_monitorx = GetCPUCaps().monitorx; | ||
| 43 | 65 | ||
| 44 | if (has_waitpkg) { | 66 | if (has_waitpkg) { |
| 45 | TPAUSE(); | 67 | TPAUSE(); |
| 68 | } else if (has_monitorx) { | ||
| 69 | MWAITX(); | ||
| 46 | } else { | 70 | } else { |
| 47 | std::this_thread::yield(); | 71 | std::this_thread::yield(); |
| 48 | } | 72 | } |