|
|
@@ -0,0 +1,87 @@
|
|
|
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
|
|
+// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
+
|
|
|
+#include <windows.h>
|
|
|
+
|
|
|
+#include "common/windows/timer_resolution.h"
|
|
|
+
|
|
|
+extern "C" {
|
|
|
+// http://undocumented.ntinternals.net/index.html?page=UserMode%2FUndocumented%20Functions%2FTime%2FNtQueryTimerResolution.html
|
|
|
+NTSYSAPI LONG NTAPI NtQueryTimerResolution(PULONG MinimumResolution, PULONG MaximumResolution,
|
|
|
+ PULONG CurrentResolution);
|
|
|
+
|
|
|
+// http://undocumented.ntinternals.net/index.html?page=UserMode%2FUndocumented%20Functions%2FTime%2FNtSetTimerResolution.html
|
|
|
+NTSYSAPI LONG NTAPI NtSetTimerResolution(ULONG DesiredResolution, BOOLEAN SetResolution,
|
|
|
+ PULONG CurrentResolution);
|
|
|
+
|
|
|
+// http://undocumented.ntinternals.net/index.html?page=UserMode%2FUndocumented%20Functions%2FNT%20Objects%2FThread%2FNtDelayExecution.html
|
|
|
+NTSYSAPI LONG NTAPI NtDelayExecution(BOOLEAN Alertable, PLARGE_INTEGER DelayInterval);
|
|
|
+}
|
|
|
+
|
|
|
+namespace Common::Windows {
|
|
|
+
|
|
|
+namespace {
|
|
|
+
|
|
|
+using namespace std::chrono;
|
|
|
+
|
|
|
+constexpr nanoseconds ToNS(ULONG hundred_ns) {
|
|
|
+ return nanoseconds{hundred_ns * 100};
|
|
|
+}
|
|
|
+
|
|
|
+constexpr ULONG ToHundredNS(nanoseconds ns) {
|
|
|
+ return static_cast<ULONG>(ns.count()) / 100;
|
|
|
+}
|
|
|
+
|
|
|
+struct TimerResolution {
|
|
|
+ std::chrono::nanoseconds minimum;
|
|
|
+ std::chrono::nanoseconds maximum;
|
|
|
+ std::chrono::nanoseconds current;
|
|
|
+};
|
|
|
+
|
|
|
+TimerResolution GetTimerResolution() {
|
|
|
+ ULONG MinimumTimerResolution;
|
|
|
+ ULONG MaximumTimerResolution;
|
|
|
+ ULONG CurrentTimerResolution;
|
|
|
+ NtQueryTimerResolution(&MinimumTimerResolution, &MaximumTimerResolution,
|
|
|
+ &CurrentTimerResolution);
|
|
|
+ return {
|
|
|
+ .minimum{ToNS(MinimumTimerResolution)},
|
|
|
+ .maximum{ToNS(MaximumTimerResolution)},
|
|
|
+ .current{ToNS(CurrentTimerResolution)},
|
|
|
+ };
|
|
|
+}
|
|
|
+
|
|
|
+} // Anonymous namespace
|
|
|
+
|
|
|
+nanoseconds GetMinimumTimerResolution() {
|
|
|
+ return GetTimerResolution().minimum;
|
|
|
+}
|
|
|
+
|
|
|
+nanoseconds GetMaximumTimerResolution() {
|
|
|
+ return GetTimerResolution().maximum;
|
|
|
+}
|
|
|
+
|
|
|
+nanoseconds GetCurrentTimerResolution() {
|
|
|
+ return GetTimerResolution().current;
|
|
|
+}
|
|
|
+
|
|
|
+nanoseconds SetCurrentTimerResolution(nanoseconds timer_resolution) {
|
|
|
+ // Set the timer resolution, and return the current timer resolution.
|
|
|
+ const auto DesiredTimerResolution = ToHundredNS(timer_resolution);
|
|
|
+ ULONG CurrentTimerResolution;
|
|
|
+ NtSetTimerResolution(DesiredTimerResolution, TRUE, &CurrentTimerResolution);
|
|
|
+ return ToNS(CurrentTimerResolution);
|
|
|
+}
|
|
|
+
|
|
|
+nanoseconds SetCurrentTimerResolutionToMaximum() {
|
|
|
+ return SetCurrentTimerResolution(GetMaximumTimerResolution());
|
|
|
+}
|
|
|
+
|
|
|
+void SleepForOneTick() {
|
|
|
+ LARGE_INTEGER DelayInterval{
|
|
|
+ .QuadPart{-1},
|
|
|
+ };
|
|
|
+ NtDelayExecution(FALSE, &DelayInterval);
|
|
|
+}
|
|
|
+
|
|
|
+} // namespace Common::Windows
|