diff options
Diffstat (limited to 'src/common')
| -rw-r--r-- | src/common/CMakeLists.txt | 11 | ||||
| -rw-r--r-- | src/common/announce_multiplayer_room.h | 2 | ||||
| -rw-r--r-- | src/common/bit_cast.h | 20 | ||||
| -rw-r--r-- | src/common/fiber.cpp | 2 | ||||
| -rw-r--r-- | src/common/fixed_point.h | 2 | ||||
| -rw-r--r-- | src/common/host_memory.cpp | 4 | ||||
| -rw-r--r-- | src/common/input.h | 10 | ||||
| -rw-r--r-- | src/common/logging/filter.cpp | 2 | ||||
| -rw-r--r-- | src/common/logging/types.h | 202 | ||||
| -rw-r--r-- | src/common/overflow.h | 22 | ||||
| -rw-r--r-- | src/common/settings.h | 10 | ||||
| -rw-r--r-- | src/common/steady_clock.cpp | 81 | ||||
| -rw-r--r-- | src/common/steady_clock.h | 34 | ||||
| -rw-r--r-- | src/common/swap.h | 12 | ||||
| -rw-r--r-- | src/common/wall_clock.cpp | 39 | ||||
| -rw-r--r-- | src/common/wall_clock.h | 3 | ||||
| -rw-r--r-- | src/common/windows/timer_resolution.cpp | 109 | ||||
| -rw-r--r-- | src/common/windows/timer_resolution.h | 38 | ||||
| -rw-r--r-- | src/common/x64/native_clock.cpp | 51 | ||||
| -rw-r--r-- | src/common/x64/native_clock.h | 5 |
20 files changed, 494 insertions, 165 deletions
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 56b247ac4..61ab68864 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt | |||
| @@ -91,6 +91,7 @@ add_library(common STATIC | |||
| 91 | multi_level_page_table.h | 91 | multi_level_page_table.h |
| 92 | nvidia_flags.cpp | 92 | nvidia_flags.cpp |
| 93 | nvidia_flags.h | 93 | nvidia_flags.h |
| 94 | overflow.h | ||
| 94 | page_table.cpp | 95 | page_table.cpp |
| 95 | page_table.h | 96 | page_table.h |
| 96 | param_package.cpp | 97 | param_package.cpp |
| @@ -113,6 +114,8 @@ add_library(common STATIC | |||
| 113 | socket_types.h | 114 | socket_types.h |
| 114 | spin_lock.cpp | 115 | spin_lock.cpp |
| 115 | spin_lock.h | 116 | spin_lock.h |
| 117 | steady_clock.cpp | ||
| 118 | steady_clock.h | ||
| 116 | stream.cpp | 119 | stream.cpp |
| 117 | stream.h | 120 | stream.h |
| 118 | string_util.cpp | 121 | string_util.cpp |
| @@ -142,6 +145,14 @@ add_library(common STATIC | |||
| 142 | zstd_compression.h | 145 | zstd_compression.h |
| 143 | ) | 146 | ) |
| 144 | 147 | ||
| 148 | if (WIN32) | ||
| 149 | target_sources(common PRIVATE | ||
| 150 | windows/timer_resolution.cpp | ||
| 151 | windows/timer_resolution.h | ||
| 152 | ) | ||
| 153 | target_link_libraries(common PRIVATE ntdll) | ||
| 154 | endif() | ||
| 155 | |||
| 145 | if(ARCHITECTURE_x86_64) | 156 | if(ARCHITECTURE_x86_64) |
| 146 | target_sources(common | 157 | target_sources(common |
| 147 | PRIVATE | 158 | PRIVATE |
diff --git a/src/common/announce_multiplayer_room.h b/src/common/announce_multiplayer_room.h index 4a3100fa4..f32060196 100644 --- a/src/common/announce_multiplayer_room.h +++ b/src/common/announce_multiplayer_room.h | |||
| @@ -66,7 +66,7 @@ public: | |||
| 66 | * @param description The room description | 66 | * @param description The room description |
| 67 | * @param port The port of the room | 67 | * @param port The port of the room |
| 68 | * @param net_version The version of the libNetwork that gets used | 68 | * @param net_version The version of the libNetwork that gets used |
| 69 | * @param has_password True if the room is passowrd protected | 69 | * @param has_password True if the room is password protected |
| 70 | * @param preferred_game The preferred game of the room | 70 | * @param preferred_game The preferred game of the room |
| 71 | * @param preferred_game_id The title id of the preferred game | 71 | * @param preferred_game_id The title id of the preferred game |
| 72 | */ | 72 | */ |
diff --git a/src/common/bit_cast.h b/src/common/bit_cast.h index 535148b4d..c6110c542 100644 --- a/src/common/bit_cast.h +++ b/src/common/bit_cast.h | |||
| @@ -3,19 +3,21 @@ | |||
| 3 | 3 | ||
| 4 | #pragma once | 4 | #pragma once |
| 5 | 5 | ||
| 6 | #include <cstring> | 6 | #include <version> |
| 7 | #include <type_traits> | 7 | |
| 8 | #ifdef __cpp_lib_bit_cast | ||
| 9 | #include <bit> | ||
| 10 | #endif | ||
| 8 | 11 | ||
| 9 | namespace Common { | 12 | namespace Common { |
| 10 | 13 | ||
| 11 | template <typename To, typename From> | 14 | template <typename To, typename From> |
| 12 | [[nodiscard]] std::enable_if_t<sizeof(To) == sizeof(From) && std::is_trivially_copyable_v<From> && | 15 | constexpr inline To BitCast(const From& from) { |
| 13 | std::is_trivially_copyable_v<To>, | 16 | #ifdef __cpp_lib_bit_cast |
| 14 | To> | 17 | return std::bit_cast<To>(from); |
| 15 | BitCast(const From& src) noexcept { | 18 | #else |
| 16 | To dst; | 19 | return __builtin_bit_cast(To, from); |
| 17 | std::memcpy(&dst, &src, sizeof(To)); | 20 | #endif |
| 18 | return dst; | ||
| 19 | } | 21 | } |
| 20 | 22 | ||
| 21 | } // namespace Common | 23 | } // namespace Common |
diff --git a/src/common/fiber.cpp b/src/common/fiber.cpp index bc92b360b..c991b7cf1 100644 --- a/src/common/fiber.cpp +++ b/src/common/fiber.cpp | |||
| @@ -90,7 +90,7 @@ Fiber::~Fiber() { | |||
| 90 | } | 90 | } |
| 91 | 91 | ||
| 92 | void Fiber::Exit() { | 92 | void Fiber::Exit() { |
| 93 | ASSERT_MSG(impl->is_thread_fiber, "Exitting non main thread fiber"); | 93 | ASSERT_MSG(impl->is_thread_fiber, "Exiting non main thread fiber"); |
| 94 | if (!impl->is_thread_fiber) { | 94 | if (!impl->is_thread_fiber) { |
| 95 | return; | 95 | return; |
| 96 | } | 96 | } |
diff --git a/src/common/fixed_point.h b/src/common/fixed_point.h index f899b0d54..b0f3ae2cc 100644 --- a/src/common/fixed_point.h +++ b/src/common/fixed_point.h | |||
| @@ -22,7 +22,7 @@ class FixedPoint; | |||
| 22 | namespace detail { | 22 | namespace detail { |
| 23 | 23 | ||
| 24 | // helper templates to make magic with types :) | 24 | // helper templates to make magic with types :) |
| 25 | // these allow us to determine resonable types from | 25 | // these allow us to determine reasonable types from |
| 26 | // a desired size, they also let us infer the next largest type | 26 | // a desired size, they also let us infer the next largest type |
| 27 | // from a type which is nice for the division op | 27 | // from a type which is nice for the division op |
| 28 | template <size_t T> | 28 | template <size_t T> |
diff --git a/src/common/host_memory.cpp b/src/common/host_memory.cpp index 611c7d1a3..8e4f1f97a 100644 --- a/src/common/host_memory.cpp +++ b/src/common/host_memory.cpp | |||
| @@ -322,7 +322,7 @@ private: | |||
| 322 | } | 322 | } |
| 323 | 323 | ||
| 324 | /// Return true when a given memory region is a "nieche" and the placeholders don't have to be | 324 | /// Return true when a given memory region is a "nieche" and the placeholders don't have to be |
| 325 | /// splitted. | 325 | /// split. |
| 326 | bool IsNiechePlaceholder(size_t virtual_offset, size_t length) const { | 326 | bool IsNiechePlaceholder(size_t virtual_offset, size_t length) const { |
| 327 | const auto it = placeholders.upper_bound({virtual_offset, virtual_offset + length}); | 327 | const auto it = placeholders.upper_bound({virtual_offset, virtual_offset + length}); |
| 328 | if (it != placeholders.end() && it->lower() == virtual_offset + length) { | 328 | if (it != placeholders.end() && it->lower() == virtual_offset + length) { |
| @@ -484,7 +484,7 @@ class HostMemory::Impl { | |||
| 484 | public: | 484 | public: |
| 485 | explicit Impl(size_t /*backing_size */, size_t /* virtual_size */) { | 485 | explicit Impl(size_t /*backing_size */, size_t /* virtual_size */) { |
| 486 | // This is just a place holder. | 486 | // This is just a place holder. |
| 487 | // Please implement fastmem in a propper way on your platform. | 487 | // Please implement fastmem in a proper way on your platform. |
| 488 | throw std::bad_alloc{}; | 488 | throw std::bad_alloc{}; |
| 489 | } | 489 | } |
| 490 | 490 | ||
diff --git a/src/common/input.h b/src/common/input.h index b5748a6c8..51b277c1f 100644 --- a/src/common/input.h +++ b/src/common/input.h | |||
| @@ -15,7 +15,7 @@ | |||
| 15 | 15 | ||
| 16 | namespace Common::Input { | 16 | namespace Common::Input { |
| 17 | 17 | ||
| 18 | // Type of data that is expected to recieve or send | 18 | // Type of data that is expected to receive or send |
| 19 | enum class InputType { | 19 | enum class InputType { |
| 20 | None, | 20 | None, |
| 21 | Battery, | 21 | Battery, |
| @@ -46,7 +46,7 @@ enum class PollingMode { | |||
| 46 | // Constant polling of buttons, analogs and motion data | 46 | // Constant polling of buttons, analogs and motion data |
| 47 | Active, | 47 | Active, |
| 48 | // Only update on button change, digital analogs | 48 | // Only update on button change, digital analogs |
| 49 | Pasive, | 49 | Passive, |
| 50 | // Enable near field communication polling | 50 | // Enable near field communication polling |
| 51 | NFC, | 51 | NFC, |
| 52 | // Enable infrared camera polling | 52 | // Enable infrared camera polling |
| @@ -103,7 +103,7 @@ enum class VibrationAmplificationType { | |||
| 103 | struct AnalogProperties { | 103 | struct AnalogProperties { |
| 104 | // Anything below this value will be detected as zero | 104 | // Anything below this value will be detected as zero |
| 105 | float deadzone{}; | 105 | float deadzone{}; |
| 106 | // Anyting above this values will be detected as one | 106 | // Anything above this values will be detected as one |
| 107 | float range{1.0f}; | 107 | float range{1.0f}; |
| 108 | // Minimum value to be detected as active | 108 | // Minimum value to be detected as active |
| 109 | float threshold{0.5f}; | 109 | float threshold{0.5f}; |
| @@ -209,7 +209,7 @@ struct LedStatus { | |||
| 209 | bool led_4{}; | 209 | bool led_4{}; |
| 210 | }; | 210 | }; |
| 211 | 211 | ||
| 212 | // Raw data fom camera | 212 | // Raw data from camera |
| 213 | struct CameraStatus { | 213 | struct CameraStatus { |
| 214 | CameraFormat format{CameraFormat::None}; | 214 | CameraFormat format{CameraFormat::None}; |
| 215 | std::vector<u8> data{}; | 215 | std::vector<u8> data{}; |
| @@ -428,7 +428,7 @@ inline void UnregisterOutputFactory(const std::string& name) { | |||
| 428 | } | 428 | } |
| 429 | 429 | ||
| 430 | /** | 430 | /** |
| 431 | * Create an input device from given paramters. | 431 | * Create an input device from given parameters. |
| 432 | * @tparam InputDeviceType the type of input devices to create | 432 | * @tparam InputDeviceType the type of input devices to create |
| 433 | * @param params a serialized ParamPackage string that contains all parameters for creating the | 433 | * @param params a serialized ParamPackage string that contains all parameters for creating the |
| 434 | * device | 434 | * device |
diff --git a/src/common/logging/filter.cpp b/src/common/logging/filter.cpp index a959acb74..c95909561 100644 --- a/src/common/logging/filter.cpp +++ b/src/common/logging/filter.cpp | |||
| @@ -119,7 +119,7 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) { | |||
| 119 | SUB(Service, NPNS) \ | 119 | SUB(Service, NPNS) \ |
| 120 | SUB(Service, NS) \ | 120 | SUB(Service, NS) \ |
| 121 | SUB(Service, NVDRV) \ | 121 | SUB(Service, NVDRV) \ |
| 122 | SUB(Service, NVFlinger) \ | 122 | SUB(Service, Nvnflinger) \ |
| 123 | SUB(Service, OLSC) \ | 123 | SUB(Service, OLSC) \ |
| 124 | SUB(Service, PCIE) \ | 124 | SUB(Service, PCIE) \ |
| 125 | SUB(Service, PCTL) \ | 125 | SUB(Service, PCTL) \ |
diff --git a/src/common/logging/types.h b/src/common/logging/types.h index 595c15ada..8356e3183 100644 --- a/src/common/logging/types.h +++ b/src/common/logging/types.h | |||
| @@ -29,107 +29,107 @@ enum class Level : u8 { | |||
| 29 | * filter.cpp. | 29 | * filter.cpp. |
| 30 | */ | 30 | */ |
| 31 | enum class Class : u8 { | 31 | enum class Class : u8 { |
| 32 | Log, ///< Messages about the log system itself | 32 | Log, ///< Messages about the log system itself |
| 33 | Common, ///< Library routines | 33 | Common, ///< Library routines |
| 34 | Common_Filesystem, ///< Filesystem interface library | 34 | Common_Filesystem, ///< Filesystem interface library |
| 35 | Common_Memory, ///< Memory mapping and management functions | 35 | Common_Memory, ///< Memory mapping and management functions |
| 36 | Core, ///< LLE emulation core | 36 | Core, ///< LLE emulation core |
| 37 | Core_ARM, ///< ARM CPU core | 37 | Core_ARM, ///< ARM CPU core |
| 38 | Core_Timing, ///< CoreTiming functions | 38 | Core_Timing, ///< CoreTiming functions |
| 39 | Config, ///< Emulator configuration (including commandline) | 39 | Config, ///< Emulator configuration (including commandline) |
| 40 | Debug, ///< Debugging tools | 40 | Debug, ///< Debugging tools |
| 41 | Debug_Emulated, ///< Debug messages from the emulated programs | 41 | Debug_Emulated, ///< Debug messages from the emulated programs |
| 42 | Debug_GPU, ///< GPU debugging tools | 42 | Debug_GPU, ///< GPU debugging tools |
| 43 | Debug_Breakpoint, ///< Logging breakpoints and watchpoints | 43 | Debug_Breakpoint, ///< Logging breakpoints and watchpoints |
| 44 | Debug_GDBStub, ///< GDB Stub | 44 | Debug_GDBStub, ///< GDB Stub |
| 45 | Kernel, ///< The HLE implementation of the CTR kernel | 45 | Kernel, ///< The HLE implementation of the CTR kernel |
| 46 | Kernel_SVC, ///< Kernel system calls | 46 | Kernel_SVC, ///< Kernel system calls |
| 47 | Service, ///< HLE implementation of system services. Each major service | 47 | Service, ///< HLE implementation of system services. Each major service |
| 48 | ///< should have its own subclass. | 48 | ///< should have its own subclass. |
| 49 | Service_ACC, ///< The ACC (Accounts) service | 49 | Service_ACC, ///< The ACC (Accounts) service |
| 50 | Service_AM, ///< The AM (Applet manager) service | 50 | Service_AM, ///< The AM (Applet manager) service |
| 51 | Service_AOC, ///< The AOC (AddOn Content) service | 51 | Service_AOC, ///< The AOC (AddOn Content) service |
| 52 | Service_APM, ///< The APM (Performance) service | 52 | Service_APM, ///< The APM (Performance) service |
| 53 | Service_ARP, ///< The ARP service | 53 | Service_ARP, ///< The ARP service |
| 54 | Service_Audio, ///< The Audio (Audio control) service | 54 | Service_Audio, ///< The Audio (Audio control) service |
| 55 | Service_BCAT, ///< The BCAT service | 55 | Service_BCAT, ///< The BCAT service |
| 56 | Service_BGTC, ///< The BGTC (Background Task Controller) service | 56 | Service_BGTC, ///< The BGTC (Background Task Controller) service |
| 57 | Service_BPC, ///< The BPC service | 57 | Service_BPC, ///< The BPC service |
| 58 | Service_BTDRV, ///< The Bluetooth driver service | 58 | Service_BTDRV, ///< The Bluetooth driver service |
| 59 | Service_BTM, ///< The BTM service | 59 | Service_BTM, ///< The BTM service |
| 60 | Service_Capture, ///< The capture service | 60 | Service_Capture, ///< The capture service |
| 61 | Service_ERPT, ///< The error reporting service | 61 | Service_ERPT, ///< The error reporting service |
| 62 | Service_ETicket, ///< The ETicket service | 62 | Service_ETicket, ///< The ETicket service |
| 63 | Service_EUPLD, ///< The error upload service | 63 | Service_EUPLD, ///< The error upload service |
| 64 | Service_Fatal, ///< The Fatal service | 64 | Service_Fatal, ///< The Fatal service |
| 65 | Service_FGM, ///< The FGM service | 65 | Service_FGM, ///< The FGM service |
| 66 | Service_Friend, ///< The friend service | 66 | Service_Friend, ///< The friend service |
| 67 | Service_FS, ///< The FS (Filesystem) service | 67 | Service_FS, ///< The FS (Filesystem) service |
| 68 | Service_GRC, ///< The game recording service | 68 | Service_GRC, ///< The game recording service |
| 69 | Service_HID, ///< The HID (Human interface device) service | 69 | Service_HID, ///< The HID (Human interface device) service |
| 70 | Service_IRS, ///< The IRS service | 70 | Service_IRS, ///< The IRS service |
| 71 | Service_JIT, ///< The JIT service | 71 | Service_JIT, ///< The JIT service |
| 72 | Service_LBL, ///< The LBL (LCD backlight) service | 72 | Service_LBL, ///< The LBL (LCD backlight) service |
| 73 | Service_LDN, ///< The LDN (Local domain network) service | 73 | Service_LDN, ///< The LDN (Local domain network) service |
| 74 | Service_LDR, ///< The loader service | 74 | Service_LDR, ///< The loader service |
| 75 | Service_LM, ///< The LM (Logger) service | 75 | Service_LM, ///< The LM (Logger) service |
| 76 | Service_Migration, ///< The migration service | 76 | Service_Migration, ///< The migration service |
| 77 | Service_Mii, ///< The Mii service | 77 | Service_Mii, ///< The Mii service |
| 78 | Service_MM, ///< The MM (Multimedia) service | 78 | Service_MM, ///< The MM (Multimedia) service |
| 79 | Service_MNPP, ///< The MNPP service | 79 | Service_MNPP, ///< The MNPP service |
| 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_NGCT, ///< The NGCT (No Good Content for Terra) 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 |
| 87 | Service_NPNS, ///< The NPNS service | 87 | Service_NPNS, ///< The NPNS service |
| 88 | Service_NS, ///< The NS services | 88 | Service_NS, ///< The NS services |
| 89 | Service_NVDRV, ///< The NVDRV (Nvidia driver) service | 89 | Service_NVDRV, ///< The NVDRV (Nvidia driver) service |
| 90 | Service_NVFlinger, ///< The NVFlinger service | 90 | Service_Nvnflinger, ///< The Nvnflinger service |
| 91 | Service_OLSC, ///< The OLSC service | 91 | Service_OLSC, ///< The OLSC service |
| 92 | Service_PCIE, ///< The PCIe service | 92 | Service_PCIE, ///< The PCIe service |
| 93 | Service_PCTL, ///< The PCTL (Parental control) service | 93 | Service_PCTL, ///< The PCTL (Parental control) service |
| 94 | Service_PCV, ///< The PCV service | 94 | Service_PCV, ///< The PCV service |
| 95 | Service_PM, ///< The PM service | 95 | Service_PM, ///< The PM service |
| 96 | Service_PREPO, ///< The PREPO (Play report) service | 96 | Service_PREPO, ///< The PREPO (Play report) service |
| 97 | Service_PSC, ///< The PSC service | 97 | Service_PSC, ///< The PSC service |
| 98 | Service_PTM, ///< The PTM service | 98 | Service_PTM, ///< The PTM service |
| 99 | Service_SET, ///< The SET (Settings) service | 99 | Service_SET, ///< The SET (Settings) service |
| 100 | Service_SM, ///< The SM (Service manager) service | 100 | Service_SM, ///< The SM (Service manager) service |
| 101 | Service_SPL, ///< The SPL service | 101 | Service_SPL, ///< The SPL service |
| 102 | Service_SSL, ///< The SSL service | 102 | Service_SSL, ///< The SSL service |
| 103 | Service_TCAP, ///< The TCAP service. | 103 | Service_TCAP, ///< The TCAP service. |
| 104 | Service_Time, ///< The time service | 104 | Service_Time, ///< The time service |
| 105 | Service_USB, ///< The USB (Universal Serial Bus) service | 105 | Service_USB, ///< The USB (Universal Serial Bus) service |
| 106 | Service_VI, ///< The VI (Video interface) service | 106 | Service_VI, ///< The VI (Video interface) service |
| 107 | Service_WLAN, ///< The WLAN (Wireless local area network) service | 107 | Service_WLAN, ///< The WLAN (Wireless local area network) service |
| 108 | HW, ///< Low-level hardware emulation | 108 | HW, ///< Low-level hardware emulation |
| 109 | HW_Memory, ///< Memory-map and address translation | 109 | HW_Memory, ///< Memory-map and address translation |
| 110 | HW_LCD, ///< LCD register emulation | 110 | HW_LCD, ///< LCD register emulation |
| 111 | HW_GPU, ///< GPU control emulation | 111 | HW_GPU, ///< GPU control emulation |
| 112 | HW_AES, ///< AES engine emulation | 112 | HW_AES, ///< AES engine emulation |
| 113 | IPC, ///< IPC interface | 113 | IPC, ///< IPC interface |
| 114 | Frontend, ///< Emulator UI | 114 | Frontend, ///< Emulator UI |
| 115 | Render, ///< Emulator video output and hardware acceleration | 115 | Render, ///< Emulator video output and hardware acceleration |
| 116 | Render_Software, ///< Software renderer backend | 116 | Render_Software, ///< Software renderer backend |
| 117 | Render_OpenGL, ///< OpenGL backend | 117 | Render_OpenGL, ///< OpenGL backend |
| 118 | Render_Vulkan, ///< Vulkan backend | 118 | Render_Vulkan, ///< Vulkan backend |
| 119 | Shader, ///< Shader recompiler | 119 | Shader, ///< Shader recompiler |
| 120 | Shader_SPIRV, ///< Shader SPIR-V code generation | 120 | Shader_SPIRV, ///< Shader SPIR-V code generation |
| 121 | Shader_GLASM, ///< Shader GLASM code generation | 121 | Shader_GLASM, ///< Shader GLASM code generation |
| 122 | Shader_GLSL, ///< Shader GLSL code generation | 122 | Shader_GLSL, ///< Shader GLSL code generation |
| 123 | Audio, ///< Audio emulation | 123 | Audio, ///< Audio emulation |
| 124 | Audio_DSP, ///< The HLE implementation of the DSP | 124 | Audio_DSP, ///< The HLE implementation of the DSP |
| 125 | Audio_Sink, ///< Emulator audio output backend | 125 | Audio_Sink, ///< Emulator audio output backend |
| 126 | Loader, ///< ROM loader | 126 | Loader, ///< ROM loader |
| 127 | CheatEngine, ///< Memory manipulation and engine VM functions | 127 | CheatEngine, ///< Memory manipulation and engine VM functions |
| 128 | Crypto, ///< Cryptographic engine/functions | 128 | Crypto, ///< Cryptographic engine/functions |
| 129 | Input, ///< Input emulation | 129 | Input, ///< Input emulation |
| 130 | Network, ///< Network emulation | 130 | Network, ///< Network emulation |
| 131 | WebService, ///< Interface to yuzu Web Services | 131 | WebService, ///< Interface to yuzu Web Services |
| 132 | Count ///< Total number of logging classes | 132 | Count ///< Total number of logging classes |
| 133 | }; | 133 | }; |
| 134 | 134 | ||
| 135 | } // namespace Common::Log | 135 | } // namespace Common::Log |
diff --git a/src/common/overflow.h b/src/common/overflow.h new file mode 100644 index 000000000..44d8e7e73 --- /dev/null +++ b/src/common/overflow.h | |||
| @@ -0,0 +1,22 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <type_traits> | ||
| 7 | #include "bit_cast.h" | ||
| 8 | |||
| 9 | namespace Common { | ||
| 10 | |||
| 11 | template <typename T> | ||
| 12 | requires(std::is_integral_v<T> && std::is_signed_v<T>) | ||
| 13 | inline T WrappingAdd(T lhs, T rhs) { | ||
| 14 | using U = std::make_unsigned_t<T>; | ||
| 15 | |||
| 16 | U lhs_u = BitCast<U>(lhs); | ||
| 17 | U rhs_u = BitCast<U>(rhs); | ||
| 18 | |||
| 19 | return BitCast<T>(lhs_u + rhs_u); | ||
| 20 | } | ||
| 21 | |||
| 22 | } // namespace Common | ||
diff --git a/src/common/settings.h b/src/common/settings.h index 512ecff69..b77a1580a 100644 --- a/src/common/settings.h +++ b/src/common/settings.h | |||
| @@ -128,7 +128,7 @@ public: | |||
| 128 | /** | 128 | /** |
| 129 | * Sets a default value, label, and setting value. | 129 | * Sets a default value, label, and setting value. |
| 130 | * | 130 | * |
| 131 | * @param default_val Intial value of the setting, and default value of the setting | 131 | * @param default_val Initial value of the setting, and default value of the setting |
| 132 | * @param name Label for the setting | 132 | * @param name Label for the setting |
| 133 | */ | 133 | */ |
| 134 | explicit Setting(const Type& default_val, const std::string& name) | 134 | explicit Setting(const Type& default_val, const std::string& name) |
| @@ -139,7 +139,7 @@ public: | |||
| 139 | /** | 139 | /** |
| 140 | * Sets a default value, minimum value, maximum value, and label. | 140 | * Sets a default value, minimum value, maximum value, and label. |
| 141 | * | 141 | * |
| 142 | * @param default_val Intial value of the setting, and default value of the setting | 142 | * @param default_val Initial value of the setting, and default value of the setting |
| 143 | * @param min_val Sets the minimum allowed value of the setting | 143 | * @param min_val Sets the minimum allowed value of the setting |
| 144 | * @param max_val Sets the maximum allowed value of the setting | 144 | * @param max_val Sets the maximum allowed value of the setting |
| 145 | * @param name Label for the setting | 145 | * @param name Label for the setting |
| @@ -231,7 +231,7 @@ public: | |||
| 231 | /** | 231 | /** |
| 232 | * Sets a default value, label, and setting value. | 232 | * Sets a default value, label, and setting value. |
| 233 | * | 233 | * |
| 234 | * @param default_val Intial value of the setting, and default value of the setting | 234 | * @param default_val Initial value of the setting, and default value of the setting |
| 235 | * @param name Label for the setting | 235 | * @param name Label for the setting |
| 236 | */ | 236 | */ |
| 237 | explicit SwitchableSetting(const Type& default_val, const std::string& name) | 237 | explicit SwitchableSetting(const Type& default_val, const std::string& name) |
| @@ -242,7 +242,7 @@ public: | |||
| 242 | /** | 242 | /** |
| 243 | * Sets a default value, minimum value, maximum value, and label. | 243 | * Sets a default value, minimum value, maximum value, and label. |
| 244 | * | 244 | * |
| 245 | * @param default_val Intial value of the setting, and default value of the setting | 245 | * @param default_val Initial value of the setting, and default value of the setting |
| 246 | * @param min_val Sets the minimum allowed value of the setting | 246 | * @param min_val Sets the minimum allowed value of the setting |
| 247 | * @param max_val Sets the maximum allowed value of the setting | 247 | * @param max_val Sets the maximum allowed value of the setting |
| 248 | * @param name Label for the setting | 248 | * @param name Label for the setting |
| @@ -503,7 +503,7 @@ struct Values { | |||
| 503 | Setting<bool> tas_loop{false, "tas_loop"}; | 503 | Setting<bool> tas_loop{false, "tas_loop"}; |
| 504 | 504 | ||
| 505 | Setting<bool> mouse_panning{false, "mouse_panning"}; | 505 | Setting<bool> mouse_panning{false, "mouse_panning"}; |
| 506 | Setting<u8, true> mouse_panning_sensitivity{10, 1, 100, "mouse_panning_sensitivity"}; | 506 | Setting<u8, true> mouse_panning_sensitivity{50, 1, 100, "mouse_panning_sensitivity"}; |
| 507 | Setting<bool> mouse_enabled{false, "mouse_enabled"}; | 507 | Setting<bool> mouse_enabled{false, "mouse_enabled"}; |
| 508 | 508 | ||
| 509 | Setting<bool> emulate_analog_keyboard{false, "emulate_analog_keyboard"}; | 509 | Setting<bool> emulate_analog_keyboard{false, "emulate_analog_keyboard"}; |
diff --git a/src/common/steady_clock.cpp b/src/common/steady_clock.cpp new file mode 100644 index 000000000..782859196 --- /dev/null +++ b/src/common/steady_clock.cpp | |||
| @@ -0,0 +1,81 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #if defined(_WIN32) | ||
| 5 | #include <windows.h> | ||
| 6 | #else | ||
| 7 | #include <time.h> | ||
| 8 | #endif | ||
| 9 | |||
| 10 | #include "common/steady_clock.h" | ||
| 11 | |||
| 12 | namespace Common { | ||
| 13 | |||
| 14 | #ifdef _WIN32 | ||
| 15 | static s64 WindowsQueryPerformanceFrequency() { | ||
| 16 | LARGE_INTEGER frequency; | ||
| 17 | QueryPerformanceFrequency(&frequency); | ||
| 18 | return frequency.QuadPart; | ||
| 19 | } | ||
| 20 | |||
| 21 | static s64 WindowsQueryPerformanceCounter() { | ||
| 22 | LARGE_INTEGER counter; | ||
| 23 | QueryPerformanceCounter(&counter); | ||
| 24 | return counter.QuadPart; | ||
| 25 | } | ||
| 26 | |||
| 27 | static s64 GetSystemTimeNS() { | ||
| 28 | // GetSystemTimePreciseAsFileTime returns the file time in 100ns units. | ||
| 29 | static constexpr s64 Multiplier = 100; | ||
| 30 | // Convert Windows epoch to Unix epoch. | ||
| 31 | static constexpr s64 WindowsEpochToUnixEpochNS = 0x19DB1DED53E8000LL; | ||
| 32 | |||
| 33 | FILETIME filetime; | ||
| 34 | GetSystemTimePreciseAsFileTime(&filetime); | ||
| 35 | return Multiplier * ((static_cast<s64>(filetime.dwHighDateTime) << 32) + | ||
| 36 | static_cast<s64>(filetime.dwLowDateTime)) - | ||
| 37 | WindowsEpochToUnixEpochNS; | ||
| 38 | } | ||
| 39 | #endif | ||
| 40 | |||
| 41 | SteadyClock::time_point SteadyClock::Now() noexcept { | ||
| 42 | #if defined(_WIN32) | ||
| 43 | static const auto freq = WindowsQueryPerformanceFrequency(); | ||
| 44 | const auto counter = WindowsQueryPerformanceCounter(); | ||
| 45 | |||
| 46 | // 10 MHz is a very common QPC frequency on modern PCs. | ||
| 47 | // Optimizing for this specific frequency can double the performance of | ||
| 48 | // this function by avoiding the expensive frequency conversion path. | ||
| 49 | static constexpr s64 TenMHz = 10'000'000; | ||
| 50 | |||
| 51 | if (freq == TenMHz) [[likely]] { | ||
| 52 | static_assert(period::den % TenMHz == 0); | ||
| 53 | static constexpr s64 Multiplier = period::den / TenMHz; | ||
| 54 | return time_point{duration{counter * Multiplier}}; | ||
| 55 | } | ||
| 56 | |||
| 57 | const auto whole = (counter / freq) * period::den; | ||
| 58 | const auto part = (counter % freq) * period::den / freq; | ||
| 59 | return time_point{duration{whole + part}}; | ||
| 60 | #elif defined(__APPLE__) | ||
| 61 | return time_point{duration{clock_gettime_nsec_np(CLOCK_MONOTONIC_RAW)}}; | ||
| 62 | #else | ||
| 63 | timespec ts; | ||
| 64 | clock_gettime(CLOCK_MONOTONIC, &ts); | ||
| 65 | return time_point{std::chrono::seconds{ts.tv_sec} + std::chrono::nanoseconds{ts.tv_nsec}}; | ||
| 66 | #endif | ||
| 67 | } | ||
| 68 | |||
| 69 | RealTimeClock::time_point RealTimeClock::Now() noexcept { | ||
| 70 | #if defined(_WIN32) | ||
| 71 | return time_point{duration{GetSystemTimeNS()}}; | ||
| 72 | #elif defined(__APPLE__) | ||
| 73 | return time_point{duration{clock_gettime_nsec_np(CLOCK_REALTIME)}}; | ||
| 74 | #else | ||
| 75 | timespec ts; | ||
| 76 | clock_gettime(CLOCK_REALTIME, &ts); | ||
| 77 | return time_point{std::chrono::seconds{ts.tv_sec} + std::chrono::nanoseconds{ts.tv_nsec}}; | ||
| 78 | #endif | ||
| 79 | } | ||
| 80 | |||
| 81 | }; // namespace Common | ||
diff --git a/src/common/steady_clock.h b/src/common/steady_clock.h new file mode 100644 index 000000000..dbd0e2513 --- /dev/null +++ b/src/common/steady_clock.h | |||
| @@ -0,0 +1,34 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <chrono> | ||
| 7 | |||
| 8 | #include "common/common_types.h" | ||
| 9 | |||
| 10 | namespace Common { | ||
| 11 | |||
| 12 | struct SteadyClock { | ||
| 13 | using rep = s64; | ||
| 14 | using period = std::nano; | ||
| 15 | using duration = std::chrono::nanoseconds; | ||
| 16 | using time_point = std::chrono::time_point<SteadyClock>; | ||
| 17 | |||
| 18 | static constexpr bool is_steady = true; | ||
| 19 | |||
| 20 | [[nodiscard]] static time_point Now() noexcept; | ||
| 21 | }; | ||
| 22 | |||
| 23 | struct RealTimeClock { | ||
| 24 | using rep = s64; | ||
| 25 | using period = std::nano; | ||
| 26 | using duration = std::chrono::nanoseconds; | ||
| 27 | using time_point = std::chrono::time_point<RealTimeClock>; | ||
| 28 | |||
| 29 | static constexpr bool is_steady = false; | ||
| 30 | |||
| 31 | [[nodiscard]] static time_point Now() noexcept; | ||
| 32 | }; | ||
| 33 | |||
| 34 | } // namespace Common | ||
diff --git a/src/common/swap.h b/src/common/swap.h index 037b82781..085baaf9a 100644 --- a/src/common/swap.h +++ b/src/common/swap.h | |||
| @@ -229,7 +229,7 @@ public: | |||
| 229 | value = swap(swap() - 1); | 229 | value = swap(swap() - 1); |
| 230 | return old; | 230 | return old; |
| 231 | } | 231 | } |
| 232 | // Comparaison | 232 | // Comparison |
| 233 | // v == i | 233 | // v == i |
| 234 | bool operator==(const swapped_t& i) const { | 234 | bool operator==(const swapped_t& i) const { |
| 235 | return swap() == i.swap(); | 235 | return swap() == i.swap(); |
| @@ -368,7 +368,7 @@ public: | |||
| 368 | // Member | 368 | // Member |
| 369 | /** todo **/ | 369 | /** todo **/ |
| 370 | 370 | ||
| 371 | // Arithmetics | 371 | // Arithmetic |
| 372 | template <typename S, typename T2, typename F2> | 372 | template <typename S, typename T2, typename F2> |
| 373 | friend S operator+(const S& p, const swapped_t v); | 373 | friend S operator+(const S& p, const swapped_t v); |
| 374 | 374 | ||
| @@ -384,7 +384,7 @@ public: | |||
| 384 | template <typename S, typename T2, typename F2> | 384 | template <typename S, typename T2, typename F2> |
| 385 | friend S operator%(const S& p, const swapped_t v); | 385 | friend S operator%(const S& p, const swapped_t v); |
| 386 | 386 | ||
| 387 | // Arithmetics + assignments | 387 | // Arithmetic + assignments |
| 388 | template <typename S, typename T2, typename F2> | 388 | template <typename S, typename T2, typename F2> |
| 389 | friend S operator+=(const S& p, const swapped_t v); | 389 | friend S operator+=(const S& p, const swapped_t v); |
| 390 | 390 | ||
| @@ -415,7 +415,7 @@ public: | |||
| 415 | friend bool operator==(const S& p, const swapped_t v); | 415 | friend bool operator==(const S& p, const swapped_t v); |
| 416 | }; | 416 | }; |
| 417 | 417 | ||
| 418 | // Arithmetics | 418 | // Arithmetic |
| 419 | template <typename S, typename T, typename F> | 419 | template <typename S, typename T, typename F> |
| 420 | S operator+(const S& i, const swap_struct_t<T, F> v) { | 420 | S operator+(const S& i, const swap_struct_t<T, F> v) { |
| 421 | return i + v.swap(); | 421 | return i + v.swap(); |
| @@ -441,7 +441,7 @@ S operator%(const S& i, const swap_struct_t<T, F> v) { | |||
| 441 | return i % v.swap(); | 441 | return i % v.swap(); |
| 442 | } | 442 | } |
| 443 | 443 | ||
| 444 | // Arithmetics + assignments | 444 | // Arithmetic + assignments |
| 445 | template <typename S, typename T, typename F> | 445 | template <typename S, typename T, typename F> |
| 446 | S& operator+=(S& i, const swap_struct_t<T, F> v) { | 446 | S& operator+=(S& i, const swap_struct_t<T, F> v) { |
| 447 | i += v.swap(); | 447 | i += v.swap(); |
| @@ -465,7 +465,7 @@ S operator&(const swap_struct_t<T, F> v, const S& i) { | |||
| 465 | return static_cast<S>(v.swap() & i); | 465 | return static_cast<S>(v.swap() & i); |
| 466 | } | 466 | } |
| 467 | 467 | ||
| 468 | // Comparaison | 468 | // Comparison |
| 469 | template <typename S, typename T, typename F> | 469 | template <typename S, typename T, typename F> |
| 470 | bool operator<(const S& p, const swap_struct_t<T, F> v) { | 470 | bool operator<(const S& p, const swap_struct_t<T, F> v) { |
| 471 | return p < v.swap(); | 471 | return p < v.swap(); |
diff --git a/src/common/wall_clock.cpp b/src/common/wall_clock.cpp index ae07f2811..817e71d52 100644 --- a/src/common/wall_clock.cpp +++ b/src/common/wall_clock.cpp | |||
| @@ -1,6 +1,7 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project | 1 | // SPDX-FileCopyrightText: Copyright 2020 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 "common/steady_clock.h" | ||
| 4 | #include "common/uint128.h" | 5 | #include "common/uint128.h" |
| 5 | #include "common/wall_clock.h" | 6 | #include "common/wall_clock.h" |
| 6 | 7 | ||
| @@ -11,45 +12,32 @@ | |||
| 11 | 12 | ||
| 12 | namespace Common { | 13 | namespace Common { |
| 13 | 14 | ||
| 14 | using base_timer = std::chrono::steady_clock; | ||
| 15 | using base_time_point = std::chrono::time_point<base_timer>; | ||
| 16 | |||
| 17 | class StandardWallClock final : public WallClock { | 15 | class StandardWallClock final : public WallClock { |
| 18 | public: | 16 | public: |
| 19 | explicit StandardWallClock(u64 emulated_cpu_frequency_, u64 emulated_clock_frequency_) | 17 | explicit StandardWallClock(u64 emulated_cpu_frequency_, u64 emulated_clock_frequency_) |
| 20 | : WallClock(emulated_cpu_frequency_, emulated_clock_frequency_, false) { | 18 | : WallClock{emulated_cpu_frequency_, emulated_clock_frequency_, false}, |
| 21 | start_time = base_timer::now(); | 19 | start_time{SteadyClock::Now()} {} |
| 22 | } | ||
| 23 | 20 | ||
| 24 | std::chrono::nanoseconds GetTimeNS() override { | 21 | std::chrono::nanoseconds GetTimeNS() override { |
| 25 | base_time_point current = base_timer::now(); | 22 | return SteadyClock::Now() - start_time; |
| 26 | auto elapsed = current - start_time; | ||
| 27 | return std::chrono::duration_cast<std::chrono::nanoseconds>(elapsed); | ||
| 28 | } | 23 | } |
| 29 | 24 | ||
| 30 | std::chrono::microseconds GetTimeUS() override { | 25 | std::chrono::microseconds GetTimeUS() override { |
| 31 | base_time_point current = base_timer::now(); | 26 | return std::chrono::duration_cast<std::chrono::microseconds>(GetTimeNS()); |
| 32 | auto elapsed = current - start_time; | ||
| 33 | return std::chrono::duration_cast<std::chrono::microseconds>(elapsed); | ||
| 34 | } | 27 | } |
| 35 | 28 | ||
| 36 | std::chrono::milliseconds GetTimeMS() override { | 29 | std::chrono::milliseconds GetTimeMS() override { |
| 37 | base_time_point current = base_timer::now(); | 30 | return std::chrono::duration_cast<std::chrono::milliseconds>(GetTimeNS()); |
| 38 | auto elapsed = current - start_time; | ||
| 39 | return std::chrono::duration_cast<std::chrono::milliseconds>(elapsed); | ||
| 40 | } | 31 | } |
| 41 | 32 | ||
| 42 | u64 GetClockCycles() override { | 33 | u64 GetClockCycles() override { |
| 43 | std::chrono::nanoseconds time_now = GetTimeNS(); | 34 | const u128 temp = Common::Multiply64Into128(GetTimeNS().count(), emulated_clock_frequency); |
| 44 | const u128 temporary = | 35 | return Common::Divide128On32(temp, NS_RATIO).first; |
| 45 | Common::Multiply64Into128(time_now.count(), emulated_clock_frequency); | ||
| 46 | return Common::Divide128On32(temporary, 1000000000).first; | ||
| 47 | } | 36 | } |
| 48 | 37 | ||
| 49 | u64 GetCPUCycles() override { | 38 | u64 GetCPUCycles() override { |
| 50 | std::chrono::nanoseconds time_now = GetTimeNS(); | 39 | const u128 temp = Common::Multiply64Into128(GetTimeNS().count(), emulated_cpu_frequency); |
| 51 | const u128 temporary = Common::Multiply64Into128(time_now.count(), emulated_cpu_frequency); | 40 | return Common::Divide128On32(temp, NS_RATIO).first; |
| 52 | return Common::Divide128On32(temporary, 1000000000).first; | ||
| 53 | } | 41 | } |
| 54 | 42 | ||
| 55 | void Pause([[maybe_unused]] bool is_paused) override { | 43 | void Pause([[maybe_unused]] bool is_paused) override { |
| @@ -57,7 +45,7 @@ public: | |||
| 57 | } | 45 | } |
| 58 | 46 | ||
| 59 | private: | 47 | private: |
| 60 | base_time_point start_time; | 48 | SteadyClock::time_point start_time; |
| 61 | }; | 49 | }; |
| 62 | 50 | ||
| 63 | #ifdef ARCHITECTURE_x86_64 | 51 | #ifdef ARCHITECTURE_x86_64 |
| @@ -93,4 +81,9 @@ std::unique_ptr<WallClock> CreateBestMatchingClock(u64 emulated_cpu_frequency, | |||
| 93 | 81 | ||
| 94 | #endif | 82 | #endif |
| 95 | 83 | ||
| 84 | std::unique_ptr<WallClock> CreateStandardWallClock(u64 emulated_cpu_frequency, | ||
| 85 | u64 emulated_clock_frequency) { | ||
| 86 | return std::make_unique<StandardWallClock>(emulated_cpu_frequency, emulated_clock_frequency); | ||
| 87 | } | ||
| 88 | |||
| 96 | } // namespace Common | 89 | } // namespace Common |
diff --git a/src/common/wall_clock.h b/src/common/wall_clock.h index 828a523a8..157ec5eae 100644 --- a/src/common/wall_clock.h +++ b/src/common/wall_clock.h | |||
| @@ -55,4 +55,7 @@ private: | |||
| 55 | [[nodiscard]] std::unique_ptr<WallClock> CreateBestMatchingClock(u64 emulated_cpu_frequency, | 55 | [[nodiscard]] std::unique_ptr<WallClock> CreateBestMatchingClock(u64 emulated_cpu_frequency, |
| 56 | u64 emulated_clock_frequency); | 56 | u64 emulated_clock_frequency); |
| 57 | 57 | ||
| 58 | [[nodiscard]] std::unique_ptr<WallClock> CreateStandardWallClock(u64 emulated_cpu_frequency, | ||
| 59 | u64 emulated_clock_frequency); | ||
| 60 | |||
| 58 | } // namespace Common | 61 | } // namespace Common |
diff --git a/src/common/windows/timer_resolution.cpp b/src/common/windows/timer_resolution.cpp new file mode 100644 index 000000000..29c6e5c7e --- /dev/null +++ b/src/common/windows/timer_resolution.cpp | |||
| @@ -0,0 +1,109 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include <windows.h> | ||
| 5 | |||
| 6 | #include "common/windows/timer_resolution.h" | ||
| 7 | |||
| 8 | extern "C" { | ||
| 9 | // http://undocumented.ntinternals.net/index.html?page=UserMode%2FUndocumented%20Functions%2FTime%2FNtQueryTimerResolution.html | ||
| 10 | NTSYSAPI LONG NTAPI NtQueryTimerResolution(PULONG MinimumResolution, PULONG MaximumResolution, | ||
| 11 | PULONG CurrentResolution); | ||
| 12 | |||
| 13 | // http://undocumented.ntinternals.net/index.html?page=UserMode%2FUndocumented%20Functions%2FTime%2FNtSetTimerResolution.html | ||
| 14 | NTSYSAPI LONG NTAPI NtSetTimerResolution(ULONG DesiredResolution, BOOLEAN SetResolution, | ||
| 15 | PULONG CurrentResolution); | ||
| 16 | |||
| 17 | // http://undocumented.ntinternals.net/index.html?page=UserMode%2FUndocumented%20Functions%2FNT%20Objects%2FThread%2FNtDelayExecution.html | ||
| 18 | NTSYSAPI LONG NTAPI NtDelayExecution(BOOLEAN Alertable, PLARGE_INTEGER DelayInterval); | ||
| 19 | } | ||
| 20 | |||
| 21 | // Defines for compatibility with older Windows 10 SDKs. | ||
| 22 | |||
| 23 | #ifndef PROCESS_POWER_THROTTLING_EXECUTION_SPEED | ||
| 24 | #define PROCESS_POWER_THROTTLING_EXECUTION_SPEED 0x1 | ||
| 25 | #endif | ||
| 26 | #ifndef PROCESS_POWER_THROTTLING_IGNORE_TIMER_RESOLUTION | ||
| 27 | #define PROCESS_POWER_THROTTLING_IGNORE_TIMER_RESOLUTION 0x4 | ||
| 28 | #endif | ||
| 29 | |||
| 30 | namespace Common::Windows { | ||
| 31 | |||
| 32 | namespace { | ||
| 33 | |||
| 34 | using namespace std::chrono; | ||
| 35 | |||
| 36 | constexpr nanoseconds ToNS(ULONG hundred_ns) { | ||
| 37 | return nanoseconds{hundred_ns * 100}; | ||
| 38 | } | ||
| 39 | |||
| 40 | constexpr ULONG ToHundredNS(nanoseconds ns) { | ||
| 41 | return static_cast<ULONG>(ns.count()) / 100; | ||
| 42 | } | ||
| 43 | |||
| 44 | struct TimerResolution { | ||
| 45 | std::chrono::nanoseconds minimum; | ||
| 46 | std::chrono::nanoseconds maximum; | ||
| 47 | std::chrono::nanoseconds current; | ||
| 48 | }; | ||
| 49 | |||
| 50 | TimerResolution GetTimerResolution() { | ||
| 51 | ULONG MinimumTimerResolution; | ||
| 52 | ULONG MaximumTimerResolution; | ||
| 53 | ULONG CurrentTimerResolution; | ||
| 54 | NtQueryTimerResolution(&MinimumTimerResolution, &MaximumTimerResolution, | ||
| 55 | &CurrentTimerResolution); | ||
| 56 | return { | ||
| 57 | .minimum{ToNS(MinimumTimerResolution)}, | ||
| 58 | .maximum{ToNS(MaximumTimerResolution)}, | ||
| 59 | .current{ToNS(CurrentTimerResolution)}, | ||
| 60 | }; | ||
| 61 | } | ||
| 62 | |||
| 63 | void SetHighQoS() { | ||
| 64 | // https://learn.microsoft.com/en-us/windows/win32/procthread/quality-of-service | ||
| 65 | PROCESS_POWER_THROTTLING_STATE PowerThrottling{ | ||
| 66 | .Version{PROCESS_POWER_THROTTLING_CURRENT_VERSION}, | ||
| 67 | .ControlMask{PROCESS_POWER_THROTTLING_EXECUTION_SPEED | | ||
| 68 | PROCESS_POWER_THROTTLING_IGNORE_TIMER_RESOLUTION}, | ||
| 69 | .StateMask{}, | ||
| 70 | }; | ||
| 71 | SetProcessInformation(GetCurrentProcess(), ProcessPowerThrottling, &PowerThrottling, | ||
| 72 | sizeof(PROCESS_POWER_THROTTLING_STATE)); | ||
| 73 | } | ||
| 74 | |||
| 75 | } // Anonymous namespace | ||
| 76 | |||
| 77 | nanoseconds GetMinimumTimerResolution() { | ||
| 78 | return GetTimerResolution().minimum; | ||
| 79 | } | ||
| 80 | |||
| 81 | nanoseconds GetMaximumTimerResolution() { | ||
| 82 | return GetTimerResolution().maximum; | ||
| 83 | } | ||
| 84 | |||
| 85 | nanoseconds GetCurrentTimerResolution() { | ||
| 86 | return GetTimerResolution().current; | ||
| 87 | } | ||
| 88 | |||
| 89 | nanoseconds SetCurrentTimerResolution(nanoseconds timer_resolution) { | ||
| 90 | // Set the timer resolution, and return the current timer resolution. | ||
| 91 | const auto DesiredTimerResolution = ToHundredNS(timer_resolution); | ||
| 92 | ULONG CurrentTimerResolution; | ||
| 93 | NtSetTimerResolution(DesiredTimerResolution, TRUE, &CurrentTimerResolution); | ||
| 94 | return ToNS(CurrentTimerResolution); | ||
| 95 | } | ||
| 96 | |||
| 97 | nanoseconds SetCurrentTimerResolutionToMaximum() { | ||
| 98 | SetHighQoS(); | ||
| 99 | return SetCurrentTimerResolution(GetMaximumTimerResolution()); | ||
| 100 | } | ||
| 101 | |||
| 102 | void SleepForOneTick() { | ||
| 103 | LARGE_INTEGER DelayInterval{ | ||
| 104 | .QuadPart{-1}, | ||
| 105 | }; | ||
| 106 | NtDelayExecution(FALSE, &DelayInterval); | ||
| 107 | } | ||
| 108 | |||
| 109 | } // namespace Common::Windows | ||
diff --git a/src/common/windows/timer_resolution.h b/src/common/windows/timer_resolution.h new file mode 100644 index 000000000..e1e50a62d --- /dev/null +++ b/src/common/windows/timer_resolution.h | |||
| @@ -0,0 +1,38 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <chrono> | ||
| 7 | |||
| 8 | namespace Common::Windows { | ||
| 9 | |||
| 10 | /// Returns the minimum (least precise) supported timer resolution in nanoseconds. | ||
| 11 | std::chrono::nanoseconds GetMinimumTimerResolution(); | ||
| 12 | |||
| 13 | /// Returns the maximum (most precise) supported timer resolution in nanoseconds. | ||
| 14 | std::chrono::nanoseconds GetMaximumTimerResolution(); | ||
| 15 | |||
| 16 | /// Returns the current timer resolution in nanoseconds. | ||
| 17 | std::chrono::nanoseconds GetCurrentTimerResolution(); | ||
| 18 | |||
| 19 | /** | ||
| 20 | * Sets the current timer resolution. | ||
| 21 | * | ||
| 22 | * @param timer_resolution Timer resolution in nanoseconds. | ||
| 23 | * | ||
| 24 | * @returns The current timer resolution. | ||
| 25 | */ | ||
| 26 | std::chrono::nanoseconds SetCurrentTimerResolution(std::chrono::nanoseconds timer_resolution); | ||
| 27 | |||
| 28 | /** | ||
| 29 | * Sets the current timer resolution to the maximum supported timer resolution. | ||
| 30 | * | ||
| 31 | * @returns The current timer resolution. | ||
| 32 | */ | ||
| 33 | std::chrono::nanoseconds SetCurrentTimerResolutionToMaximum(); | ||
| 34 | |||
| 35 | /// Sleep for one tick of the current timer resolution. | ||
| 36 | void SleepForOneTick(); | ||
| 37 | |||
| 38 | } // namespace Common::Windows | ||
diff --git a/src/common/x64/native_clock.cpp b/src/common/x64/native_clock.cpp index 8b08332ab..76c66e7ee 100644 --- a/src/common/x64/native_clock.cpp +++ b/src/common/x64/native_clock.cpp | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | #include <thread> | 6 | #include <thread> |
| 7 | 7 | ||
| 8 | #include "common/atomic_ops.h" | 8 | #include "common/atomic_ops.h" |
| 9 | #include "common/steady_clock.h" | ||
| 9 | #include "common/uint128.h" | 10 | #include "common/uint128.h" |
| 10 | #include "common/x64/native_clock.h" | 11 | #include "common/x64/native_clock.h" |
| 11 | 12 | ||
| @@ -39,6 +40,12 @@ static u64 FencedRDTSC() { | |||
| 39 | } | 40 | } |
| 40 | #endif | 41 | #endif |
| 41 | 42 | ||
| 43 | template <u64 Nearest> | ||
| 44 | static u64 RoundToNearest(u64 value) { | ||
| 45 | const auto mod = value % Nearest; | ||
| 46 | return mod >= (Nearest / 2) ? (value - mod + Nearest) : (value - mod); | ||
| 47 | } | ||
| 48 | |||
| 42 | u64 EstimateRDTSCFrequency() { | 49 | u64 EstimateRDTSCFrequency() { |
| 43 | // Discard the first result measuring the rdtsc. | 50 | // Discard the first result measuring the rdtsc. |
| 44 | FencedRDTSC(); | 51 | FencedRDTSC(); |
| @@ -46,18 +53,18 @@ u64 EstimateRDTSCFrequency() { | |||
| 46 | FencedRDTSC(); | 53 | FencedRDTSC(); |
| 47 | 54 | ||
| 48 | // Get the current time. | 55 | // Get the current time. |
| 49 | const auto start_time = std::chrono::steady_clock::now(); | 56 | const auto start_time = Common::RealTimeClock::Now(); |
| 50 | const u64 tsc_start = FencedRDTSC(); | 57 | const u64 tsc_start = FencedRDTSC(); |
| 51 | // Wait for 200 milliseconds. | 58 | // Wait for 250 milliseconds. |
| 52 | std::this_thread::sleep_for(std::chrono::milliseconds{200}); | 59 | std::this_thread::sleep_for(std::chrono::milliseconds{250}); |
| 53 | const auto end_time = std::chrono::steady_clock::now(); | 60 | const auto end_time = Common::RealTimeClock::Now(); |
| 54 | const u64 tsc_end = FencedRDTSC(); | 61 | const u64 tsc_end = FencedRDTSC(); |
| 55 | // Calculate differences. | 62 | // Calculate differences. |
| 56 | const u64 timer_diff = static_cast<u64>( | 63 | const u64 timer_diff = static_cast<u64>( |
| 57 | std::chrono::duration_cast<std::chrono::nanoseconds>(end_time - start_time).count()); | 64 | std::chrono::duration_cast<std::chrono::nanoseconds>(end_time - start_time).count()); |
| 58 | const u64 tsc_diff = tsc_end - tsc_start; | 65 | const u64 tsc_diff = tsc_end - tsc_start; |
| 59 | const u64 tsc_freq = MultiplyAndDivide64(tsc_diff, 1000000000ULL, timer_diff); | 66 | const u64 tsc_freq = MultiplyAndDivide64(tsc_diff, 1000000000ULL, timer_diff); |
| 60 | return tsc_freq; | 67 | return RoundToNearest<1000>(tsc_freq); |
| 61 | } | 68 | } |
| 62 | 69 | ||
| 63 | namespace X64 { | 70 | namespace X64 { |
| @@ -65,13 +72,29 @@ NativeClock::NativeClock(u64 emulated_cpu_frequency_, u64 emulated_clock_frequen | |||
| 65 | u64 rtsc_frequency_) | 72 | u64 rtsc_frequency_) |
| 66 | : WallClock(emulated_cpu_frequency_, emulated_clock_frequency_, true), rtsc_frequency{ | 73 | : WallClock(emulated_cpu_frequency_, emulated_clock_frequency_, true), rtsc_frequency{ |
| 67 | rtsc_frequency_} { | 74 | rtsc_frequency_} { |
| 75 | // Thread to re-adjust the RDTSC frequency after 10 seconds has elapsed. | ||
| 76 | time_sync_thread = std::jthread{[this](std::stop_token token) { | ||
| 77 | // Get the current time. | ||
| 78 | const auto start_time = Common::RealTimeClock::Now(); | ||
| 79 | const u64 tsc_start = FencedRDTSC(); | ||
| 80 | // Wait for 10 seconds. | ||
| 81 | if (!Common::StoppableTimedWait(token, std::chrono::seconds{10})) { | ||
| 82 | return; | ||
| 83 | } | ||
| 84 | const auto end_time = Common::RealTimeClock::Now(); | ||
| 85 | const u64 tsc_end = FencedRDTSC(); | ||
| 86 | // Calculate differences. | ||
| 87 | const u64 timer_diff = static_cast<u64>( | ||
| 88 | std::chrono::duration_cast<std::chrono::nanoseconds>(end_time - start_time).count()); | ||
| 89 | const u64 tsc_diff = tsc_end - tsc_start; | ||
| 90 | const u64 tsc_freq = MultiplyAndDivide64(tsc_diff, 1000000000ULL, timer_diff); | ||
| 91 | rtsc_frequency = tsc_freq; | ||
| 92 | CalculateAndSetFactors(); | ||
| 93 | }}; | ||
| 94 | |||
| 68 | time_point.inner.last_measure = FencedRDTSC(); | 95 | time_point.inner.last_measure = FencedRDTSC(); |
| 69 | time_point.inner.accumulated_ticks = 0U; | 96 | time_point.inner.accumulated_ticks = 0U; |
| 70 | ns_rtsc_factor = GetFixedPoint64Factor(NS_RATIO, rtsc_frequency); | 97 | CalculateAndSetFactors(); |
| 71 | us_rtsc_factor = GetFixedPoint64Factor(US_RATIO, rtsc_frequency); | ||
| 72 | ms_rtsc_factor = GetFixedPoint64Factor(MS_RATIO, rtsc_frequency); | ||
| 73 | clock_rtsc_factor = GetFixedPoint64Factor(emulated_clock_frequency, rtsc_frequency); | ||
| 74 | cpu_rtsc_factor = GetFixedPoint64Factor(emulated_cpu_frequency, rtsc_frequency); | ||
| 75 | } | 98 | } |
| 76 | 99 | ||
| 77 | u64 NativeClock::GetRTSC() { | 100 | u64 NativeClock::GetRTSC() { |
| @@ -131,6 +154,14 @@ u64 NativeClock::GetCPUCycles() { | |||
| 131 | return MultiplyHigh(rtsc_value, cpu_rtsc_factor); | 154 | return MultiplyHigh(rtsc_value, cpu_rtsc_factor); |
| 132 | } | 155 | } |
| 133 | 156 | ||
| 157 | void NativeClock::CalculateAndSetFactors() { | ||
| 158 | ns_rtsc_factor = GetFixedPoint64Factor(NS_RATIO, rtsc_frequency); | ||
| 159 | us_rtsc_factor = GetFixedPoint64Factor(US_RATIO, rtsc_frequency); | ||
| 160 | ms_rtsc_factor = GetFixedPoint64Factor(MS_RATIO, rtsc_frequency); | ||
| 161 | clock_rtsc_factor = GetFixedPoint64Factor(emulated_clock_frequency, rtsc_frequency); | ||
| 162 | cpu_rtsc_factor = GetFixedPoint64Factor(emulated_cpu_frequency, rtsc_frequency); | ||
| 163 | } | ||
| 164 | |||
| 134 | } // namespace X64 | 165 | } // namespace X64 |
| 135 | 166 | ||
| 136 | } // namespace Common | 167 | } // namespace Common |
diff --git a/src/common/x64/native_clock.h b/src/common/x64/native_clock.h index 38ae7a462..03ca291d8 100644 --- a/src/common/x64/native_clock.h +++ b/src/common/x64/native_clock.h | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | 3 | ||
| 4 | #pragma once | 4 | #pragma once |
| 5 | 5 | ||
| 6 | #include "common/polyfill_thread.h" | ||
| 6 | #include "common/wall_clock.h" | 7 | #include "common/wall_clock.h" |
| 7 | 8 | ||
| 8 | namespace Common { | 9 | namespace Common { |
| @@ -28,6 +29,8 @@ public: | |||
| 28 | private: | 29 | private: |
| 29 | u64 GetRTSC(); | 30 | u64 GetRTSC(); |
| 30 | 31 | ||
| 32 | void CalculateAndSetFactors(); | ||
| 33 | |||
| 31 | union alignas(16) TimePoint { | 34 | union alignas(16) TimePoint { |
| 32 | TimePoint() : pack{} {} | 35 | TimePoint() : pack{} {} |
| 33 | u128 pack{}; | 36 | u128 pack{}; |
| @@ -47,6 +50,8 @@ private: | |||
| 47 | u64 ms_rtsc_factor{}; | 50 | u64 ms_rtsc_factor{}; |
| 48 | 51 | ||
| 49 | u64 rtsc_frequency; | 52 | u64 rtsc_frequency; |
| 53 | |||
| 54 | std::jthread time_sync_thread; | ||
| 50 | }; | 55 | }; |
| 51 | } // namespace X64 | 56 | } // namespace X64 |
| 52 | 57 | ||