summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Morph2023-03-01 19:27:10 -0500
committerGravatar Morph2023-03-05 01:41:28 -0500
commit1ed49f92dd56289e6e31a967e602c65ccedd4ff1 (patch)
treea151df116022445b7606614e31e9b3a3b8225152 /src
parentcommon: Implement a high resolution steady clock (diff)
downloadyuzu-1ed49f92dd56289e6e31a967e602c65ccedd4ff1.tar.gz
yuzu-1ed49f92dd56289e6e31a967e602c65ccedd4ff1.tar.xz
yuzu-1ed49f92dd56289e6e31a967e602c65ccedd4ff1.zip
common: Implement a method to change the Windows timer resolution
This utilizes undocumented NtDll functions to change the current timer resolution from the default of 1ms.
Diffstat (limited to 'src')
-rw-r--r--src/common/CMakeLists.txt8
-rw-r--r--src/common/windows/timer_resolution.cpp87
-rw-r--r--src/common/windows/timer_resolution.h38
3 files changed, 133 insertions, 0 deletions
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index 9f5d4c265..58ff5f2f3 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -144,6 +144,14 @@ add_library(common STATIC
144 zstd_compression.h 144 zstd_compression.h
145) 145)
146 146
147if (WIN32)
148 target_sources(common PRIVATE
149 windows/timer_resolution.cpp
150 windows/timer_resolution.h
151 )
152 target_link_libraries(common PRIVATE ntdll)
153endif()
154
147if(ARCHITECTURE_x86_64) 155if(ARCHITECTURE_x86_64)
148 target_sources(common 156 target_sources(common
149 PRIVATE 157 PRIVATE
diff --git a/src/common/windows/timer_resolution.cpp b/src/common/windows/timer_resolution.cpp
new file mode 100644
index 000000000..6c2063a4c
--- /dev/null
+++ b/src/common/windows/timer_resolution.cpp
@@ -0,0 +1,87 @@
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
8extern "C" {
9// http://undocumented.ntinternals.net/index.html?page=UserMode%2FUndocumented%20Functions%2FTime%2FNtQueryTimerResolution.html
10NTSYSAPI 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
14NTSYSAPI 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
18NTSYSAPI LONG NTAPI NtDelayExecution(BOOLEAN Alertable, PLARGE_INTEGER DelayInterval);
19}
20
21namespace Common::Windows {
22
23namespace {
24
25using namespace std::chrono;
26
27constexpr nanoseconds ToNS(ULONG hundred_ns) {
28 return nanoseconds{hundred_ns * 100};
29}
30
31constexpr ULONG ToHundredNS(nanoseconds ns) {
32 return static_cast<ULONG>(ns.count()) / 100;
33}
34
35struct TimerResolution {
36 std::chrono::nanoseconds minimum;
37 std::chrono::nanoseconds maximum;
38 std::chrono::nanoseconds current;
39};
40
41TimerResolution GetTimerResolution() {
42 ULONG MinimumTimerResolution;
43 ULONG MaximumTimerResolution;
44 ULONG CurrentTimerResolution;
45 NtQueryTimerResolution(&MinimumTimerResolution, &MaximumTimerResolution,
46 &CurrentTimerResolution);
47 return {
48 .minimum{ToNS(MinimumTimerResolution)},
49 .maximum{ToNS(MaximumTimerResolution)},
50 .current{ToNS(CurrentTimerResolution)},
51 };
52}
53
54} // Anonymous namespace
55
56nanoseconds GetMinimumTimerResolution() {
57 return GetTimerResolution().minimum;
58}
59
60nanoseconds GetMaximumTimerResolution() {
61 return GetTimerResolution().maximum;
62}
63
64nanoseconds GetCurrentTimerResolution() {
65 return GetTimerResolution().current;
66}
67
68nanoseconds SetCurrentTimerResolution(nanoseconds timer_resolution) {
69 // Set the timer resolution, and return the current timer resolution.
70 const auto DesiredTimerResolution = ToHundredNS(timer_resolution);
71 ULONG CurrentTimerResolution;
72 NtSetTimerResolution(DesiredTimerResolution, TRUE, &CurrentTimerResolution);
73 return ToNS(CurrentTimerResolution);
74}
75
76nanoseconds SetCurrentTimerResolutionToMaximum() {
77 return SetCurrentTimerResolution(GetMaximumTimerResolution());
78}
79
80void SleepForOneTick() {
81 LARGE_INTEGER DelayInterval{
82 .QuadPart{-1},
83 };
84 NtDelayExecution(FALSE, &DelayInterval);
85}
86
87} // 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
8namespace Common::Windows {
9
10/// Returns the minimum (least precise) supported timer resolution in nanoseconds.
11std::chrono::nanoseconds GetMinimumTimerResolution();
12
13/// Returns the maximum (most precise) supported timer resolution in nanoseconds.
14std::chrono::nanoseconds GetMaximumTimerResolution();
15
16/// Returns the current timer resolution in nanoseconds.
17std::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 */
26std::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 */
33std::chrono::nanoseconds SetCurrentTimerResolutionToMaximum();
34
35/// Sleep for one tick of the current timer resolution.
36void SleepForOneTick();
37
38} // namespace Common::Windows