summaryrefslogtreecommitdiff
path: root/src/common/windows
diff options
context:
space:
mode:
Diffstat (limited to 'src/common/windows')
-rw-r--r--src/common/windows/timer_resolution.cpp109
-rw-r--r--src/common/windows/timer_resolution.h38
2 files changed, 147 insertions, 0 deletions
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
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
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
30namespace Common::Windows {
31
32namespace {
33
34using namespace std::chrono;
35
36constexpr nanoseconds ToNS(ULONG hundred_ns) {
37 return nanoseconds{hundred_ns * 100};
38}
39
40constexpr ULONG ToHundredNS(nanoseconds ns) {
41 return static_cast<ULONG>(ns.count()) / 100;
42}
43
44struct TimerResolution {
45 std::chrono::nanoseconds minimum;
46 std::chrono::nanoseconds maximum;
47 std::chrono::nanoseconds current;
48};
49
50TimerResolution 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
63void 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
77nanoseconds GetMinimumTimerResolution() {
78 return GetTimerResolution().minimum;
79}
80
81nanoseconds GetMaximumTimerResolution() {
82 return GetTimerResolution().maximum;
83}
84
85nanoseconds GetCurrentTimerResolution() {
86 return GetTimerResolution().current;
87}
88
89nanoseconds 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
97nanoseconds SetCurrentTimerResolutionToMaximum() {
98 SetHighQoS();
99 return SetCurrentTimerResolution(GetMaximumTimerResolution());
100}
101
102void 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
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