diff --git a/src/Windows/Avalonia.Win32/DirectX/DxgiConnection.cs b/src/Windows/Avalonia.Win32/DirectX/DxgiConnection.cs index 1482a5cc62..c1e77aab76 100644 --- a/src/Windows/Avalonia.Win32/DirectX/DxgiConnection.cs +++ b/src/Windows/Avalonia.Win32/DirectX/DxgiConnection.cs @@ -1,13 +1,20 @@ using System; +using System.Collections.Generic; using System.Diagnostics; +using System.Runtime.InteropServices; using System.Threading.Tasks; using Avalonia.Logging; using Avalonia.OpenGL.Egl; using Avalonia.Rendering; -using static Avalonia.Win32.Interop.UnmanagedMethods; -using static Avalonia.Win32.DirectX.DirectXUnmanagedMethods; + using MicroCom.Runtime; +using Windows.Win32; +using Windows.Win32.Graphics.Gdi; + +using static Avalonia.Win32.DirectX.DirectXUnmanagedMethods; +using static Avalonia.Win32.Interop.UnmanagedMethods; + namespace Avalonia.Win32.DirectX { internal unsafe class DxgiConnection : IRenderTimer, IWindowsSurfaceFactory @@ -111,6 +118,8 @@ namespace Avalonia.Win32.DirectX ushort adapterIndex = 0; + Dictionary monitorFrequencies = GetAllMonitorFrequencies(); + // this looks odd, but that's just how one enumerates adapters in DXGI while (fact.EnumAdapters(adapterIndex, &adapterPointer) == 0) { @@ -122,8 +131,12 @@ namespace Avalonia.Win32.DirectX using var output = MicroComRuntime.CreateProxyFor(outputPointer, true); DXGI_OUTPUT_DESC outputDesc = output.Desc; - var screen = Win32Platform.Instance.Screen.ScreenFromHMonitor((IntPtr)outputDesc.Monitor.Value); - var frequency = screen?.Frequency ?? highestRefreshRate; + var hMonitor = new HMONITOR(outputDesc.Monitor.Value); + + var frequency = + monitorFrequencies.TryGetValue(hMonitor, out uint frequencyValue) ? + frequencyValue : + highestRefreshRate; if (highestRefreshRate < frequency) { @@ -145,6 +158,33 @@ namespace Avalonia.Win32.DirectX } + private unsafe Dictionary GetAllMonitorFrequencies() + { + var monitorHandlers = ScreenImpl.GetAllDisplayMonitorHandlers(); + var dictionary = new Dictionary(monitorHandlers.Count); + + foreach (var monitorHandler in monitorHandlers) + { + var info = MONITORINFOEX.Create(); + var hMonitor = new HMONITOR(monitorHandler); + PInvoke.GetMonitorInfo(hMonitor, (MONITORINFO*)&info); + + var deviceMode = new DEVMODEW + { + dmFields = DEVMODE_FIELD_FLAGS.DM_DISPLAYORIENTATION | DEVMODE_FIELD_FLAGS.DM_DISPLAYFREQUENCY, + dmSize = (ushort)Marshal.SizeOf() + }; + PInvoke.EnumDisplaySettings(info.szDevice.ToString(), ENUM_DISPLAY_SETTINGS_MODE.ENUM_CURRENT_SETTINGS, + ref deviceMode); + + var frequency = deviceMode.dmDisplayFrequency; + + dictionary[hMonitor] = frequency; + } + + return dictionary; + } + // Used the windows composition as a blueprint for this startup/creation private static bool TryCreateAndRegisterCore() { diff --git a/src/Windows/Avalonia.Win32/ScreenImpl.cs b/src/Windows/Avalonia.Win32/ScreenImpl.cs index 0f73d39249..b4bff3da35 100644 --- a/src/Windows/Avalonia.Win32/ScreenImpl.cs +++ b/src/Windows/Avalonia.Win32/ScreenImpl.cs @@ -15,6 +15,11 @@ internal unsafe class ScreenImpl : ScreensBase protected override int GetScreenCount() => GetSystemMetrics(SystemMetric.SM_CMONITORS); protected override IReadOnlyList GetAllScreenKeys() + { + return GetAllDisplayMonitorHandlers(); + } + + public static List GetAllDisplayMonitorHandlers() { var screens = new List(); var gcHandle = GCHandle.Alloc(screens);