Files
vatrog-vm-vgpu-streamer/src/stream/win32/geometry.c
T
lirent bcf708d3cc feat: add graphics-context sensors to producer contract
Append three host-readable sensor groups to the producer block, ABI
frozen by offset asserts (producer still fits page 0):

- cursor Tier-1 (hotspot, glyph dims, shape identity), published under
  the existing cursor_seq gate
- content_change_ns: monotonic stamp of the last scene-content change
- display geometry on its own cache line under a geom_seq seqlock:
  virtual-desktop bbox, captured-output origin, DPI, refresh

Source the cursor from each backend's existing grab metadata instead of
polling GetCursorInfo in the present pump: DDA from the duplication frame
info pointer position (no extra calls), NvFBC visibility from the grab
info plus one GetCursorInfo per frame for position, GDI from
GetCursorInfo. Position sampling now rides the frame rate, not the pump
tick.

Sample display geometry once at startup and re-sample only on backend
session recreate or a captured-mode change. Drop per-tick cursor
sampling (cursor_sample_pos) from the present loop.

Add src/stream/win32/geometry.{c,h}.
2026-06-19 01:32:28 +03:00

53 lines
2.0 KiB
C

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include "geometry.h"
#include "stream.h" /* vgpu_publish_geometry */
/* GetDpiForMonitor lives in Shcore.dll (per-monitor DPI awareness API). Loaded dynamically so
* the binary does not hard-depend on it; absence degrades dpi to "unknown" (0). */
typedef HRESULT (WINAPI *GetDpiForMonitor_t)(HMONITOR, int /*MDT_*/, UINT*, UINT*);
#define VGPU_MDT_EFFECTIVE_DPI 0
static UINT monitor_dpi(HMONITOR mon) {
static GetDpiForMonitor_t fn = NULL;
static int tried = 0;
if (!tried) {
HMODULE lib = LoadLibraryA("Shcore.dll");
if (lib) fn = (GetDpiForMonitor_t)(void*)GetProcAddress(lib, "GetDpiForMonitor");
tried = 1;
}
if (!fn || !mon) return 0u;
UINT dx = 0, dy = 0;
if (fn(mon, VGPU_MDT_EFFECTIVE_DPI, &dx, &dy) != S_OK || dx == 0u)
return 0u;
return dx;
}
static uint32_t monitor_refresh_mhz(HMONITOR mon) {
MONITORINFOEXW mi; mi.cbSize = sizeof mi;
if (!mon || !GetMonitorInfoW(mon, (MONITORINFO*)&mi))
return 0u;
DEVMODEW dm; ZeroMemory(&dm, sizeof dm); dm.dmSize = sizeof dm;
if (!EnumDisplaySettingsW(mi.szDevice, ENUM_CURRENT_SETTINGS, &dm))
return 0u;
if (dm.dmDisplayFrequency <= 1u) /* 0/1 = hardware default, not a real rate */
return 0u;
return (uint32_t)dm.dmDisplayFrequency * 1000u; /* whole Hz -> milli-Hz */
}
void geometry_sample_and_publish(vgpu_ctx* ctx, int32_t cap_x, int32_t cap_y) {
int32_t virt_x = (int32_t)GetSystemMetrics(SM_XVIRTUALSCREEN);
int32_t virt_y = (int32_t)GetSystemMetrics(SM_YVIRTUALSCREEN);
uint32_t virt_w = (uint32_t)GetSystemMetrics(SM_CXVIRTUALSCREEN);
uint32_t virt_h = (uint32_t)GetSystemMetrics(SM_CYVIRTUALSCREEN);
POINT origin = { cap_x, cap_y };
HMONITOR mon = MonitorFromPoint(origin, MONITOR_DEFAULTTOPRIMARY);
uint32_t dpi = monitor_dpi(mon);
uint32_t refresh = monitor_refresh_mhz(mon);
vgpu_publish_geometry(&ctx->view, virt_x, virt_y, virt_w, virt_h,
cap_x, cap_y, dpi, refresh);
}