timer_resolution.cpp 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include <windows.h>
  4. #include "common/windows/timer_resolution.h"
  5. extern "C" {
  6. // http://undocumented.ntinternals.net/index.html?page=UserMode%2FUndocumented%20Functions%2FTime%2FNtQueryTimerResolution.html
  7. NTSYSAPI LONG NTAPI NtQueryTimerResolution(PULONG MinimumResolution, PULONG MaximumResolution,
  8. PULONG CurrentResolution);
  9. // http://undocumented.ntinternals.net/index.html?page=UserMode%2FUndocumented%20Functions%2FTime%2FNtSetTimerResolution.html
  10. NTSYSAPI LONG NTAPI NtSetTimerResolution(ULONG DesiredResolution, BOOLEAN SetResolution,
  11. PULONG CurrentResolution);
  12. // http://undocumented.ntinternals.net/index.html?page=UserMode%2FUndocumented%20Functions%2FNT%20Objects%2FThread%2FNtDelayExecution.html
  13. NTSYSAPI LONG NTAPI NtDelayExecution(BOOLEAN Alertable, PLARGE_INTEGER DelayInterval);
  14. }
  15. // Defines for compatibility with older Windows 10 SDKs.
  16. #ifndef PROCESS_POWER_THROTTLING_EXECUTION_SPEED
  17. #define PROCESS_POWER_THROTTLING_EXECUTION_SPEED 0x1
  18. #endif
  19. #ifndef PROCESS_POWER_THROTTLING_IGNORE_TIMER_RESOLUTION
  20. #define PROCESS_POWER_THROTTLING_IGNORE_TIMER_RESOLUTION 0x4
  21. #endif
  22. namespace Common::Windows {
  23. namespace {
  24. using namespace std::chrono;
  25. constexpr nanoseconds ToNS(ULONG hundred_ns) {
  26. return nanoseconds{hundred_ns * 100};
  27. }
  28. constexpr ULONG ToHundredNS(nanoseconds ns) {
  29. return static_cast<ULONG>(ns.count()) / 100;
  30. }
  31. struct TimerResolution {
  32. std::chrono::nanoseconds minimum;
  33. std::chrono::nanoseconds maximum;
  34. std::chrono::nanoseconds current;
  35. };
  36. TimerResolution GetTimerResolution() {
  37. ULONG MinimumTimerResolution;
  38. ULONG MaximumTimerResolution;
  39. ULONG CurrentTimerResolution;
  40. NtQueryTimerResolution(&MinimumTimerResolution, &MaximumTimerResolution,
  41. &CurrentTimerResolution);
  42. return {
  43. .minimum{ToNS(MinimumTimerResolution)},
  44. .maximum{ToNS(MaximumTimerResolution)},
  45. .current{ToNS(CurrentTimerResolution)},
  46. };
  47. }
  48. void SetHighQoS() {
  49. // https://learn.microsoft.com/en-us/windows/win32/procthread/quality-of-service
  50. PROCESS_POWER_THROTTLING_STATE PowerThrottling{
  51. .Version{PROCESS_POWER_THROTTLING_CURRENT_VERSION},
  52. .ControlMask{PROCESS_POWER_THROTTLING_EXECUTION_SPEED |
  53. PROCESS_POWER_THROTTLING_IGNORE_TIMER_RESOLUTION},
  54. .StateMask{},
  55. };
  56. SetProcessInformation(GetCurrentProcess(), ProcessPowerThrottling, &PowerThrottling,
  57. sizeof(PROCESS_POWER_THROTTLING_STATE));
  58. }
  59. } // Anonymous namespace
  60. nanoseconds GetMinimumTimerResolution() {
  61. return GetTimerResolution().minimum;
  62. }
  63. nanoseconds GetMaximumTimerResolution() {
  64. return GetTimerResolution().maximum;
  65. }
  66. nanoseconds GetCurrentTimerResolution() {
  67. return GetTimerResolution().current;
  68. }
  69. nanoseconds SetCurrentTimerResolution(nanoseconds timer_resolution) {
  70. // Set the timer resolution, and return the current timer resolution.
  71. const auto DesiredTimerResolution = ToHundredNS(timer_resolution);
  72. ULONG CurrentTimerResolution;
  73. NtSetTimerResolution(DesiredTimerResolution, TRUE, &CurrentTimerResolution);
  74. return ToNS(CurrentTimerResolution);
  75. }
  76. nanoseconds SetCurrentTimerResolutionToMaximum() {
  77. SetHighQoS();
  78. return SetCurrentTimerResolution(GetMaximumTimerResolution());
  79. }
  80. void SleepForOneTick() {
  81. LARGE_INTEGER DelayInterval{
  82. .QuadPart{-1},
  83. };
  84. NtDelayExecution(FALSE, &DelayInterval);
  85. }
  86. } // namespace Common::Windows