Browse Source

Implemented ANGLE-based OpenGL support in Win32 backend

pull/1935/head
Nikita Tsukanov 8 years ago
parent
commit
25919bf48a
  1. 18
      src/Avalonia.OpenGL/EglConsts.cs
  2. 31
      src/Avalonia.OpenGL/EglDisplay.cs
  3. 12
      src/Avalonia.OpenGL/EglGlPlatformFeature.cs
  4. 12
      src/Avalonia.OpenGL/EglInterface.cs
  5. 4
      src/Avalonia.OpenGL/EntryPointAttribute.cs
  6. 6
      src/Avalonia.OpenGL/GlInterface.cs
  7. 7
      src/Avalonia.OpenGL/GlInterfaceBase.cs
  8. 2
      src/Skia/Avalonia.Skia/PlatformRenderInterface.cs
  9. 1
      src/Windows/Avalonia.Win32/Avalonia.Win32.csproj
  10. 25
      src/Windows/Avalonia.Win32/Win32GlManager.cs
  11. 2
      src/Windows/Avalonia.Win32/Win32Platform.cs
  12. 23
      src/Windows/Avalonia.Win32/WindowImpl.cs

18
src/Avalonia.OpenGL/EglConsts.cs

@ -174,5 +174,23 @@ namespace Avalonia.OpenGL
public const int EGL_NO_IMAGE = 0;
public const int EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE = 0x3207;
public const int EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE = 0x3208;
//EGL_ANGLE_platform_angle
public const int EGL_PLATFORM_ANGLE_ANGLE = 0x3202;
public const int EGL_PLATFORM_ANGLE_TYPE_ANGLE = 0x3203;
public const int EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE = 0x3204;
public const int EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE = 0x3205;
public const int EGL_PLATFORM_ANGLE_DEBUG_LAYERS_ENABLED = 0x3451;
public const int EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE = 0x3206;
public const int EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE = 0x320A;
public const int EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE = 0x345E;
//EGL_ANGLE_platform_angle_d3d
public const int EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE = 0x3209;
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;
}
}

31
src/Avalonia.OpenGL/EglDisplay.cs

@ -14,10 +14,27 @@ namespace Avalonia.OpenGL
public EglDisplay(EglInterface egl)
{
_egl = egl;
_display = _egl.GetDisplay(IntPtr.Zero);
_egl = egl;
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && _egl.GetPlatformDisplayEXT != null)
{
foreach (var dapi in new[] {EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE})
{
_display = _egl.GetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, IntPtr.Zero, new[]
{
EGL_PLATFORM_ANGLE_TYPE_ANGLE, dapi, EGL_NONE
});
if(_display != IntPtr.Zero)
break;
}
}
if (_display == IntPtr.Zero)
_display = _egl.GetDisplay(IntPtr.Zero);
if(_display == IntPtr.Zero)
throw new OpenGlException("eglGetDisplay failed");
if (!_egl.Initialize(_display, out var major, out var minor))
throw new OpenGlException("eglInitialize failed");
@ -67,10 +84,16 @@ namespace Avalonia.OpenGL
if (_contextAttributes == null)
throw new OpenGlException("No suitable EGL config was found");
GlInterface = new GlInterface(proc =>
GlInterface = new GlInterface((proc, optional) =>
{
using (var u = new Utf8Buffer(proc))
return _egl.GetProcAddress(u);
{
var rv = _egl.GetProcAddress(u);
if (rv == IntPtr.Zero && !optional)
throw new OpenGlException("Missing function " + proc);
return rv;
}
});
}

12
src/Avalonia.OpenGL/EglGlPlatformFeature.cs

@ -11,21 +11,29 @@ namespace Avalonia.OpenGL
public IGlContext DeferredContext { get; set; }
public static void TryInitialize()
{
var feature = TryCreate();
if (feature != null)
AvaloniaLocator.CurrentMutable.Bind<IWindowingPlatformGlFeature>().ToConstant(feature);
}
public static EglGlPlatformFeature TryCreate()
{
try
{
var disp = new EglDisplay();
var ctx = disp.CreateContext(null);
AvaloniaLocator.CurrentMutable.Bind<IWindowingPlatformGlFeature>().ToConstant(new EglGlPlatformFeature
return new EglGlPlatformFeature
{
Display = disp,
ImmediateContext = ctx,
DeferredContext = disp.CreateContext(ctx)
});
};
}
catch(Exception e)
{
Logger.Error("OpenGL", null, "Unable to initialize EGL-based rendering: {0}", e);
return null;
}
}
}

12
src/Avalonia.OpenGL/EglInterface.cs

@ -16,21 +16,21 @@ namespace Avalonia.OpenGL
{
}
static Func<string, IntPtr> Load()
static Func<string, bool, 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)
return Load("libEGL.dll");
return Load(@"libegl.dll");
throw new PlatformNotSupportedException();
}
static Func<string, IntPtr> Load(string library)
static Func<string, bool, IntPtr> Load(string library)
{
var dyn = AvaloniaLocator.Current.GetService<IDynamicLibraryLoader>();
var lib = dyn.LoadLibrary(library);
return s => dyn.GetProcAddress(lib, s, false);
return (s, o) => dyn.GetProcAddress(lib, s, o);
}
@ -38,6 +38,10 @@ namespace Avalonia.OpenGL
public delegate IntPtr EglGetDisplay(IntPtr nativeDisplay);
[EntryPoint("eglGetDisplay")]
public EglGetDisplay GetDisplay { get; }
public delegate IntPtr EglGetPlatformDisplayEXT(int platform, IntPtr nativeDisplay, int[] attrs);
[EntryPoint("eglGetPlatformDisplayEXT", true)]
public EglGetPlatformDisplayEXT GetPlatformDisplayEXT { get; }
public delegate bool EglInitialize(IntPtr display, out int major, out int minor);
[EntryPoint("eglInitialize")]

4
src/Avalonia.OpenGL/EntryPointAttribute.cs

@ -5,10 +5,12 @@ namespace Avalonia.OpenGL
class EntryPointAttribute : Attribute
{
public string EntryPoint { get; }
public bool Optional { get; }
public EntryPointAttribute(string entryPoint)
public EntryPointAttribute(string entryPoint, bool optional = false)
{
EntryPoint = entryPoint;
Optional = optional;
}
}
}

6
src/Avalonia.OpenGL/GlInterface.cs

@ -7,15 +7,15 @@ namespace Avalonia.OpenGL
public class GlInterface : GlInterfaceBase
{
private readonly Func<string, IntPtr> _getProcAddress;
private readonly Func<string, bool, IntPtr> _getProcAddress;
public GlInterface(Func<string, IntPtr> getProcAddress) : base(getProcAddress)
public GlInterface(Func<string, bool, IntPtr> getProcAddress) : base(getProcAddress)
{
_getProcAddress = getProcAddress;
}
public IntPtr GetProcAddress(string proc) => _getProcAddress(proc);
public IntPtr GetProcAddress(string proc) => _getProcAddress(proc, true);
public T GetProcAddress<T>(string proc) => Marshal.GetDelegateForFunctionPointer<T>(GetProcAddress(proc));

7
src/Avalonia.OpenGL/GlInterfaceBase.cs

@ -6,7 +6,7 @@ namespace Avalonia.OpenGL
{
public class GlInterfaceBase
{
public GlInterfaceBase(Func<string, IntPtr> getProcAddress)
public GlInterfaceBase(Func<string, bool, IntPtr> getProcAddress)
{
foreach (var prop in this.GetType().GetProperties())
{
@ -18,8 +18,9 @@ namespace Avalonia.OpenGL
BindingFlags.Instance | BindingFlags.NonPublic);
if (field == null)
throw new InvalidProgramException($"Expected property {prop.Name} to have {fieldName}");
field.SetValue(this,
Marshal.GetDelegateForFunctionPointer(getProcAddress(a.EntryPoint), prop.PropertyType));
var proc = getProcAddress(a.EntryPoint, a.Optional);
if (proc != IntPtr.Zero)
field.SetValue(this, Marshal.GetDelegateForFunctionPointer(proc, prop.PropertyType));
}
}
}

2
src/Skia/Avalonia.Skia/PlatformRenderInterface.cs

@ -108,7 +108,7 @@ namespace Avalonia.Skia
{
foreach (var surface in surfaces)
{
if (surface is IGlPlatformSurface glSurface)
if (surface is IGlPlatformSurface glSurface && GrContext != null)
{
return new GlRenderTarget(GrContext, glSurface);
}

1
src/Windows/Avalonia.Win32/Avalonia.Win32.csproj

@ -10,6 +10,7 @@
<ProjectReference Include="..\..\Avalonia.Input\Avalonia.Input.csproj" />
<ProjectReference Include="..\..\Avalonia.Interactivity\Avalonia.Interactivity.csproj" />
<ProjectReference Include="..\..\Avalonia.Layout\Avalonia.Layout.csproj" />
<ProjectReference Include="..\..\Avalonia.OpenGL\Avalonia.OpenGL.csproj" />
<ProjectReference Include="..\..\Avalonia.Styling\Avalonia.Styling.csproj" />
<ProjectReference Include="..\..\Avalonia.Visuals\Avalonia.Visuals.csproj" />
</ItemGroup>

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

@ -0,0 +1,25 @@
using Avalonia.OpenGL;
namespace Avalonia.Win32
{
static class Win32GlManager
{
/// <summary>This property is initialized if drawing platform requests OpenGL support</summary>
public static EglGlPlatformFeature EglFeature { get; private set; }
private static bool s_attemptedToInitialize;
public static void Initialize()
{
AvaloniaLocator.CurrentMutable.Bind<IWindowingPlatformGlFeature>().ToFunc(() =>
{
if (!s_attemptedToInitialize)
{
EglFeature = EglGlPlatformFeature.TryCreate();
s_attemptedToInitialize = true;
}
return EglFeature;
});
}
}
}

2
src/Windows/Avalonia.Win32/Win32Platform.cs

@ -88,7 +88,7 @@ namespace Avalonia.Win32
.Bind<ISystemDialogImpl>().ToSingleton<SystemDialogImpl>()
.Bind<IWindowingPlatform>().ToConstant(s_instance)
.Bind<IPlatformIconLoader>().ToConstant(s_instance);
Win32GlManager.Initialize();
UseDeferredRendering = deferredRendering;
_uiThread = UnmanagedMethods.GetCurrentThreadId();

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

@ -10,6 +10,7 @@ using System.Runtime.InteropServices;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Input.Raw;
using Avalonia.OpenGL;
using Avalonia.Platform;
using Avalonia.Rendering;
using Avalonia.Win32.Input;
@ -18,7 +19,7 @@ using static Avalonia.Win32.Interop.UnmanagedMethods;
namespace Avalonia.Win32
{
public class WindowImpl : IWindowImpl
public class WindowImpl : IWindowImpl, IEglWindowGlPlatformSurfaceInfo
{
private static readonly List<WindowImpl> s_instances = new List<WindowImpl>();
@ -37,6 +38,7 @@ namespace Avalonia.Win32
private WindowState _showWindowState;
private WindowState _lastWindowState;
private FramebufferManager _framebuffer;
private IGlPlatformSurface _gl;
private OleDropTarget _dropTarget;
private Size _minSize;
private Size _maxSize;
@ -58,6 +60,10 @@ namespace Avalonia.Win32
#endif
CreateWindow();
_framebuffer = new FramebufferManager(_hwnd);
if (Win32GlManager.EglFeature != null)
_gl = new EglGlPlatformSurface((EglDisplay)Win32GlManager.EglFeature.Display,
Win32GlManager.EglFeature.DeferredContext, this);
s_instances.Add(this);
}
@ -211,7 +217,7 @@ namespace Avalonia.Win32
public IEnumerable<object> Surfaces => new object[]
{
Handle, _framebuffer
Handle, _gl, _framebuffer
};
public void Activate()
@ -921,5 +927,18 @@ namespace Avalonia.Win32
_topmost = value;
}
System.Drawing.Size IEglWindowGlPlatformSurfaceInfo.PixelSize
{
get
{
RECT rect;
GetClientRect(_hwnd, out rect);
return new System.Drawing.Size(
Math.Max(1, rect.right - rect.left),
Math.Max(1, rect.bottom - rect.top));
}
}
IntPtr IEglWindowGlPlatformSurfaceInfo.Handle => Handle.Handle;
}
}

Loading…
Cancel
Save