From 4413f5fa2992a8e2b112380807acb99f45e28d23 Mon Sep 17 00:00:00 2001 From: lindexi Date: Thu, 22 Jan 2026 23:28:46 +0800 Subject: [PATCH] Reduce the number of WrapDirect3D11Texture calls (#20517) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Reduce the number of WrapDirect3D11Texture calls Reduce the number of WrapDirect3D11Texture calls by tying the EglSurface lifetime to _renderTexture. When testing on a 4K display, I observed that eglCreatePbufferFromClientBuffer, which is invoked by WrapDirect3D11Texture, can take around 5 ms per frame. By reducing the number of eglCreatePbufferFromClientBuffer calls, I was able to improve rendering performance by about 30%. However, I’m not sure why the previous implementation needed to call WrapDirect3D11Texture on every frame. * Remove the commented code #Conflicts: # src/Windows/Avalonia.Win32/DirectX/DxgiRenderTarget.cs --- .../Avalonia.Win32/DirectX/DxgiConnection.cs | 2 +- .../DirectX/DxgiRenderTarget.cs | 24 +++++++++++++------ 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/Windows/Avalonia.Win32/DirectX/DxgiConnection.cs b/src/Windows/Avalonia.Win32/DirectX/DxgiConnection.cs index c1e77aab76..d26769e8da 100644 --- a/src/Windows/Avalonia.Win32/DirectX/DxgiConnection.cs +++ b/src/Windows/Avalonia.Win32/DirectX/DxgiConnection.cs @@ -131,7 +131,7 @@ namespace Avalonia.Win32.DirectX using var output = MicroComRuntime.CreateProxyFor(outputPointer, true); DXGI_OUTPUT_DESC outputDesc = output.Desc; - var hMonitor = new HMONITOR(outputDesc.Monitor.Value); + var hMonitor = new HMONITOR((IntPtr)outputDesc.Monitor.Value); var frequency = monitorFrequencies.TryGetValue(hMonitor, out uint frequencyValue) ? diff --git a/src/Windows/Avalonia.Win32/DirectX/DxgiRenderTarget.cs b/src/Windows/Avalonia.Win32/DirectX/DxgiRenderTarget.cs index 513aba4f20..000c818fdf 100644 --- a/src/Windows/Avalonia.Win32/DirectX/DxgiRenderTarget.cs +++ b/src/Windows/Avalonia.Win32/DirectX/DxgiRenderTarget.cs @@ -23,6 +23,7 @@ namespace Avalonia.Win32.DirectX private IUnknown? _renderTexture; private RECT _clientRect; + private EglSurface? _surface; public DxgiRenderTarget(EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo window, EglContext context, DxgiConnection connection) : base(context) { @@ -81,7 +82,6 @@ namespace Avalonia.Win32.DirectX } var contextLock = Context.EnsureCurrent(); - EglSurface? surface = null; IDisposable? transaction = null; var success = false; try @@ -94,6 +94,9 @@ namespace Avalonia.Win32.DirectX if (_renderTexture is not null) { + _surface?.Dispose(); + _surface = null; + _renderTexture.Dispose(); _renderTexture = null; } @@ -112,19 +115,24 @@ namespace Avalonia.Win32.DirectX var texture = _renderTexture; if (texture is null) { + _surface?.Dispose(); + _surface = null; + Guid textureGuid = ID3D11Texture2DGuid; texture = MicroComRuntime.CreateProxyFor(_swapChain.GetBuffer(0, &textureGuid), true); } _renderTexture = texture; - // I also have to get the pointer to this texture directly - surface = ((AngleWin32EglDisplay)Context.Display).WrapDirect3D11Texture(MicroComRuntime.GetNativeIntPtr(_renderTexture), - 0, 0, size.Width, size.Height); + if (_surface is null) + { + // I also have to get the pointer to this texture directly + _surface = ((AngleWin32EglDisplay)Context.Display).WrapDirect3D11Texture(MicroComRuntime.GetNativeIntPtr(_renderTexture), + 0, 0, size.Width, size.Height); + } - var res = base.BeginDraw(surface, _window.Size, _window.Scaling, () => + var res = base.BeginDraw(_surface, _window.Size, _window.Scaling, () => { _swapChain.Present((ushort)0U, (ushort)0U); - surface.Dispose(); transaction?.Dispose(); contextLock?.Dispose(); }, true); @@ -135,7 +143,8 @@ namespace Avalonia.Win32.DirectX { if (!success) { - surface?.Dispose(); + _surface?.Dispose(); + _surface = null; if (_renderTexture is not null) { _renderTexture.Dispose(); @@ -153,6 +162,7 @@ namespace Avalonia.Win32.DirectX _dxgiDevice?.Dispose(); _dxgiFactory?.Dispose(); _swapChain?.Dispose(); + _surface?.Dispose(); _renderTexture?.Dispose(); }