Skip to content

Commit 2de0d2a

Browse files
committed
Add DPI and scale to GraphicsOutput
1 parent 8ae1478 commit 2de0d2a

2 files changed

Lines changed: 48 additions & 0 deletions

File tree

sources/engine/Stride.Graphics/Direct3D/GraphicsOutput.Direct3D.cs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,18 @@ public sealed unsafe partial class GraphicsOutput
173173
/// </summary>
174174
public Vector2 WhitePoint { get; }
175175

176+
/// <summary>
177+
/// Gets the DPI scale factor of the display attached to this output, which is used
178+
/// to convert between physical pixels and device-independent pixels (DIPs).
179+
/// </summary>
180+
public float DpiScale { get; }
181+
182+
/// <summary>
183+
/// Gets the dots per inch (DPI) of the display attached to this output
184+
/// in the horizontal and vertical directions.
185+
/// </summary>
186+
public Int2 Dpi { get; }
187+
176188

177189
/// <summary>
178190
/// Initializes a new instance of <see cref="GraphicsOutput"/>.
@@ -221,6 +233,10 @@ internal GraphicsOutput(GraphicsAdapter adapter, ComPtr<IDXGIOutput> nativeOutpu
221233
_ => DisplayRotation.Default
222234
};
223235

236+
GetDpiForMonitor(MonitorHandle, out int dpiX, out int dpiY);
237+
Dpi = new Int2(dpiX, dpiY);
238+
DpiScale = dpiX / 96.0f;
239+
224240
if (dxgiOutputVersion >= 6)
225241
{
226242
var nativeOutput6 = nativeOutput.AsComPtrUnsafe<IDXGIOutput, IDXGIOutput6>();
@@ -312,6 +328,31 @@ static string GetFriendlyName(char* deviceName)
312328
}
313329
return null;
314330
}
331+
332+
//
333+
// Attempts to get the DPI for the monitor associated with this output using Win32 API.
334+
//
335+
static void GetDpiForMonitor(nint hMonitor, out int dpiX, out int dpiY)
336+
{
337+
uint x, y;
338+
339+
// Windows 8.1+: shcore!GetDpiForMonitor
340+
// TODO: Consider using GetDpiForWindow (Windows 10, version 1607+) as a fallback, which can be more accurate in multi-monitor setups with different DPI settings.
341+
// TODO: Consider a fallback to GetDeviceCaps(LOGPIXELSX/Y) via a DC if GetDpiForMonitor is not available, which is the traditional way to get DPI on older Windows versions.
342+
HResult result = Win32.GetDpiForMonitor(hMonitor, Win32.MDT_EFFECTIVE_DPI, &x, &y);
343+
344+
if (result.IsSuccess)
345+
{
346+
dpiX = (int) x;
347+
dpiY = (int) y;
348+
}
349+
else
350+
{
351+
// Defaults to 96 dpi, which corresponds to 100% scaling
352+
dpiX = 96;
353+
dpiY = 96;
354+
}
355+
}
315356
}
316357

317358
/// <inheritdoc/>

sources/engine/Stride.Graphics/Direct3D/Win32.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,13 @@ public struct DISPLAY_DEVICEW
3939
[DllImport("user32", ExactSpelling = true)]
4040
public static unsafe extern BOOL EnumDisplayDevicesW(char* lpDevice, uint iDevNum, DISPLAY_DEVICEW* lpDisplayDevice, uint dwFlags);
4141

42+
// MONITOR_DPI_TYPE
43+
public const int MDT_EFFECTIVE_DPI = 0;
44+
45+
// GetDpiForMonitor(HMONITOR hmonitor, MONITOR_DPI_TYPE dpiType, UINT* dpiX, UINT* dpiY);
46+
[DllImport("shcore", ExactSpelling = true)]
47+
public static unsafe extern int GetDpiForMonitor(nint hmonitor, int dpiType, uint* dpiX, uint* dpiY);
48+
4249
#region Helper structs and types
4350

4451
public readonly struct BOOL(int value)

0 commit comments

Comments
 (0)