[hal] Windows sim: enable High QOS and honor timer resolution requests (#6908)

By default on Windows 11, power throttling will increase timer resolution
if a window is occluded.  Disable that behavior.  Also enable high QOS to
achieve maximum performance and turn off power saving.

Also use internal APIs to set timer precision to 500 us if available.
This commit is contained in:
Peter Johnson
2024-08-01 19:51:02 -07:00
committed by GitHub
parent 685c732568
commit caf424e09c

View File

@@ -13,7 +13,12 @@
#ifdef _WIN32
#include <Windows.h>
#pragma comment(lib, "Winmm.lib")
#pragma comment(lib, "ntdll.lib")
extern "C" NTSYSAPI NTSTATUS NTAPI NtSetTimerResolution(
ULONG DesiredResolution, BOOLEAN SetResolution, PULONG CurrentResolution);
extern "C" NTSYSAPI NTSTATUS NTAPI
NtQueryTimerResolution(PULONG MinimumResolution, PULONG MaximumResolution,
PULONG CurrentResolution);
#endif // _WIN32
#include "ErrorsInternal.h"
@@ -364,19 +369,51 @@ HAL_Bool HAL_Initialize(int32_t timeout, int32_t mode) {
initialized = true;
// Set Timer Precision to 1ms on Windows
// Set Timer Precision to 0.5ms on Windows
#ifdef _WIN32
TIMECAPS tc;
if (timeGetDevCaps(&tc, sizeof(tc)) == TIMERR_NOERROR) {
UINT target = (std::min)(static_cast<UINT>(1), tc.wPeriodMin);
timeBeginPeriod(target);
std::atexit([]() {
TIMECAPS tc;
if (timeGetDevCaps(&tc, sizeof(tc)) == TIMERR_NOERROR) {
UINT target = (std::min)(static_cast<UINT>(1), tc.wPeriodMin);
timeEndPeriod(target);
}
});
// https://stackoverflow.com/questions/3141556/how-to-setup-timer-resolution-to-0-5-ms
ULONG min, max, current;
if (NtQueryTimerResolution(&min, &max, &current) == 0) {
ULONG currentRes;
if (NtSetTimerResolution(max, TRUE, &currentRes) == 0) {
std::atexit([]() {
ULONG currentRes;
NtSetTimerResolution(0, FALSE, &currentRes);
});
}
}
// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-setprocessinformation
// Enable HighQoS to achieve maximum performance, and turn off power saving.
{
PROCESS_POWER_THROTTLING_STATE PowerThrottling{};
PowerThrottling.Version = PROCESS_POWER_THROTTLING_CURRENT_VERSION;
PowerThrottling.ControlMask = PROCESS_POWER_THROTTLING_EXECUTION_SPEED;
PowerThrottling.StateMask = 0;
SetProcessInformation(GetCurrentProcess(), ProcessPowerThrottling,
&PowerThrottling, sizeof(PowerThrottling));
}
// https://forums.oculusvr.com/t5/General/SteamVR-has-fixed-the-problems-with-Windows-11/td-p/956413
// Always honor Timer Resolution Requests. This is to ensure that the timer
// resolution set-up above sticks through transitions of the main window (eg:
// minimization).
{
// This setting was introduced in Windows 11 and the definition is not
// available in older headers.
#ifndef PROCESS_POWER_THROTTLING_IGNORE_TIMER_RESOLUTION
const auto PROCESS_POWER_THROTTLING_IGNORE_TIMER_RESOLUTION = 0x4U;
#endif
PROCESS_POWER_THROTTLING_STATE PowerThrottling{};
PowerThrottling.Version = PROCESS_POWER_THROTTLING_CURRENT_VERSION;
PowerThrottling.ControlMask =
PROCESS_POWER_THROTTLING_IGNORE_TIMER_RESOLUTION;
PowerThrottling.StateMask = 0;
SetProcessInformation(GetCurrentProcess(), ProcessPowerThrottling,
&PowerThrottling, sizeof(PowerThrottling));
}
#endif // _WIN32