Browse Source

Fix the DxgiRenderTimerLoop thread get the screens from UI thread (#20511)

Fixes https://github.com/AvaloniaUI/Avalonia/issues/20508
pull/20513/head
lindexi 2 weeks ago
committed by GitHub
parent
commit
93eeadf3c1
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 48
      src/Windows/Avalonia.Win32/DirectX/DxgiConnection.cs
  2. 5
      src/Windows/Avalonia.Win32/ScreenImpl.cs

48
src/Windows/Avalonia.Win32/DirectX/DxgiConnection.cs

@ -1,13 +1,20 @@
using System; using System;
using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading.Tasks; using System.Threading.Tasks;
using Avalonia.Logging; using Avalonia.Logging;
using Avalonia.OpenGL.Egl; using Avalonia.OpenGL.Egl;
using Avalonia.Rendering; using Avalonia.Rendering;
using static Avalonia.Win32.Interop.UnmanagedMethods;
using static Avalonia.Win32.DirectX.DirectXUnmanagedMethods;
using MicroCom.Runtime; 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 namespace Avalonia.Win32.DirectX
{ {
internal unsafe class DxgiConnection : IRenderTimer, IWindowsSurfaceFactory internal unsafe class DxgiConnection : IRenderTimer, IWindowsSurfaceFactory
@ -111,6 +118,8 @@ namespace Avalonia.Win32.DirectX
ushort adapterIndex = 0; ushort adapterIndex = 0;
Dictionary<HMONITOR /*MonitorHandler*/, uint /*Frequency*/> monitorFrequencies = GetAllMonitorFrequencies();
// this looks odd, but that's just how one enumerates adapters in DXGI // this looks odd, but that's just how one enumerates adapters in DXGI
while (fact.EnumAdapters(adapterIndex, &adapterPointer) == 0) while (fact.EnumAdapters(adapterIndex, &adapterPointer) == 0)
{ {
@ -122,8 +131,12 @@ namespace Avalonia.Win32.DirectX
using var output = MicroComRuntime.CreateProxyFor<IDXGIOutput>(outputPointer, true); using var output = MicroComRuntime.CreateProxyFor<IDXGIOutput>(outputPointer, true);
DXGI_OUTPUT_DESC outputDesc = output.Desc; DXGI_OUTPUT_DESC outputDesc = output.Desc;
var screen = Win32Platform.Instance.Screen.ScreenFromHMonitor((IntPtr)outputDesc.Monitor.Value); var hMonitor = new HMONITOR(outputDesc.Monitor.Value);
var frequency = screen?.Frequency ?? highestRefreshRate;
var frequency =
monitorFrequencies.TryGetValue(hMonitor, out uint frequencyValue) ?
frequencyValue :
highestRefreshRate;
if (highestRefreshRate < frequency) if (highestRefreshRate < frequency)
{ {
@ -145,6 +158,33 @@ namespace Avalonia.Win32.DirectX
} }
private unsafe Dictionary<HMONITOR /*MonitorHandler*/, uint /*Frequency*/> GetAllMonitorFrequencies()
{
var monitorHandlers = ScreenImpl.GetAllDisplayMonitorHandlers();
var dictionary = new Dictionary<HMONITOR /*MonitorHandler*/, uint /*Frequency*/>(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<DEVMODEW>()
};
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 // Used the windows composition as a blueprint for this startup/creation
private static bool TryCreateAndRegisterCore() private static bool TryCreateAndRegisterCore()
{ {

5
src/Windows/Avalonia.Win32/ScreenImpl.cs

@ -15,6 +15,11 @@ internal unsafe class ScreenImpl : ScreensBase<nint, WinScreen>
protected override int GetScreenCount() => GetSystemMetrics(SystemMetric.SM_CMONITORS); protected override int GetScreenCount() => GetSystemMetrics(SystemMetric.SM_CMONITORS);
protected override IReadOnlyList<nint> GetAllScreenKeys() protected override IReadOnlyList<nint> GetAllScreenKeys()
{
return GetAllDisplayMonitorHandlers();
}
public static List<nint> GetAllDisplayMonitorHandlers()
{ {
var screens = new List<nint>(); var screens = new List<nint>();
var gcHandle = GCHandle.Alloc(screens); var gcHandle = GCHandle.Alloc(screens);

Loading…
Cancel
Save