Make the host per-monitor DPI aware and scale the ImGui overlay
The window sized itself to GetSystemMetrics(SM_CXSCREEN/CYSCREEN) but the process was DPI-unaware, so on a scaled display (e.g. 4K @ 150%) Windows handed us a virtualized resolution and bitmap-stretched the whole window up to native -- softening the mirror, which is the tool's entire point. Declare per-monitor-v2 awareness at startup so GetSystemMetrics/GetDpiForWindow report true pixels. That alone would shrink the fixed-13px ImGui overlay to crisp-but-tiny, so pair it with UI scaling: rebuild the default-font atlas at a DPI-scaled SizePixels (crisp at the target size, unlike FontGlobalScale's bitmap stretch) and ScaleAllSizes() the style. Net: same physical size as before, now sharp. - common/include/coop/dpi.hpp: pure DPI->scale math (uses USER_DEFAULT_SCREEN_DPI and a named kBaseFontPx, not bare 96/13 literals), with a zero fallback and clamping. Unit-tested by tests/dpi_test.cpp. - imgui_layer: apply_dpi() at init from GetDpiForWindow; set_dpi() for runtime changes (rebuild atlas + reset/scale style + invalidate the DX11 font texture). - d3d11_window: latch WM_DPICHANGED (honor the suggested rect), expose take_dpi_change(); main loop polls it and calls imgui.set_dpi() between frames. The DPI math is unit-tested; the actual awareness + font rasterization + live WM_DPICHANGED rescale are verified by hand. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -387,6 +387,13 @@ int run()
|
||||
|
||||
while (window.pump_messages())
|
||||
{
|
||||
// Rescale the overlay if the window changed DPI (moved monitors, or the display scale changed).
|
||||
// pump_messages() latches the new DPI; apply it here, outside any in-progress ImGui frame.
|
||||
if (unsigned new_dpi = 0; window.take_dpi_change(new_dpi))
|
||||
{
|
||||
imgui.set_dpi(new_dpi);
|
||||
}
|
||||
|
||||
// When the operator enabled "Sync flip to game frames" (Hooked source), pace the
|
||||
// whole iteration to the game: wait for the next published frame before rendering,
|
||||
// then present without vsync so the flip lands in lockstep with the game.
|
||||
@@ -539,6 +546,11 @@ int run()
|
||||
|
||||
int WINAPI wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int)
|
||||
{
|
||||
// Per-monitor DPI awareness (v2): make GetSystemMetrics / GetDpiForWindow report true pixels so the
|
||||
// mirror renders at the display's native resolution instead of a virtualized one that Windows would
|
||||
// bitmap-stretch (softening the image). We scale the ImGui overlay ourselves to stay readable. Must
|
||||
// run before any window is created.
|
||||
SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
|
||||
// WGC requires an initialized apartment; multi-threaded suits the
|
||||
// free-threaded frame pool.
|
||||
winrt::init_apartment(winrt::apartment_type::multi_threaded);
|
||||
|
||||
Reference in New Issue
Block a user