Browse Source

Extracted ANGLE-based EGL display to a separate class and added some DX-interop features

pull/4624/head
Nikita Tsukanov 6 years ago
parent
commit
90b405952e
  1. 31
      src/Avalonia.OpenGL/Angle/AngleEglInterface.cs
  2. 88
      src/Avalonia.OpenGL/Angle/AngleWin32EglDisplay.cs
  3. 10
      src/Avalonia.OpenGL/EglConsts.cs
  4. 76
      src/Avalonia.OpenGL/EglDisplay.cs
  5. 7
      src/Avalonia.OpenGL/EglGlPlatformFeature.cs
  6. 29
      src/Avalonia.OpenGL/EglInterface.cs
  7. 3
      src/Windows/Avalonia.Win32/Win32GlManager.cs

31
src/Avalonia.OpenGL/Angle/AngleEglInterface.cs

@ -0,0 +1,31 @@
using System;
using System.Runtime.InteropServices;
using Avalonia.Platform;
using Avalonia.Platform.Interop;
namespace Avalonia.OpenGL.Angle
{
public class AngleEglInterface : EglInterface
{
[DllImport("libegl.dll", CharSet = CharSet.Ansi)]
static extern IntPtr eglGetProcAddress(string proc);
public AngleEglInterface() : base(LoadAngle())
{
}
static Func<string, IntPtr> LoadAngle()
{
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
throw new PlatformNotSupportedException();
{
var disp = eglGetProcAddress("eglGetPlatformDisplayEXT");
if (disp == IntPtr.Zero)
throw new OpenGlException("libegl.dll doesn't have eglGetPlatformDisplayEXT entry point");
return eglGetProcAddress;
}
}
}
}

88
src/Avalonia.OpenGL/Angle/AngleWin32EglDisplay.cs

@ -0,0 +1,88 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using static Avalonia.OpenGL.EglConsts;
namespace Avalonia.OpenGL.Angle
{
public class AngleWin32EglDisplay : EglDisplay
{
struct AngleInfo
{
public IntPtr Display { get; set; }
public AngleOptions.PlatformApi PlatformApi { get; set; }
}
static AngleInfo CreateAngleDisplay(EglInterface _egl)
{
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
throw new PlatformNotSupportedException();
var display = IntPtr.Zero;
AngleOptions.PlatformApi angleApi = default;
{
if (_egl.GetPlatformDisplayEXT == null)
throw new OpenGlException("eglGetPlatformDisplayEXT is not supported by libegl.dll");
var allowedApis = AvaloniaLocator.Current.GetService<AngleOptions>()?.AllowedPlatformApis
?? new List<AngleOptions.PlatformApi> {AngleOptions.PlatformApi.DirectX9};
foreach (var platformApi in allowedApis)
{
int dapi;
if (platformApi == AngleOptions.PlatformApi.DirectX9)
dapi = EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE;
else if (platformApi == AngleOptions.PlatformApi.DirectX11)
dapi = EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE;
else
continue;
display = _egl.GetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, IntPtr.Zero,
new[] { EGL_PLATFORM_ANGLE_TYPE_ANGLE, dapi, EGL_NONE });
if (display != IntPtr.Zero)
{
angleApi = platformApi;
break;
}
}
if (display == IntPtr.Zero)
throw new OpenGlException("Unable to create ANGLE display");
return new AngleInfo { Display = display, PlatformApi = angleApi };
}
}
private AngleWin32EglDisplay(EglInterface egl, AngleInfo info) : base(egl, info.Display)
{
PlatformApi = info.PlatformApi;
}
public AngleWin32EglDisplay(EglInterface egl) : this(egl, CreateAngleDisplay(egl))
{
}
public AngleWin32EglDisplay() : this(new AngleEglInterface())
{
}
public AngleOptions.PlatformApi PlatformApi { get; }
public IntPtr GetDirect3DDevice()
{
if (!EglInterface.QueryDisplayAttribExt(Handle, EglConsts.EGL_DEVICE_EXT, out var eglDevice))
throw new OpenGlException("Unable to get EGL_DEVICE_EXT");
if (!EglInterface.QueryDeviceAttribExt(eglDevice, PlatformApi == AngleOptions.PlatformApi.DirectX9 ? EGL_D3D9_DEVICE_ANGLE : EGL_D3D11_DEVICE_ANGLE, out var d3dDeviceHandle))
throw new OpenGlException("Unable to get EGL_D3D9_DEVICE_ANGLE");
return d3dDeviceHandle;
}
public EglSurface WrapDirect3D11Texture(IntPtr handle)
{
if (PlatformApi != AngleOptions.PlatformApi.DirectX11)
throw new InvalidOperationException("Current platform API is " + PlatformApi);
return CreatePBufferFromClientBuffer(EGL_D3D_TEXTURE_ANGLE, handle, new[] { EGL_NONE, EGL_NONE });
}
}
}

10
src/Avalonia.OpenGL/EglConsts.cs

@ -192,5 +192,15 @@ namespace Avalonia.OpenGL
public const int EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE = 0x320F;
public const int EGL_PLATFORM_ANGLE_DEVICE_TYPE_D3D_WARP_ANGLE = 0x320B;
public const int EGL_PLATFORM_ANGLE_DEVICE_TYPE_D3D_REFERENCE_ANGLE = 0x320C;
//EXT_device_query
public const int EGL_DEVICE_EXT = 0x322C;
//ANGLE_device_d3d
public const int EGL_D3D9_DEVICE_ANGLE = 0x33A0;
public const int EGL_D3D11_DEVICE_ANGLE = 0x33A1;
public const int EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE = 0x3200;
public const int EGL_D3D_TEXTURE_ANGLE = 0x33A3;
}
}

76
src/Avalonia.OpenGL/EglDisplay.cs

@ -15,7 +15,6 @@ namespace Avalonia.OpenGL
private readonly int _surfaceType;
public IntPtr Handle => _display;
private AngleOptions.PlatformApi? _angleApi;
private int _sampleCount;
private int _stencilSize;
private GlVersion _version;
@ -24,56 +23,41 @@ namespace Avalonia.OpenGL
{
}
public EglDisplay(EglInterface egl, int platformType, IntPtr platformDisplay, int[] attrs)
{
_egl = egl;
static IntPtr CreateDisplay(EglInterface egl, int platformType, IntPtr platformDisplay, int[] attrs)
{
var display = IntPtr.Zero;
if (platformType == -1 && platformDisplay == IntPtr.Zero)
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
if (_egl.GetPlatformDisplayEXT == null)
throw new OpenGlException("eglGetPlatformDisplayEXT is not supported by libegl.dll");
var allowedApis = AvaloniaLocator.Current.GetService<AngleOptions>()?.AllowedPlatformApis
?? new List<AngleOptions.PlatformApi> {AngleOptions.PlatformApi.DirectX9};
foreach (var platformApi in allowedApis)
{
int dapi;
if (platformApi == AngleOptions.PlatformApi.DirectX9)
dapi = EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE;
else if (platformApi == AngleOptions.PlatformApi.DirectX11)
dapi = EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE;
else
continue;
_display = _egl.GetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, IntPtr.Zero,
new[] {EGL_PLATFORM_ANGLE_TYPE_ANGLE, dapi, EGL_NONE});
if (_display != IntPtr.Zero)
{
_angleApi = platformApi;
break;
}
}
if (_display == IntPtr.Zero)
throw new OpenGlException("Unable to create ANGLE display");
}
if (_display == IntPtr.Zero)
_display = _egl.GetDisplay(IntPtr.Zero);
if (display == IntPtr.Zero)
display = egl.GetDisplay(IntPtr.Zero);
}
else
{
if (_egl.GetPlatformDisplayEXT == null)
if (egl.GetPlatformDisplayEXT == null)
throw new OpenGlException("eglGetPlatformDisplayEXT is not supported by libegl");
_display = _egl.GetPlatformDisplayEXT(platformType, platformDisplay, attrs);
display = egl.GetPlatformDisplayEXT(platformType, platformDisplay, attrs);
}
if (display == IntPtr.Zero)
throw OpenGlException.GetFormattedException("eglGetDisplay", egl);
return display;
}
if (_display == IntPtr.Zero)
throw OpenGlException.GetFormattedException("eglGetDisplay", _egl);
public EglDisplay(EglInterface egl, int platformType, IntPtr platformDisplay, int[] attrs)
: this(egl, CreateDisplay(egl, platformType, platformDisplay, attrs))
{
}
public EglDisplay(EglInterface egl, IntPtr display)
{
_egl = egl;
_display = display;
if(_display == IntPtr.Zero)
throw new ArgumentException();
if (!_egl.Initialize(_display, out var major, out var minor))
throw OpenGlException.GetFormattedException("eglInitialize", _egl);
@ -172,5 +156,15 @@ namespace Avalonia.OpenGL
throw OpenGlException.GetFormattedException("eglCreateWindowSurface", _egl);
return new EglSurface(this, _egl, s);
}
public EglSurface CreatePBufferFromClientBuffer (int bufferType, IntPtr handle, int[] attribs)
{
var s = _egl.CreatePbufferFromClientBuffer(_display, bufferType, handle,
_config, attribs);
if (s == IntPtr.Zero)
throw OpenGlException.GetFormattedException("eglCreatePbufferFromClientBuffer", _egl);
return new EglSurface(this, _egl, s);
}
}
}

7
src/Avalonia.OpenGL/EglGlPlatformFeature.cs

@ -20,12 +20,13 @@ namespace Avalonia.OpenGL
if (feature != null)
AvaloniaLocator.CurrentMutable.Bind<IWindowingPlatformGlFeature>().ToConstant(feature);
}
public static EglGlPlatformFeature TryCreate()
public static EglGlPlatformFeature TryCreate() => TryCreate(() => new EglDisplay());
public static EglGlPlatformFeature TryCreate(Func<EglDisplay> displayFactory)
{
try
{
var disp = new EglDisplay();
var disp = displayFactory();
return new EglGlPlatformFeature
{
_display = disp,

29
src/Avalonia.OpenGL/EglInterface.cs

@ -17,25 +17,21 @@ namespace Avalonia.OpenGL
}
public EglInterface(Func<string, IntPtr> getProcAddress) : base(getProcAddress)
{
}
public EglInterface(string library) : base(Load(library))
{
}
[DllImport("libegl.dll", CharSet = CharSet.Ansi)]
static extern IntPtr eglGetProcAddress(string proc);
static Func<string, IntPtr> Load()
{
var os = AvaloniaLocator.Current.GetService<IRuntimePlatform>().GetRuntimeInfo().OperatingSystem;
if(os == OperatingSystemType.Linux || os == OperatingSystemType.Android)
return Load("libEGL.so.1");
if (os == OperatingSystemType.WinNT)
{
var disp = eglGetProcAddress("eglGetPlatformDisplayEXT");
if (disp == IntPtr.Zero)
throw new OpenGlException("libegl.dll doesn't have eglGetPlatformDisplayEXT entry point");
return eglGetProcAddress;
}
throw new PlatformNotSupportedException();
}
@ -147,6 +143,21 @@ namespace Avalonia.OpenGL
return null;
return Marshal.PtrToStringAnsi(rv);
}
public delegate IntPtr EglCreatePbufferFromClientBuffer(IntPtr display, int buftype, IntPtr buffer, IntPtr config, int[] attrib_list);
[GlEntryPoint("eglCreatePbufferFromClientBuffer")]
public EglCreatePbufferFromClientBuffer CreatePbufferFromClientBuffer { get; }
public delegate bool EglQueryDisplayAttribEXT(IntPtr display, int attr, out IntPtr res);
[GlEntryPoint("eglQueryDisplayAttribEXT"), GlOptionalEntryPoint]
public EglQueryDisplayAttribEXT QueryDisplayAttribExt { get; }
public delegate bool EglQueryDeviceAttribEXT(IntPtr display, int attr, out IntPtr res);
[GlEntryPoint("eglQueryDeviceAttribEXT"), GlOptionalEntryPoint]
public EglQueryDisplayAttribEXT QueryDeviceAttribExt { get; }
// ReSharper restore UnassignedGetOnlyAutoProperty
}

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

@ -1,4 +1,5 @@
using Avalonia.OpenGL;
using Avalonia.OpenGL.Angle;
namespace Avalonia.Win32
{
@ -15,7 +16,7 @@ namespace Avalonia.Win32
{
if (!s_attemptedToInitialize)
{
EglFeature = EglGlPlatformFeature.TryCreate();
EglFeature = EglGlPlatformFeature.TryCreate(() => new AngleWin32EglDisplay());
s_attemptedToInitialize = true;
}

Loading…
Cancel
Save