From 411a6b1e49f9ef5e660236fbcdfc8167b1245107 Mon Sep 17 00:00:00 2001 From: Geoffrey McRae Date: Sat, 17 Jul 2021 14:55:22 +1000 Subject: [PATCH] [host] windows: add `delayExecution` function for more accurate sleeps This change not only exposes and allows use of NtDelayExecution, but also moves the code to set the system timer resolution. --- host/platform/Windows/CMakeLists.txt | 1 + .../platform/Windows/capture/DXGI/dll/deyfh.s | 16 ++++++ host/platform/Windows/include/windows/delay.h | 34 +++++++++++++ host/platform/Windows/src/delay.c | 49 +++++++++++++++++++ host/platform/Windows/src/mousehook.c | 3 +- host/platform/Windows/src/platform.c | 16 ++---- 6 files changed, 105 insertions(+), 14 deletions(-) create mode 100644 host/platform/Windows/capture/DXGI/dll/deyfh.s create mode 100644 host/platform/Windows/include/windows/delay.h create mode 100644 host/platform/Windows/src/delay.c diff --git a/host/platform/Windows/CMakeLists.txt b/host/platform/Windows/CMakeLists.txt index 71bcfa3d..43eda645 100644 --- a/host/platform/Windows/CMakeLists.txt +++ b/host/platform/Windows/CMakeLists.txt @@ -10,6 +10,7 @@ add_library(platform_Windows STATIC src/service.c src/mousehook.c src/force_compose.c + src/delay.c ) # allow use of functions for Windows Vista or later diff --git a/host/platform/Windows/capture/DXGI/dll/deyfh.s b/host/platform/Windows/capture/DXGI/dll/deyfh.s new file mode 100644 index 00000000..4d563555 --- /dev/null +++ b/host/platform/Windows/capture/DXGI/dll/deyfh.s @@ -0,0 +1,16 @@ +# IMAGE_IMPORT_DESCRIPTOR + .section .idata$2 + .global _head_C__msys64_home_Geoff_LookingGlass_host_release_platform_Windows_capture_DXGI_libd3d11_dll +_head_C__msys64_home_Geoff_LookingGlass_host_release_platform_Windows_capture_DXGI_libd3d11_dll: + .rva hname #Ptr to image import by name list + #this should be the timestamp, but NT sometimes + #doesn't load DLLs when this is set. + .long 0 # loaded time + .long 0 # Forwarder chain + .rva __C__msys64_home_Geoff_LookingGlass_host_release_platform_Windows_capture_DXGI_libd3d11_dll_iname # imported dll's name + .rva fthunk # pointer to firstthunk +#Stuff for compatibility + .section .idata$5 +fthunk: + .section .idata$4 +hname: diff --git a/host/platform/Windows/include/windows/delay.h b/host/platform/Windows/include/windows/delay.h new file mode 100644 index 00000000..cc72f66d --- /dev/null +++ b/host/platform/Windows/include/windows/delay.h @@ -0,0 +1,34 @@ +/** + * Looking Glass + * Copyright (C) 2017-2021 The Looking Glass Authors + * https://looking-glass.io + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + +typedef NTSTATUS (__stdcall *ZwSetTimerResolution_t)(ULONG RequestedResolution, + BOOLEAN Set, PULONG ActualResolution); +extern ZwSetTimerResolution_t ZwSetTimerResolution; + +typedef NTSTATUS (__stdcall *NtDelayExecution_t)(BOOL Alertable, + PLARGE_INTEGER DelayInterval); +extern NtDelayExecution_t NtDelayExecution; + +void delayInit(void); + +// like sleep but more accurate +void delayExecution(float ms); diff --git a/host/platform/Windows/src/delay.c b/host/platform/Windows/src/delay.c new file mode 100644 index 00000000..a36db371 --- /dev/null +++ b/host/platform/Windows/src/delay.c @@ -0,0 +1,49 @@ +/** + * Looking Glass + * Copyright (C) 2017-2021 The Looking Glass Authors + * https://looking-glass.io + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "windows/delay.h" +#include "common/debug.h" + +NtDelayExecution_t NtDelayExecution; +ZwSetTimerResolution_t ZwSetTimerResolution; + +void delayInit(void) +{ + HMODULE ntdll = GetModuleHandle("ntdll.dll"); + NtDelayExecution = (NtDelayExecution_t) + GetProcAddress(ntdll, "NtDelayExecution"); + + // Increase the timer resolution + ZwSetTimerResolution = (ZwSetTimerResolution_t) + GetProcAddress(ntdll, "ZwSetTimerResolution"); + + if (ZwSetTimerResolution) + { + ULONG actualResolution; + ZwSetTimerResolution(1, true, &actualResolution); + DEBUG_INFO("System timer resolution: %lu ns", actualResolution * 100); + } +} + +void delayExecution(float ms) +{ + LARGE_INTEGER interval = { .QuadPart = -1 * (int)(ms * 1000.0f) }; + NtDelayExecution(FALSE, &interval); +} diff --git a/host/platform/Windows/src/mousehook.c b/host/platform/Windows/src/mousehook.c index 7aadd8ef..a4ef4b9b 100644 --- a/host/platform/Windows/src/mousehook.c +++ b/host/platform/Windows/src/mousehook.c @@ -19,6 +19,7 @@ */ #include "windows/mousehook.h" +#include "windows/delay.h" #include "common/windebug.h" #include "platform.h" @@ -104,7 +105,7 @@ static DWORD WINAPI updateThreadProc(LPVOID lParam) mouseHook.callback(mouseHook.x, mouseHook.y); // limit this to 1000Hz, who has a mouse that updates faster anyway? - Sleep(1); + delayExecution(1.0f); break; } } diff --git a/host/platform/Windows/src/platform.c b/host/platform/Windows/src/platform.c index ef791009..39dce89c 100644 --- a/host/platform/Windows/src/platform.c +++ b/host/platform/Windows/src/platform.c @@ -20,6 +20,7 @@ #include "platform.h" #include "service.h" +#include "windows/delay.h" #include "windows/mousehook.h" #include @@ -61,10 +62,6 @@ struct AppState static struct AppState app = {0}; HWND MessageHWND; -// undocumented API to adjust the system timer resolution (yes, its a nasty hack) -typedef NTSTATUS (__stdcall *ZwSetTimerResolution_t)(ULONG RequestedResolution, BOOLEAN Set, PULONG ActualResolution); -static ZwSetTimerResolution_t ZwSetTimerResolution = NULL; - // linux mingw64 is missing this #ifndef MSGFLT_RESET #define MSGFLT_RESET (0) @@ -504,7 +501,7 @@ void boostPriority(void) bool app_init(void) { - const char * logFile = option_get_string("os", "logFile" ); + const char * logFile = option_get_string("os", "logFile"); // redirect stderr to a file if (logFile && strcmp(logFile, "stderr") != 0) @@ -513,14 +510,7 @@ bool app_init(void) // always flush stderr setbuf(stderr, NULL); - // Increase the timer resolution - ZwSetTimerResolution = (ZwSetTimerResolution_t)GetProcAddress(GetModuleHandle("ntdll.dll"), "ZwSetTimerResolution"); - if (ZwSetTimerResolution) - { - ULONG actualResolution; - ZwSetTimerResolution(1, true, &actualResolution); - DEBUG_INFO("System timer resolution: %lu ns", actualResolution * 100); - } + delayInit(); // get the performance frequency for spinlocks QueryPerformanceFrequency(&app.perfFreq);