Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
multimonitor support
  • Loading branch information
erepb committed Feb 2, 2026
commit a7964cbabb134b69a2f4a3717a422e4ee90f6101
27 changes: 20 additions & 7 deletions src/Layers/xrRender/HW.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ void CHW::DestroyDevice()
}

extern void GetMonitorResolution(u32& horizontal, u32& vertical);

extern void GetMonitorPosition(int& x, int& y);
void CHW::selectResolution(u32& dwWidth, u32& dwHeight, BOOL bWindowed)
{
fill_vid_mode_list(this);
Expand Down Expand Up @@ -271,6 +271,17 @@ void CHW::CreateDevice(HWND m_hWnd, bool move_window)
#endif

DevAdapter = D3DADAPTER_DEFAULT;
{
HMONITOR hWindowMonitor = MonitorFromWindow(m_hWnd, MONITOR_DEFAULTTOPRIMARY);
for (UINT Adapter = 0; Adapter < pD3D->GetAdapterCount(); Adapter++)
{
if (pD3D->GetAdapterMonitor(Adapter) == hWindowMonitor)
{
DevAdapter = Adapter;
break;
}
}
}
DevT = Caps.bForceGPU_REF ? D3DDEVTYPE_REF : D3DDEVTYPE_HAL;

#ifndef MASTER_GOLD
Expand Down Expand Up @@ -627,6 +638,8 @@ void CHW::updateWindowProps(HWND m_hWnd)

u32 monW, monH;
GetMonitorResolution(monW, monH);
int monX, monY;
GetMonitorPosition(monX, monY);

LONG res_width = g_screenmode == 0 ? psCurrentVidMode[0] : monW;
LONG res_height = g_screenmode == 0 ? psCurrentVidMode[1] : monH;
Expand All @@ -637,15 +650,15 @@ void CHW::updateWindowProps(HWND m_hWnd)
GetClientRect(GetDesktopWindow(), &DesktopRect);

SetRect(&m_rcWindowBounds,
(DesktopRect.right - res_width) / 2,
(DesktopRect.bottom - res_height) / 2,
(DesktopRect.right + res_width) / 2,
(DesktopRect.bottom + res_height) / 2);
(LONG(monW) - res_width) / 2,
(LONG(monH) - res_height) / 2,
(monW + res_width) / 2,
(monH + res_height) / 2);

SetWindowPos(m_hWnd,
HWND_NOTOPMOST,
m_rcWindowBounds.left,
m_rcWindowBounds.top,
monX + m_rcWindowBounds.left,
monY + m_rcWindowBounds.top,
(m_rcWindowBounds.right - m_rcWindowBounds.left),
(m_rcWindowBounds.bottom - m_rcWindowBounds.top),
SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_DRAWFRAME);
Expand Down
15 changes: 9 additions & 6 deletions src/Layers/xrRenderDX10/dx10HW.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -847,6 +847,7 @@ D3DFORMAT CHW::selectDepthStencil(D3DFORMAT fTarget)
}

extern void GetMonitorResolution(u32& horizontal, u32& vertical);
extern void GetMonitorPosition(int& x, int& y);

void CHW::selectResolution(u32& dwWidth, u32& dwHeight, BOOL bWindowed)
{
Expand Down Expand Up @@ -1124,6 +1125,8 @@ void CHW::updateWindowProps(HWND m_hWnd)

u32 monW, monH;
GetMonitorResolution(monW, monH);
int monX, monY;
GetMonitorPosition(monX, monY);

if (psCurrentVidMode[0] == 0 || psCurrentVidMode[1] == 0)
GetMonitorResolution(psCurrentVidMode[0], psCurrentVidMode[1]);
Expand All @@ -1136,15 +1139,15 @@ void CHW::updateWindowProps(HWND m_hWnd)
GetClientRect(GetDesktopWindow(), &DesktopRect);

SetRect(&m_rcWindowBounds,
(DesktopRect.right - res_width) / 2,
(DesktopRect.bottom - res_height) / 2,
(DesktopRect.right + res_width) / 2,
(DesktopRect.bottom + res_height) / 2);
(LONG(monW) - res_width) / 2,
(LONG(monH) - res_height) / 2,
(monW + res_width) / 2,
(monH + res_height) / 2);

SetWindowPos(m_hWnd,
HWND_NOTOPMOST,
m_rcWindowBounds.left,
m_rcWindowBounds.top,
monX + m_rcWindowBounds.left,
monY + m_rcWindowBounds.top,
(m_rcWindowBounds.right - m_rcWindowBounds.left),
(m_rcWindowBounds.bottom - m_rcWindowBounds.top),
SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_DRAWFRAME);
Expand Down
19 changes: 19 additions & 0 deletions src/Layers/xrRenderPC_R2/xrRender_R2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,30 @@ bool /*_declspec(dllexport)*/ SupportsAdvancedRendering();

bool /*_declspec(dllexport)*/ SupportsAdvancedRendering()
{
// Save DPI awareness context — Direct3DCreate9() can change the thread's
// DPI context, which later causes SetWindowPos to use the wrong scale on
// secondary monitors with different DPI.
typedef HANDLE(WINAPI* pfnSetThreadDpiAwarenessContext)(HANDLE);
pfnSetThreadDpiAwarenessContext fnSetCtx = NULL;
HANDLE prevDpiContext = NULL;
HMODULE user32 = GetModuleHandleA("user32.dll");
if (user32)
{
fnSetCtx = (pfnSetThreadDpiAwarenessContext)GetProcAddress(user32, "SetThreadDpiAwarenessContext");
if (fnSetCtx)
prevDpiContext = fnSetCtx(/*DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2*/ (HANDLE)-4);
}

D3DCAPS9 caps;
CHW _HW;
_HW.CreateD3D();
_HW.pD3D->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps);
_HW.DestroyD3D();

// Restore DPI awareness context
if (fnSetCtx && prevDpiContext)
fnSetCtx(prevDpiContext);

u16 ps_ver_major = u16(u32(u32(caps.PixelShaderVersion) & u32(0xf << 8ul)) >> 8);

if (ps_ver_major < 3)
Expand Down
5 changes: 4 additions & 1 deletion src/xrEngine/Device_create.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ void CRenderDevice::ConnectToRender()

extern u32 g_screenmode;
extern void GetMonitorResolution(u32& horizontal, u32& vertical);
extern void GetMonitorPosition(int& x, int& y);

PROTECT_API void CRenderDevice::Create()
{
Expand All @@ -172,6 +173,8 @@ PROTECT_API void CRenderDevice::Create()

u32 w, h;
GetMonitorResolution(w, h);
int monX, monY;
GetMonitorPosition(monX, monY);
if (psCurrentVidMode[0] == 0 || psCurrentVidMode[1] == 0)
{
psCurrentVidMode[0] = w;
Expand All @@ -191,7 +194,7 @@ PROTECT_API void CRenderDevice::Create()
}

SetWindowLongPtr(m_hWnd, GWL_STYLE, style);
SetWindowPos(m_hWnd, HWND_TOP, 0, 0, w, h, SWP_FRAMECHANGED);
SetWindowPos(m_hWnd, HWND_TOP, monX, monY, w, h, SWP_FRAMECHANGED);

Statistic = xr_new<CStats>();
#ifdef DEBUG
Expand Down
5 changes: 4 additions & 1 deletion src/xrEngine/Device_destroy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ extern bool init_reshade();
extern void unregister_reshade();
extern u32 g_screenmode;
extern void GetMonitorResolution(u32& horizontal, u32& vertical);
extern void GetMonitorPosition(int& x, int& y);

void CRenderDevice::Reset(bool precache)
{
Expand Down Expand Up @@ -101,9 +102,11 @@ void CRenderDevice::Reset(bool precache)
if (g_screenmode == 1)
{
u32 w, h;
int monX, monY;
GetMonitorResolution(w, h);
GetMonitorPosition(monX, monY);
SetWindowLongPtr(Device.m_hWnd, GWL_STYLE, WS_VISIBLE | WS_POPUP);
SetWindowPos(Device.m_hWnd, HWND_TOP, 0, 0, w, h, SWP_FRAMECHANGED);
SetWindowPos(Device.m_hWnd, HWND_TOP, monX, monY, w, h, SWP_FRAMECHANGED);
}

#ifndef DEDICATED_SERVER
Expand Down
34 changes: 31 additions & 3 deletions src/xrEngine/device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -246,14 +246,24 @@ ENGINE_API xr_list<LOADING_EVENT> g_loading_events;

extern bool IsMainMenuActive(); //ECO_RENDER add

static HMONITOR g_StartupMonitor = NULL;
void InitMonitor()
{
if (!g_StartupMonitor)
{
POINT cursorPos;
GetCursorPos(&cursorPos);
g_StartupMonitor = MonitorFromPoint(cursorPos, MONITOR_DEFAULTTOPRIMARY);
}
}

void GetMonitorResolution(u32& horizontal, u32& vertical)
{
HMONITOR hMonitor = MonitorFromWindow(
Device.m_hWnd, MONITOR_DEFAULTTOPRIMARY);
InitMonitor();

MONITORINFO mi;
mi.cbSize = sizeof(mi);
if (GetMonitorInfoA(hMonitor, &mi))
if (GetMonitorInfoA(g_StartupMonitor, &mi))
{
horizontal = mi.rcMonitor.right - mi.rcMonitor.left;
vertical = mi.rcMonitor.bottom - mi.rcMonitor.top;
Expand All @@ -268,6 +278,24 @@ void GetMonitorResolution(u32& horizontal, u32& vertical)
}
}

void GetMonitorPosition(int& x, int& y)
{
InitMonitor();

MONITORINFO mi;
mi.cbSize = sizeof(mi);
if (GetMonitorInfoA(g_StartupMonitor, &mi))
{
x = mi.rcMonitor.left;
y = mi.rcMonitor.top;
}
else
{
x = 0;
y = 0;
}
}

float GetMonitorRefresh()
{
DEVMODE lpDevMode;
Expand Down
36 changes: 34 additions & 2 deletions src/xrEngine/x_ray.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ bool use_reshade = false;
extern bool init_reshade();
extern void unregister_reshade();
extern void GetMonitorResolution(u32& horizontal, u32& vertical);
extern void GetMonitorPosition(int& x, int& y);

//ImGui
#pragma comment(lib, "imgui.lib")
Expand Down Expand Up @@ -978,9 +979,11 @@ int APIENTRY WinMain_impl(HINSTANCE hInstance,
int splashH = logoRect.bottom - logoRect.top;

u32 screenW, screenH;
int monX, monY;
GetMonitorResolution(screenW, screenH);
int x = (screenW - splashW) / 2;
int y = (screenH - splashH) / 2;
GetMonitorPosition(monX, monY);
int x = monX + (screenW - splashW) / 2;
int y = monY + (screenH - splashH) / 2;

SetWindowPos(
logoWindow,
Expand Down Expand Up @@ -1179,6 +1182,35 @@ int APIENTRY WinMain(HINSTANCE hInstance,
char* lpCmdLine,
int nCmdShow)
{
// Enable per-monitor DPI awareness so GetMonitorInfo returns real pixel sizes.
// Without this, monitors with different DPI scaling report wrong resolutions
// (e.g. a 1920x1080 secondary monitor reports 2400x1290 when primary is at 125%).
// Uses dynamic loading since _WIN32_WINNT is too old for these APIs.
// Try Win10 1703+ API first, fall back to Win 8.1+ API, silently skip on Win 7 or older.
{
bool dpi_set = false;
HMODULE user32 = GetModuleHandleA("user32.dll");
if (user32)
{
typedef BOOL(WINAPI* pfnSetProcessDpiAwarenessContext)(HANDLE);
auto fn = (pfnSetProcessDpiAwarenessContext)GetProcAddress(user32, "SetProcessDpiAwarenessContext");
if (fn)
dpi_set = fn(/*DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2*/ (HANDLE)-4) != FALSE;
}
if (!dpi_set)
{
HMODULE shcore = LoadLibraryA("Shcore.dll");
if (shcore)
{
typedef HRESULT(WINAPI* pfnSetProcessDpiAwareness)(int);
auto fn = (pfnSetProcessDpiAwareness)GetProcAddress(shcore, "SetProcessDpiAwareness");
if (fn)
fn(/*PROCESS_PER_MONITOR_DPI_AWARE*/ 2);
FreeLibrary(shcore);
}
}
}

//DllMainOpenAL32(NULL, DLL_PROCESS_ATTACH, NULL);
DllMainXrCore(NULL, DLL_PROCESS_ATTACH, NULL);
DllMainXrPhysics(NULL, DLL_PROCESS_ATTACH, NULL);
Expand Down
9 changes: 6 additions & 3 deletions src/xrEngine/xr_ioc_cmd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -526,6 +526,7 @@ class CCC_VidMode : public CCC_Token
};

extern void GetMonitorResolution(u32& horizontal, u32& vertical);
extern void GetMonitorPosition(int& x, int& y);

class CCC_Screenmode : public CCC_Token
{
Expand Down Expand Up @@ -575,21 +576,23 @@ class CCC_Screenmode : public CCC_Token
if (!reset_required)
{
u32 monW, monH;
int monX, monY;
GetMonitorResolution(monW, monH);
GetMonitorPosition(monX, monY);
DWORD style = g_screenmode == 0 ? WS_OVERLAPPEDWINDOW : WS_POPUP;
SetWindowLongPtr(Device.m_hWnd, GWL_STYLE, WS_VISIBLE | style);

if (g_screenmode == 0)
{
LONG w = psCurrentVidMode[0];
LONG h = psCurrentVidMode[1];
int x = (LONG(monW) - w) / 2;
int y = (LONG(monH) - h) / 2;
int x = monX + (LONG(monW) - w) / 2;
int y = monY + (LONG(monH) - h) / 2;
SetWindowPos(Device.m_hWnd, HWND_TOP, x, y, w, h, SWP_FRAMECHANGED);
}
else
{
SetWindowPos(Device.m_hWnd, HWND_TOP, 0, 0, monW, monH, SWP_FRAMECHANGED);
SetWindowPos(Device.m_hWnd, HWND_TOP, monX, monY, monW, monH, SWP_FRAMECHANGED);
}
}
}
Expand Down