Browse Source

Merge pull request #12574 from MrJul/perf/win32-angle-creation

Win32+Angle: reuse the first created D3D11 display
pull/12774/head
Max Katz 3 years ago
committed by GitHub
parent
commit
52a3beeae4
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 143
      src/Windows/Avalonia.Win32/OpenGl/Angle/AngleWin32PlatformGraphics.cs
  2. 48
      src/Windows/Avalonia.Win32/OpenGl/Angle/AngleWin32PlatformGraphicsFactory.cs
  3. 91
      src/Windows/Avalonia.Win32/OpenGl/Angle/D3D11AngleWin32PlatformGraphics.cs
  4. 53
      src/Windows/Avalonia.Win32/OpenGl/Angle/D3D9AngleWin32PlatformGraphics.cs
  5. 4
      src/Windows/Avalonia.Win32/Win32GlManager.cs
  6. 5
      src/Windows/Avalonia.Win32/WindowImpl.cs

143
src/Windows/Avalonia.Win32/OpenGl/Angle/AngleWin32PlatformGraphics.cs

@ -1,143 +0,0 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Avalonia.Logging;
using Avalonia.OpenGL;
using Avalonia.OpenGL.Angle;
using Avalonia.OpenGL.Egl;
using Avalonia.Platform;
namespace Avalonia.Win32.OpenGl.Angle;
internal class AngleWin32PlatformGraphics : IPlatformGraphics, IPlatformGraphicsOpenGlContextFactory
{
private readonly Win32AngleEglInterface _egl;
private readonly AngleWin32EglDisplay? _sharedDisplay;
private EglContext? _sharedContext;
[MemberNotNullWhen(true, nameof(_sharedDisplay))]
public bool UsesSharedContext => _sharedDisplay is not null;
public AngleOptions.PlatformApi PlatformApi { get; }
public IPlatformGraphicsContext CreateContext()
{
if (UsesSharedContext)
throw new InvalidOperationException();
var display = AngleWin32EglDisplay.CreateD3D11Display(_egl);
var success = false;
try
{
var rv = display.CreateContext(new EglContextOptions
{
DisposeCallback = display.Dispose,
ExtraFeatures = new Dictionary<Type, Func<EglContext, object>>
{
[typeof(IGlPlatformSurfaceRenderTargetFactory)] = _ => new AngleD3DTextureFeature(),
[typeof(IGlContextExternalObjectsFeature)] = context => new AngleExternalObjectsFeature(context)
}
});
success = true;
return rv;
}
finally
{
if (!success)
display.Dispose();
}
}
public IPlatformGraphicsContext GetSharedContext()
{
if (!UsesSharedContext)
throw new InvalidOperationException();
if (_sharedContext == null || _sharedContext.IsLost)
{
_sharedContext?.Dispose();
_sharedContext = null;
_sharedContext = _sharedDisplay.CreateContext(new EglContextOptions());
}
return _sharedContext;
}
public AngleWin32PlatformGraphics(Win32AngleEglInterface egl, AngleWin32EglDisplay display)
: this(egl, display.PlatformApi)
{
_sharedDisplay = display;
}
public AngleWin32PlatformGraphics(Win32AngleEglInterface egl, AngleOptions.PlatformApi api)
{
_egl = egl;
PlatformApi = api;
}
public static AngleWin32PlatformGraphics? TryCreate(AngleOptions? options)
{
Win32AngleEglInterface egl;
try
{
egl = new();
}
catch (Exception e)
{
Logger.TryGet(LogEventLevel.Error, "OpenGL")
?.Log(null, "Unable to load ANGLE: {0}", e);
return null;
}
foreach (var api in (options?.AllowedPlatformApis ?? new []
{
AngleOptions.PlatformApi.DirectX11
}).Distinct())
if (api == AngleOptions.PlatformApi.DirectX11)
{
try
{
using var display = AngleWin32EglDisplay.CreateD3D11Display(egl);
using var ctx = display.CreateContext(new EglContextOptions());
ctx.MakeCurrent().Dispose();
}
catch (Exception e)
{
Logger.TryGet(LogEventLevel.Error, "OpenGL")
?.Log(null, "Unable to initialize ANGLE-based rendering with DirectX11 : {0}", e);
continue;
}
return new AngleWin32PlatformGraphics(egl, AngleOptions.PlatformApi.DirectX11);
}
else
{
AngleWin32EglDisplay? sharedDisplay = null;
try
{
sharedDisplay = AngleWin32EglDisplay.CreateD3D9Display(egl);
using (var ctx = sharedDisplay.CreateContext(new EglContextOptions()))
ctx.MakeCurrent().Dispose();
return new AngleWin32PlatformGraphics(egl, sharedDisplay);
}
catch (Exception e)
{
sharedDisplay?.Dispose();
Logger.TryGet(LogEventLevel.Error, "OpenGL")
?.Log(null, "Unable to initialize ANGLE-based rendering with DirectX9 : {0}", e);
}
}
return null;
}
public IGlContext CreateContext(IEnumerable<GlVersion>? versions)
{
if (UsesSharedContext)
throw new InvalidOperationException();
if (versions != null && versions.All(v => v.Type != GlProfileType.OpenGLES || v.Major != 3))
throw new OpenGlException("Unable to create context with requested version");
return (IGlContext)CreateContext();
}
}

48
src/Windows/Avalonia.Win32/OpenGl/Angle/AngleWin32PlatformGraphicsFactory.cs

@ -0,0 +1,48 @@
using System;
using System.Linq;
using Avalonia.Logging;
using Avalonia.OpenGL.Angle;
using Avalonia.Platform;
namespace Avalonia.Win32.OpenGl.Angle;
internal static class AngleWin32PlatformGraphicsFactory
{
public static IPlatformGraphics? TryCreate(AngleOptions? options)
{
Win32AngleEglInterface egl;
try
{
egl = new();
}
catch (Exception e)
{
Logger.TryGet(LogEventLevel.Error, "OpenGL")
?.Log(null, "Unable to load ANGLE: {0}", e);
return null;
}
var allowedPlatformApis = options?.AllowedPlatformApis ?? new[] { AngleOptions.PlatformApi.DirectX11 };
foreach (var api in allowedPlatformApis.Distinct())
{
switch (api)
{
case AngleOptions.PlatformApi.DirectX11
when D3D11AngleWin32PlatformGraphics.TryCreate(egl) is { } platformGraphics:
return platformGraphics;
case AngleOptions.PlatformApi.DirectX9
when D3D9AngleWin32PlatformGraphics.TryCreate(egl) is { } platformGraphics:
return platformGraphics;
default:
Logger.TryGet(LogEventLevel.Error, "OpenGL")
?.Log(null, "Unknown requested PlatformApi {0}", api);
break;
}
}
return null;
}
}

91
src/Windows/Avalonia.Win32/OpenGl/Angle/D3D11AngleWin32PlatformGraphics.cs

@ -0,0 +1,91 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using Avalonia.Logging;
using Avalonia.OpenGL;
using Avalonia.OpenGL.Angle;
using Avalonia.OpenGL.Egl;
using Avalonia.Platform;
namespace Avalonia.Win32.OpenGl.Angle;
internal sealed class D3D11AngleWin32PlatformGraphics : IPlatformGraphics, IPlatformGraphicsOpenGlContextFactory
{
private readonly Win32AngleEglInterface _egl;
private AngleWin32EglDisplay? _initialDisplay;
public D3D11AngleWin32PlatformGraphics(Win32AngleEglInterface egl, AngleWin32EglDisplay? initialDisplay)
{
_egl = egl;
_initialDisplay = initialDisplay;
}
public bool UsesSharedContext
=> false;
public IPlatformGraphicsContext CreateContext()
{
var display = Interlocked.Exchange(ref _initialDisplay, null);
if (display is { IsLost: true })
display = null;
display ??= AngleWin32EglDisplay.CreateD3D11Display(_egl);
return CreateContextForDisplay(display);
}
private static EglContext CreateContextForDisplay(AngleWin32EglDisplay display)
{
var success = false;
try
{
var context = display.CreateContext(new EglContextOptions
{
DisposeCallback = display.Dispose,
ExtraFeatures = new Dictionary<Type, Func<EglContext, object>>
{
[typeof(IGlPlatformSurfaceRenderTargetFactory)] = _ => new AngleD3DTextureFeature(),
[typeof(IGlContextExternalObjectsFeature)] = context => new AngleExternalObjectsFeature(context)
}
});
success = true;
return context;
}
finally
{
if (!success)
display.Dispose();
}
}
public IGlContext CreateContext(IEnumerable<GlVersion>? versions)
{
if (versions is not null && versions.All(v => v.Type != GlProfileType.OpenGLES || v.Major != 3))
throw new OpenGlException("Unable to create context with requested version");
return (IGlContext)CreateContext();
}
IPlatformGraphicsContext IPlatformGraphics.GetSharedContext()
=> throw new InvalidOperationException();
public static D3D11AngleWin32PlatformGraphics? TryCreate(Win32AngleEglInterface egl)
{
AngleWin32EglDisplay? display = null;
try
{
display = AngleWin32EglDisplay.CreateD3D11Display(egl);
using var ctx = display.CreateContext(new EglContextOptions());
ctx.MakeCurrent().Dispose();
}
catch (Exception e)
{
display?.Dispose();
Logger.TryGet(LogEventLevel.Error, "OpenGL")
?.Log(null, "Unable to initialize ANGLE-based rendering with DirectX11 : {0}", e);
return null;
}
return new D3D11AngleWin32PlatformGraphics(egl, display);
}
}

53
src/Windows/Avalonia.Win32/OpenGl/Angle/D3D9AngleWin32PlatformGraphics.cs

@ -0,0 +1,53 @@
using System;
using Avalonia.Logging;
using Avalonia.OpenGL.Angle;
using Avalonia.OpenGL.Egl;
using Avalonia.Platform;
namespace Avalonia.Win32.OpenGl.Angle;
internal sealed class D3D9AngleWin32PlatformGraphics : IPlatformGraphics
{
private readonly AngleWin32EglDisplay _sharedDisplay;
private EglContext? _sharedContext;
public D3D9AngleWin32PlatformGraphics(AngleWin32EglDisplay sharedDisplay)
=> _sharedDisplay = sharedDisplay;
public bool UsesSharedContext
=> true;
public IPlatformGraphicsContext GetSharedContext()
{
if (_sharedContext is { IsLost: true })
{
_sharedContext.Dispose();
_sharedContext = null;
}
return _sharedContext ??= _sharedDisplay.CreateContext(new EglContextOptions());
}
IPlatformGraphicsContext IPlatformGraphics.CreateContext()
=> throw new InvalidOperationException();
public static D3D9AngleWin32PlatformGraphics? TryCreate(Win32AngleEglInterface egl)
{
AngleWin32EglDisplay? sharedDisplay = null;
try
{
sharedDisplay = AngleWin32EglDisplay.CreateD3D9Display(egl);
using var ctx = sharedDisplay.CreateContext(new EglContextOptions());
ctx.MakeCurrent().Dispose();
}
catch (Exception e)
{
sharedDisplay?.Dispose();
Logger.TryGet(LogEventLevel.Error, "OpenGL")
?.Log(null, "Unable to initialize ANGLE-based rendering with DirectX9 : {0}", e);
return null;
}
return new D3D9AngleWin32PlatformGraphics(sharedDisplay);
}
}

4
src/Windows/Avalonia.Win32/Win32GlManager.cs

@ -45,9 +45,9 @@ static class Win32GlManager
if (renderingMode == Win32RenderingMode.AngleEgl)
{
var egl = AngleWin32PlatformGraphics.TryCreate(AvaloniaLocator.Current.GetService<AngleOptions>() ?? new());
var egl = AngleWin32PlatformGraphicsFactory.TryCreate(AvaloniaLocator.Current.GetService<AngleOptions>() ?? new());
if (egl != null && egl.PlatformApi == AngleOptions.PlatformApi.DirectX11)
if (egl is D3D11AngleWin32PlatformGraphics)
{
TryRegisterComposition(opts);
return egl;

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

@ -135,8 +135,7 @@ namespace Avalonia.Win32
var compositionConnector = AvaloniaLocator.Current.GetService<WinUiCompositorConnection>();
var isUsingAngleDX11 = glPlatform is AngleWin32PlatformGraphics angle &&
angle.PlatformApi == AngleOptions.PlatformApi.DirectX11;
var isUsingAngleDX11 = glPlatform is D3D11AngleWin32PlatformGraphics;
_isUsingComposition = compositionConnector is { } && isUsingAngleDX11;
DxgiConnection? dxgiConnection = null;
@ -172,7 +171,7 @@ namespace Avalonia.Win32
}
else
{
if (glPlatform is AngleWin32PlatformGraphics)
if (glPlatform is D3D11AngleWin32PlatformGraphics or D3D9AngleWin32PlatformGraphics)
_gl = new EglGlPlatformSurface(this);
else if (glPlatform is WglPlatformOpenGlInterface)
_gl = new WglGlPlatformSurface(this);

Loading…
Cancel
Save