From bfa2319e77d5a828a11f2e6b3bead596a113e585 Mon Sep 17 00:00:00 2001 From: Nick Nassiri Date: Thu, 2 Jul 2026 23:52:36 -0700 Subject: [PATCH] Win32/ARM64: let GraphicsAdapterSelectionCallback see unfiltered adapters and warn on Adreno WARP fallback (#21695) * win32: let GraphicsAdapterSelectionCallback see unfiltered adapters on ARM64 The ARM64 Adreno blocklist in AngleWin32EglDisplay removed every Adreno adapter from the list before it was handed to GraphicsAdapterSelectionCallback, so an application had no way to opt back into hardware acceleration and no indication that WARP (the Microsoft Basic Render Driver) was being forced. Stop mutating the adapter list. The blocklist now only moves the *default* selection to the first non-Adreno adapter when no callback is supplied, and logs a warning about the CPU-usage impact and the available workarounds. When a callback is present it receives the full, unfiltered adapter list and its choice is used as-is. As a side effect this also removes a latent IndexOutOfRange: the old code could empty the list when every enumerated adapter was Adreno. Refs #21689 * Update src/Windows/Avalonia.Win32/OpenGl/Angle/AngleWin32EglDisplay.cs Co-authored-by: Max Katz --------- Co-authored-by: nickna Co-authored-by: Max Katz --- .../OpenGl/Angle/AngleWin32EglDisplay.cs | 30 ++++++++++++------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/src/Windows/Avalonia.Win32/OpenGl/Angle/AngleWin32EglDisplay.cs b/src/Windows/Avalonia.Win32/OpenGl/Angle/AngleWin32EglDisplay.cs index 9b23bc9aa8..afee6efd23 100644 --- a/src/Windows/Avalonia.Win32/OpenGl/Angle/AngleWin32EglDisplay.cs +++ b/src/Windows/Avalonia.Win32/OpenGl/Angle/AngleWin32EglDisplay.cs @@ -4,6 +4,7 @@ using System.ComponentModel; using System.Linq; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using Avalonia.Logging; using Avalonia.OpenGL; using Avalonia.OpenGL.Angle; using Avalonia.OpenGL.Egl; @@ -95,19 +96,28 @@ namespace Avalonia.Win32.OpenGl.Angle if (adapters.Count == 0) throw new OpenGlException("No adapters found"); - 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); - } - } - + // The Adreno blacklist (see #10405) now only moves the *default* selection away + // from Adreno GPUs - it no longer hides adapters from the selection callback, so + // an application can deliberately opt back into hardware acceleration. var chosenAdapterIndex = 0; if (selectionCallback != null) + { chosenAdapterIndex = selectionCallback(adapters.Select(a => a.desc).ToArray()); + } + else if (applyArmAdrenoBlacklist && adapters.Count > 1) + { + var firstNonAdreno = adapters.FindIndex(a => a.desc.Description?.Contains("adreno") != true); + if (firstNonAdreno > 0) + { + chosenAdapterIndex = firstNonAdreno; + Logger.TryGet(LogEventLevel.Warning, "OpenGL")?.Log(null, + "ARM64 Adreno GPU detected; the Adreno rendering blocklist is forcing a " + + "fallback to '{FallbackAdapter}' (typically a software renderer). Set " + + "Win32PlatformOptions.GraphicsAdapterSelectionCallback to choose an adapter " + + "explicitly, or switch Win32PlatformOptions.RenderingMode to Vulkan or Wgl.", + adapters[firstNonAdreno].desc.Description); + } + } chosenAdapter = adapters[chosenAdapterIndex].adapter.CloneReference();