From 49ab0b36e53fc97cd84be172d6613445ec4c5ddd Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Tue, 24 Sep 2024 02:49:04 +0500 Subject: [PATCH] Added Win32PlatformOptions.GraphicsAdapterSelectionCallback (#17079) --- ...latformGraphicsDeviceAdapterDescription.cs | 8 ++++ .../OpenGl/Angle/AngleWin32EglDisplay.cs | 40 ++++++++++++++----- .../Avalonia.Win32/Win32PlatformOptions.cs | 10 ++++- 3 files changed, 47 insertions(+), 11 deletions(-) create mode 100644 src/Avalonia.Base/Platform/PlatformGraphicsDeviceAdapterDescription.cs diff --git a/src/Avalonia.Base/Platform/PlatformGraphicsDeviceAdapterDescription.cs b/src/Avalonia.Base/Platform/PlatformGraphicsDeviceAdapterDescription.cs new file mode 100644 index 0000000000..ccd3e0fb31 --- /dev/null +++ b/src/Avalonia.Base/Platform/PlatformGraphicsDeviceAdapterDescription.cs @@ -0,0 +1,8 @@ +namespace Avalonia.Platform; + +public class PlatformGraphicsDeviceAdapterDescription +{ + public string? Description { get; set; } + public byte[]? DeviceLuid { get; set; } + public byte[]? DeviceUuid { get; set; } +} diff --git a/src/Windows/Avalonia.Win32/OpenGl/Angle/AngleWin32EglDisplay.cs b/src/Windows/Avalonia.Win32/OpenGl/Angle/AngleWin32EglDisplay.cs index 892278a60a..ac78557a35 100644 --- a/src/Windows/Avalonia.Win32/OpenGl/Angle/AngleWin32EglDisplay.cs +++ b/src/Windows/Avalonia.Win32/OpenGl/Angle/AngleWin32EglDisplay.cs @@ -7,6 +7,7 @@ using System.Runtime.InteropServices; using Avalonia.OpenGL; using Avalonia.OpenGL.Angle; using Avalonia.OpenGL.Egl; +using Avalonia.Platform; using Avalonia.Win32.DirectX; using MicroCom.Runtime; using static Avalonia.OpenGL.Egl.EglConsts; @@ -63,31 +64,50 @@ namespace Avalonia.Win32.OpenGl.Angle { using var factory = MicroComRuntime.CreateProxyFor(pDxgiFactory, true); + var selectionCallback = AvaloniaLocator.Current.GetService() + ?.GraphicsAdapterSelectionCallback; + void* pAdapter = null; + + var applyArmAdrenoBlacklist = RuntimeInformation.ProcessArchitecture == Architecture.Arm64; + // As for now, we only need to redefine default adapter only on ARM64 just in case of Adreno GPU. - var redefineDefaultAdapter = RuntimeInformation.ProcessArchitecture == Architecture.Arm64; + var redefineDefaultAdapter = + selectionCallback != null + || applyArmAdrenoBlacklist; + if (redefineDefaultAdapter) { ushort adapterIndex = 0; - var adapters = new List<(IDXGIAdapter1 adapter, string name)>(); + var adapters = new List<(IDXGIAdapter1 adapter, PlatformGraphicsDeviceAdapterDescription desc)>(); while (factory.EnumAdapters1(adapterIndex, &pAdapter) == 0) { var adapter = MicroComRuntime.CreateProxyFor(pAdapter, true); var desc = adapter.Desc1; - var name = Marshal.PtrToStringUni(new IntPtr(desc.Description))!.ToLowerInvariant(); - adapters.Add((adapter, name)); + var name = Marshal.PtrToStringUni(new IntPtr(desc.Description))?.ToLowerInvariant(); + var luid = BitConverter.GetBytes(desc.AdapterLuid); + adapters.Add((adapter, new() { Description = name, DeviceLuid = luid })); adapterIndex++; } if (adapters.Count == 0) throw new OpenGlException("No adapters found"); - chosenAdapter = adapters - .OrderByDescending(x => - // Put adreno in lower priority - it's broken in Avalonia. - x.name.Contains("adreno") ? -1 : 0) - .First().adapter - .CloneReference(); + if (applyArmAdrenoBlacklist && adapters.Count > 1) + { + for (var c = adapters.Count - 1; c >= 0; c--) + if (adapters[c].desc.Description?.Contains("adreno") == true) + { + adapters[c].adapter.Dispose(); + adapters.RemoveAt(c); + } + } + + var chosenAdapterIndex = 0; + if (selectionCallback != null) + chosenAdapterIndex = selectionCallback(adapters.Select(a => a.desc).ToArray()); + + chosenAdapter = adapters[chosenAdapterIndex].adapter.CloneReference(); foreach (var a in adapters) a.adapter.Dispose(); diff --git a/src/Windows/Avalonia.Win32/Win32PlatformOptions.cs b/src/Windows/Avalonia.Win32/Win32PlatformOptions.cs index 7230bc1f24..351b374e3e 100644 --- a/src/Windows/Avalonia.Win32/Win32PlatformOptions.cs +++ b/src/Windows/Avalonia.Win32/Win32PlatformOptions.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using Avalonia.OpenGL; using Avalonia.Platform; @@ -168,4 +169,11 @@ public class Win32PlatformOptions /// Gets or sets the application's DPI awareness. /// public Win32DpiAwareness DpiAwareness { get; set; } = Win32DpiAwareness.PerMonitorDpiAware; + + /// + /// Specifies a callback method to be called when compositor needs to create a platform graphics device + /// Currently is only called for AngleEgl rendering mode when DirectX 11 is used + /// + public Func, int>? + GraphicsAdapterSelectionCallback { get; set; } }