From a4776050e6f9ab08e8c3e80f9516138137a27493 Mon Sep 17 00:00:00 2001 From: Max <112043822+Maxaubert@users.noreply.github.com> Date: Mon, 25 May 2026 22:19:17 +0200 Subject: [PATCH] revert: remove opt-in DComp backend + GPU-priority (#28) A/B testing pinned the background-game lag on the dcomp (DirectComposition flip-model) backend; blt+DwmFlush is responsive. Revert both the opt-in dcomp backend (#24/PR #25) and the gpuPriority change (#26/PR #27) to the clean blt+DwmFlush state - dcomp regressed background-app responsiveness for no perceptible upside, and gpuPriority=7 risked starving foreground games while zoomed (and isn't needed once dcomp is gone). Restores the affected files to f847a08 (the pre-dcomp #23 state). The finding that WS_EX_LAYERED + DComp coexist is preserved in the closed PRs for reference. build.bat test: 31 cases / 91 assertions; render selftest verified. Co-Authored-By: Claude Opus 4.7 (1M context) --- build.bat | 4 +- src/config.cpp | 8 --- src/config.h | 9 --- src/main.cpp | 14 ++--- src/render_engine.cpp | 138 +++++++++++------------------------------- src/render_engine.h | 6 +- tests/test_config.cpp | 8 --- 7 files changed, 46 insertions(+), 141 deletions(-) diff --git a/build.bat b/build.bat index be6f213a..65c99a1e 100644 --- a/build.bat +++ b/build.bat @@ -30,7 +30,7 @@ cl /nologo /std:c++17 /EHsc /O2 /W4 /DUNICODE /D_UNICODE ^ src\*.cpp ^ /Fe:Wind.exe ^ /link Magnification.lib Dwmapi.lib user32.lib shell32.lib gdi32.lib ^ - d3d11.lib dxgi.lib dxguid.lib dcomp.lib d3dcompiler.lib windowscodecs.lib ole32.lib ^ + d3d11.lib dxgi.lib dxguid.lib d3dcompiler.lib windowscodecs.lib ole32.lib ^ /MANIFEST:EMBED /MANIFESTUAC:NO /MANIFESTINPUT:Wind.manifest /SUBSYSTEM:WINDOWS exit /b %errorlevel% @@ -42,7 +42,7 @@ cl /nologo /std:c++17 /EHsc /O2 /W4 /DUNICODE /D_UNICODE ^ src\*.cpp ^ /Fe:Wind.exe ^ /link Magnification.lib Dwmapi.lib user32.lib shell32.lib gdi32.lib ^ - d3d11.lib dxgi.lib dxguid.lib dcomp.lib d3dcompiler.lib windowscodecs.lib ole32.lib ^ + d3d11.lib dxgi.lib dxguid.lib d3dcompiler.lib windowscodecs.lib ole32.lib ^ /MANIFEST:EMBED /MANIFESTUAC:NO /MANIFESTINPUT:Wind.uiaccess.manifest /SUBSYSTEM:WINDOWS exit /b %errorlevel% diff --git a/src/config.cpp b/src/config.cpp index 03349187..867524e0 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -31,8 +31,6 @@ Config ParseConfig(const std::string& text) { else if (key == "tickHzCap") c.tickHzCap = std::stoi(val); else if (key == "vsync") c.vsync = std::stoi(val); else if (key == "dwmFlush") c.dwmFlush = std::stoi(val); - else if (key == "present") c.present = val; - else if (key == "gpuPriority") c.gpuPriority = std::stoi(val); else if (key == "diagnostics") c.diagnostics = std::stoi(val); else if (key == "cursorSensitivity") c.cursorSensitivity = std::stod(val); else if (key == "cursorSmoothing") c.cursorSmoothing = std::stod(val); @@ -76,12 +74,6 @@ Config LoadConfig(const std::wstring& path) { "vsync=1\n" "; dwmFlush: 1=pace the zoomed loop to DWM's composition (smooth, default); 0=old vsync pacing\n" "dwmFlush=1\n" - "; present: blt=default (blt swapchain + DwmFlush); dcomp=flip-model via DirectComposition\n" - "; (experimental, vsync-paced; restart to change)\n" - "present=blt\n" - "; gpuPriority: GPU scheduling priority (-7..7). Higher keeps the zoom responsive when a\n" - "; game runs in the background; lower if it hurts a foreground game (restart to apply)\n" - "gpuPriority=7\n" "; diagnostics=1 logs frame timing to %TEMP%\\wind_diag.log (restart to apply)\n" "diagnostics=0\n" "; cursorSensitivity: pan speed per raw count\n" diff --git a/src/config.h b/src/config.h index 7e62fbca..87da515f 100644 --- a/src/config.h +++ b/src/config.h @@ -21,15 +21,6 @@ struct Config { // compositor. Fixes the blt-model microstutter (phase mismatch between our Present and DWM's // composite) - default ON. 1 = on (overrides vsync while zoomed), 0 = old vsync pacing. int dwmFlush = 1; - // Presentation backend (restart to change): "blt" = blt-model swapchain paced by DwmFlush - // (default); "dcomp" = flip-model swapchain via DirectComposition, paced by vsync Present - // (experimental A/B - native flip pacing + lower latency, still click-through via layered). - std::string present = "blt"; - // GPU scheduling priority for the magnifier's device (IDXGIDevice::SetGPUThreadPriority, - // clamped to [-7,7]). Higher = the GPU scheduler favors us over other apps, so the zoom - // stays responsive when a GPU-heavy app (a game) runs in the background. 0 = OS default. - // Lower it if it hurts a foreground game while zoomed. - int gpuPriority = 7; int diagnostics = 0; // 1 = log frame-timing to wind_diag.log // --- Own GPU renderer --------------------------------------------------- diff --git a/src/main.cpp b/src/main.cpp index 7e85bd41..f51c6992 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -42,7 +42,6 @@ static int DetectRefreshHz() { struct TickState { RenderEngine& renderEngine; int sw, sh; - bool useDComp; // flip-model backend (fixed at init; not hot-reloaded) Config cfg; ZoomController zoom; CursorMapper mapper; @@ -56,7 +55,7 @@ struct TickState { double diagAccum = 0.0, diagSumDt = 0.0, diagMaxDt = 0.0; int diagFrames = 0, diagHitches = 0; TickState(RenderEngine& re, int w, int h, const Config& c) - : renderEngine(re), sw(w), sh(h), useDComp(c.present == "dcomp"), cfg(c), + : renderEngine(re), sw(w), sh(h), cfg(c), zoom(1.0, c.maxLevel, c.fullRangeSeconds), mapper(w, h, c.cursorSensitivity, c.cursorSmoothing) {} }; @@ -142,9 +141,8 @@ static void RunTick(TickState& t) { p.motionBlurStrength = t.cfg.motionBlurStrength; p.brightness = t.cfg.brightness; p.cursorMode = CursorModeFromCfg(t.cfg); - // dcomp backend: flip-model is paced natively by vsync Present(1,0). blt backend: in - // DwmFlush mode present immediately (no vsync block) and let DwmFlush() pace. - p.vsync = t.useDComp ? true : (t.cfg.vsync != 0 && t.cfg.dwmFlush == 0); + // In DwmFlush mode we present immediately (no vsync block) and let DwmFlush() pace. + p.vsync = (t.cfg.vsync != 0 && t.cfg.dwmFlush == 0); t.renderEngine.renderFrame(p); // Reveal AFTER the live frame is presented: setVisible flips the layer alpha over the // now-current front buffer, so the overlay never shows its retained previous-session @@ -255,7 +253,7 @@ int WINAPI wWinMain(HINSTANCE hInst, HINSTANCE, PWSTR, int) { // --- Own GPU renderer (DXGI Desktop Duplication + D3D11) --- RenderEngine renderEngine; - if (!renderEngine.initialize(sw, sh, cfg.zorderBand, cfg.hdrTonemap != 0, cfg.present == "dcomp", cfg.gpuPriority)) { + if (!renderEngine.initialize(sw, sh, cfg.zorderBand, cfg.hdrTonemap != 0)) { MessageBoxW(nullptr, L"Could not start the renderer (Direct3D 11 / Desktop Duplication " L"unavailable on this system).", L"Wind", MB_ICONERROR); g_input.stop(); @@ -377,8 +375,8 @@ int WINAPI wWinMain(HINSTANCE hInst, HINSTANCE, PWSTR, int) { // - else: Present(0,0) doesn't block, so the timer paces at tickHzCap. // Idle at 1x uses the timer. bool zoomed = ts.prevLvl > 1.0; - bool dwmPaces = zoomed && !ts.useDComp && ts.cfg.dwmFlush != 0; - bool renderPresentPaces = zoomed && (ts.useDComp || (ts.cfg.vsync != 0 && !dwmPaces)); + bool dwmPaces = zoomed && ts.cfg.dwmFlush != 0; + bool renderPresentPaces = zoomed && ts.cfg.vsync != 0 && !dwmPaces; if (!renderPresentPaces && !dwmPaces) { if (timer) { SetWaitableTimer(timer, &due, 0, nullptr, nullptr, FALSE); diff --git a/src/render_engine.cpp b/src/render_engine.cpp index ef39f1df..e0ababca 100644 --- a/src/render_engine.cpp +++ b/src/render_engine.cpp @@ -2,7 +2,6 @@ #include #include #include -#include #include #include #include @@ -15,7 +14,6 @@ #pragma comment(lib, "d3d11.lib") #pragma comment(lib, "dxgi.lib") -#pragma comment(lib, "dcomp.lib") #pragma comment(lib, "d3dcompiler.lib") #pragma comment(lib, "windowscodecs.lib") #pragma comment(lib, "Magnification.lib") @@ -138,8 +136,7 @@ float4 PSMain(VSOut i) : SV_TARGET { c.rgb = LinearToSrgb(max(c.rgb, 0.0) * scRgbScale); } c.rgb *= brightness; // optional fine-tune (default 1.0) - return float4(c.rgb, 1.0); // opaque: the DComp backend uses per-pixel alpha - // (blt ignores it via LWA_ALPHA), so force alpha 1 + return c; } )"; @@ -234,13 +231,7 @@ struct RenderEngine::State { HWND hwnd = nullptr; ID3D11Device* device = nullptr; ID3D11DeviceContext* ctx = nullptr; - IDXGISwapChain* swap = nullptr; // blt-model, OR flip-model composed via DirectComposition - // Opt-in flip-model backend (present=dcomp): keeps WS_EX_LAYERED for click-through but presents a - // flip-model swapchain through a DComp visual (smoother native pacing). Null members = blt backend. - bool useDComp = false; - IDCompositionDevice* dcomp = nullptr; - IDCompositionTarget* dcompTarget = nullptr; - IDCompositionVisual* dcompVisual = nullptr; + IDXGISwapChain* swap = nullptr; // blt-model (layered window needs the redirection surface) ID3D11RenderTargetView* rtv = nullptr; int lastClickX = INT_MIN, lastClickY = INT_MIN; // skip redundant SetCursorPos unsigned long long lastTopmostMs = 0; // last HWND_TOPMOST re-assert (throttled) @@ -447,12 +438,11 @@ void RenderEngine::debugHdr(unsigned& ddaFormat, int& colorSpace, int& bitsPerCo ddaFormat = s_->ddaFormat; colorSpace = s_->outColorSpace; bitsPerColor = s_->outBitsPerColor; } -bool RenderEngine::initialize(int screenW, int screenH, int zorderBand, bool hdrTonemap, bool useDComp, int gpuPriority) { +bool RenderEngine::initialize(int screenW, int screenH, int zorderBand, bool hdrTonemap) { s_->sw = screenW; s_->sh = screenH; s_->wantHdrTonemap = hdrTonemap; // read before recreateDupl decides the capture format - s_->useDComp = useDComp; - RLog("=== initialize sw=%d sh=%d band=%d hdrTonemap=%d dcomp=%d ===", screenW, screenH, zorderBand, (int)hdrTonemap, (int)useDComp); + RLog("=== initialize sw=%d sh=%d band=%d hdrTonemap=%d ===", screenW, screenH, zorderBand, (int)hdrTonemap); // --- Overlay window: fullscreen, borderless, topmost, click-through, no-activate --- static const wchar_t* kClass = L"WindRenderOverlay"; @@ -464,8 +454,8 @@ bool RenderEngine::initialize(int screenW, int screenH, int zorderBand, bool hdr ATOM atom = RegisterClassW(&wc); // WS_EX_LAYERED is required for true cross-process click-through (WS_EX_TRANSPARENT + // HTTRANSPARENT alone only forwards to same-thread windows, so clicks to other apps were - // being eaten). Kept for BOTH backends - a spike confirmed WS_EX_LAYERED coexists with a - // DirectComposition flip-model swapchain (click-through + display both work). + // being eaten). LAYERED rules out a flip swapchain, so we use a blt-model swapchain below + // (verified to display via the redirection surface). LWA_ALPHA 255 = fully opaque. const DWORD exStyle = WS_EX_LAYERED | WS_EX_TRANSPARENT | WS_EX_TOPMOST | WS_EX_NOACTIVATE | WS_EX_TOOLWINDOW; s_->hwnd = nullptr; @@ -489,11 +479,12 @@ bool RenderEngine::initialize(int screenW, int screenH, int zorderBand, bool hdr 0, 0, screenW, screenH, nullptr, nullptr, wc.hInstance, nullptr); } if (!s_->hwnd) return false; - // Hide/show without SW_HIDE/SW_SHOW (which makes DWM re-display a cached last-visible frame - // -> the alt-tab flash). blt backend: toggle the layer alpha 0/255 (per-pixel alpha is - // ignored under LWA_ALPHA). dcomp backend: keep the layer opaque (255) and hide by presenting - // a fully transparent frame (per-pixel alpha). Either way the window stays shown. - SetLayeredWindowAttributes(s_->hwnd, 0, useDComp ? 255 : 0, LWA_ALPHA); + // Start fully transparent (alpha 0 = invisible). We toggle the layer alpha to show/hide + // instead of SW_HIDE/SW_SHOW: a layered window that is hidden and re-shown makes DWM cache + // and re-display the frame from when it was last visible, which flashed the previous zoom + // session's window on the next zoom-in (most visibly right after an alt-tab). Keeping the + // window always shown lets a reveal just flip alpha over the already-current front buffer. + SetLayeredWindowAttributes(s_->hwnd, 0, 0, LWA_ALPHA); // CRITICAL: exclude our own overlay from screen capture, or Desktop Duplication captures // our presented frame and we magnify our own output -> a feedback loop (degenerates to // black). WDA_EXCLUDEFROMCAPTURE (Win10 2004+) keeps the window visible on screen but @@ -509,79 +500,39 @@ bool RenderEngine::initialize(int screenW, int screenH, int zorderBand, bool hdr &s_->device, &got, &s_->ctx); if (FAILED(hr)) return false; - // --- Swapchain: blt-model on the HWND (default), or flip-model via DirectComposition (opt-in) --- + // --- Blt-model swapchain on the layered overlay HWND (flip can't target layered) --- IDXGIDevice1* dxgiDev = nullptr; if (FAILED(s_->device->QueryInterface(__uuidof(IDXGIDevice1), (void**)&dxgiDev))) return false; dxgiDev->SetMaximumFrameLatency(1); // cap input-to-photon latency to ~1 frame - if (gpuPriority != 0) { // favor the magnifier on the GPU vs background apps - int p = gpuPriority < -7 ? -7 : (gpuPriority > 7 ? 7 : gpuPriority); - dxgiDev->SetGPUThreadPriority(p); - RLog("SetGPUThreadPriority(%d)", p); - } IDXGIAdapter* adapter = nullptr; dxgiDev->GetAdapter(&adapter); + IDXGIFactory* factory = nullptr; + if (adapter) adapter->GetParent(__uuidof(IDXGIFactory), (void**)&factory); + SafeRelease(dxgiDev); + SafeRelease(adapter); + if (!factory) return false; + + DXGI_SWAP_CHAIN_DESC scd{}; + scd.BufferDesc.Width = screenW; + scd.BufferDesc.Height = screenH; + scd.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; + scd.SampleDesc.Count = 1; + scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + scd.BufferCount = 1; + scd.OutputWindow = s_->hwnd; + scd.Windowed = TRUE; + scd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; + hr = factory->CreateSwapChain(s_->device, &scd, &s_->swap); + factory->MakeWindowAssociation(s_->hwnd, DXGI_MWA_NO_ALT_ENTER); + SafeRelease(factory); + if (FAILED(hr)) return false; - if (useDComp) { - // Flip-model swapchain composed onto the (still layered) HWND via DirectComposition. - IDXGIFactory2* factory2 = nullptr; - if (adapter) adapter->GetParent(__uuidof(IDXGIFactory2), (void**)&factory2); - if (!factory2) { SafeRelease(dxgiDev); SafeRelease(adapter); return false; } - DXGI_SWAP_CHAIN_DESC1 d{}; - d.Width = screenW; d.Height = screenH; d.Format = DXGI_FORMAT_B8G8R8A8_UNORM; - d.SampleDesc.Count = 1; d.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; d.BufferCount = 2; - d.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; d.AlphaMode = DXGI_ALPHA_MODE_PREMULTIPLIED; - d.Scaling = DXGI_SCALING_STRETCH; - IDXGISwapChain1* sc1 = nullptr; - hr = factory2->CreateSwapChainForComposition(s_->device, &d, nullptr, &sc1); - SafeRelease(factory2); - if (FAILED(hr) || !sc1) { SafeRelease(dxgiDev); SafeRelease(adapter); RLog("CreateSwapChainForComposition hr=0x%08lX", (unsigned long)hr); return false; } - s_->swap = sc1; // IDXGISwapChain1 is-a IDXGISwapChain - hr = DCompositionCreateDevice(dxgiDev, __uuidof(IDCompositionDevice), (void**)&s_->dcomp); - if (SUCCEEDED(hr) && s_->dcomp && - SUCCEEDED(s_->dcomp->CreateTargetForHwnd(s_->hwnd, TRUE, &s_->dcompTarget)) && - SUCCEEDED(s_->dcomp->CreateVisual(&s_->dcompVisual))) { - s_->dcompVisual->SetContent(s_->swap); - s_->dcompTarget->SetRoot(s_->dcompVisual); - hr = s_->dcomp->Commit(); - } - SafeRelease(dxgiDev); SafeRelease(adapter); - if (FAILED(hr)) { RLog("DComp setup hr=0x%08lX", (unsigned long)hr); return false; } - } else { - IDXGIFactory* factory = nullptr; - if (adapter) adapter->GetParent(__uuidof(IDXGIFactory), (void**)&factory); - SafeRelease(dxgiDev); - SafeRelease(adapter); - if (!factory) return false; - DXGI_SWAP_CHAIN_DESC scd{}; - scd.BufferDesc.Width = screenW; - scd.BufferDesc.Height = screenH; - scd.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; - scd.SampleDesc.Count = 1; - scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; - scd.BufferCount = 1; - scd.OutputWindow = s_->hwnd; - scd.Windowed = TRUE; - scd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; - hr = factory->CreateSwapChain(s_->device, &scd, &s_->swap); - factory->MakeWindowAssociation(s_->hwnd, DXGI_MWA_NO_ALT_ENTER); - SafeRelease(factory); - if (FAILED(hr)) return false; - } - - // --- Render target view from back-buffer 0 (reusable across Presents in D3D11) --- + // --- Render target view from back-buffer 0 --- ID3D11Texture2D* back = nullptr; if (FAILED(s_->swap->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&back))) return false; hr = s_->device->CreateRenderTargetView(back, nullptr, &s_->rtv); SafeRelease(back); if (FAILED(hr)) return false; - // dcomp backend: present an initial transparent frame so the overlay starts see-through - // (the layer is opaque at 255; per-pixel alpha provides invisibility until we draw). - if (useDComp) { - const float clearT[4] = { 0, 0, 0, 0 }; - s_->ctx->OMSetRenderTargets(1, &s_->rtv, nullptr); - s_->ctx->ClearRenderTargetView(s_->rtv, clearT); - s_->swap->Present(0, 0); - } // --- Desktop copy texture (SRV-able; DDA frames are copied into this). Starts BGRA8; // capture() re-creates it to match the acquired format (e.g. FP16 scRGB on HDR). --- @@ -668,21 +619,9 @@ bool RenderEngine::initialize(int screenW, int screenH, int zorderBand, bool hdr void RenderEngine::setVisible(bool visible) { if (!s_ || !s_->hwnd) return; - // Always-shown window (no SW_HIDE/SW_SHOW, which flashes DWM's cached frame). blt backend: - // toggle the layer alpha 0/255. dcomp backend: the layer stays opaque (255) - hide by - // presenting one fully transparent frame (per-pixel alpha); show is implicit (next renderFrame). - if (s_->useDComp) { - if (visible) { - s_->prevSrcValid = false; - SetWindowPos(s_->hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); - } else if (s_->ctx && s_->rtv && s_->swap) { - const float clearT[4] = { 0, 0, 0, 0 }; - s_->ctx->OMSetRenderTargets(1, &s_->rtv, nullptr); - s_->ctx->ClearRenderTargetView(s_->rtv, clearT); - s_->swap->Present(0, 0); - } - return; - } + // Reveal/hide via layer alpha over the always-shown window (see initialize): flip alpha + // rather than SW_HIDE/SW_SHOW, so a reveal shows the already-current front buffer instead + // of DWM's cached last-visible frame. Callers present the live frame BEFORE revealing. SetLayeredWindowAttributes(s_->hwnd, 0, visible ? 255 : 0, LWA_ALPHA); if (visible) { s_->prevSrcValid = false; // don't motion-blur the jump into zoom @@ -887,9 +826,6 @@ void RenderEngine::shutdown() { SafeRelease(s_->dupl); SafeRelease(s_->desktopCopy); SafeRelease(s_->rtv); - SafeRelease(s_->dcompVisual); - SafeRelease(s_->dcompTarget); - SafeRelease(s_->dcomp); SafeRelease(s_->swap); SafeRelease(s_->ctx); SafeRelease(s_->device); diff --git a/src/render_engine.h b/src/render_engine.h index ff1117b0..262bd0a4 100644 --- a/src/render_engine.h +++ b/src/render_engine.h @@ -33,11 +33,7 @@ class RenderEngine { // CreateWindowInBand (needs UIAccess; e.g. 16 = ZBID_SYSTEM_TOOLS, above the shell so the // Start menu / taskbar flyouts don't show an unmagnified copy). Falls back to a normal // window if the band can't be used. - // useDComp: false = blt-model swapchain on the layered HWND (default, paced by DwmFlush); - // true = flip-model swapchain composed via DirectComposition (still WS_EX_LAYERED for - // click-through), paced by vsync Present. Opt-in A/B backend. - bool initialize(int screenW, int screenH, int zorderBand = 0, bool hdrTonemap = false, - bool useDComp = false, int gpuPriority = 0); + bool initialize(int screenW, int screenH, int zorderBand = 0, bool hdrTonemap = false); bool renderFrame(const RenderFrameParams& p); // capture (if changed) + scale + cursor + present void setVisible(bool visible); // show/hide the overlay (hidden at 1x) // Force the next frame to grab a fresh full-desktop capture (release+recreate the diff --git a/tests/test_config.cpp b/tests/test_config.cpp index 3c1e9d78..0c177613 100644 --- a/tests/test_config.cpp +++ b/tests/test_config.cpp @@ -32,14 +32,6 @@ TEST_CASE("renderer knobs have sane defaults") { CHECK(c.vsync == 1); // vsync on by default CHECK(c.dwmFlush == 1); // DwmFlush pacing on by default (the smooth path) CHECK(c.tickHzCap == 0); // 0 = auto-detect display refresh rate - CHECK(c.present == "blt"); // blt+DwmFlush backend by default - CHECK(c.gpuPriority == 7); // favor the magnifier on the GPU by default -} -TEST_CASE("present backend and gpuPriority parse") { - CHECK(ParseConfig("present=dcomp\n").present == "dcomp"); - CHECK(ParseConfig("present=blt\n").present == "blt"); - CHECK(ParseConfig("gpuPriority=0\n").gpuPriority == 0); - CHECK(ParseConfig("gpuPriority=-7\n").gpuPriority == -7); } TEST_CASE("vsync, dwmFlush, tickHzCap can be set") { CHECK(ParseConfig("vsync=0\n").vsync == 0);