Browse Source

Added WGL support

pull/4799/head
Nikita Tsukanov 6 years ago
parent
commit
c4bbe3ac5e
  1. 4
      samples/RenderDemo/App.xaml.cs
  2. 17
      src/Avalonia.Base/AvaloniaLocator.cs
  3. 92
      src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs
  4. 62
      src/Windows/Avalonia.Win32/OpenGl/WglConsts.cs
  5. 85
      src/Windows/Avalonia.Win32/OpenGl/WglContext.cs
  6. 183
      src/Windows/Avalonia.Win32/OpenGl/WglDisplay.cs
  7. 85
      src/Windows/Avalonia.Win32/OpenGl/WglGlPlatformSurface.cs
  8. 39
      src/Windows/Avalonia.Win32/OpenGl/WglPlatformOpenGlInterface.cs
  9. 39
      src/Windows/Avalonia.Win32/OpenGl/WglRestoreContext.cs
  10. 18
      src/Windows/Avalonia.Win32/Win32GlManager.cs
  11. 10
      src/Windows/Avalonia.Win32/Win32Platform.cs
  12. 13
      src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs
  13. 9
      src/Windows/Avalonia.Win32/WindowImpl.cs

4
samples/RenderDemo/App.xaml.cs

@ -18,6 +18,10 @@ namespace RenderDemo
// App configuration, used by the entry point and previewer
static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure<App>()
.With(new Win32PlatformOptions
{
OverlayPopups = true,
})
.UsePlatformDetect()
.UseReactiveUI()
.LogToDebug();

17
src/Avalonia.Base/AvaloniaLocator.cs

@ -54,6 +54,23 @@ namespace Avalonia
return _locator;
}
public AvaloniaLocator ToLazy<TImlp>(Func<TImlp> func) where TImlp : TService
{
var constructed = false;
TImlp instance = default;
_locator._registry[typeof (TService)] = () =>
{
if (!constructed)
{
instance = func();
constructed = true;
}
return instance;
};
return _locator;
}
public AvaloniaLocator ToSingleton<TImpl>() where TImpl : class, TService, new()
{
TImpl instance = null;

92
src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs

@ -1011,6 +1011,10 @@ namespace Avalonia.Win32.Interop
[DllImport("user32.dll")]
public static extern bool InvalidateRect(IntPtr hWnd, RECT* lpRect, bool bErase);
[DllImport("user32.dll")]
public static extern bool ValidateRect(IntPtr hWnd, IntPtr lpRect);
[DllImport("user32.dll")]
public static extern bool IsWindowEnabled(IntPtr hWnd);
@ -1292,6 +1296,41 @@ namespace Avalonia.Win32.Interop
[DllImport("gdi32.dll")]
public static extern IntPtr SelectObject(IntPtr hdc, IntPtr hObject);
[DllImport("gdi32.dll")]
public static extern int ChoosePixelFormat(IntPtr hdc, ref PixelFormatDescriptor pfd);
[DllImport("gdi32.dll")]
public static extern int DescribePixelFormat(IntPtr hdc, ref PixelFormatDescriptor pfd);
[DllImport("gdi32.dll")]
public static extern int SetPixelFormat(IntPtr hdc, int iPixelFormat, ref PixelFormatDescriptor pfd);
[DllImport("gdi32.dll")]
public static extern int DescribePixelFormat(IntPtr hdc, int iPixelFormat, int bytes, ref PixelFormatDescriptor pfd);
[DllImport("gdi32.dll")]
public static extern bool SwapBuffers(IntPtr hdc);
[DllImport("opengl32.dll")]
public static extern IntPtr wglCreateContext(IntPtr hdc);
[DllImport("opengl32.dll")]
public static extern bool wglDeleteContext(IntPtr context);
[DllImport("opengl32.dll")]
public static extern bool wglMakeCurrent(IntPtr hdc, IntPtr context);
[DllImport("opengl32.dll")]
public static extern IntPtr wglGetCurrentContext();
[DllImport("opengl32.dll")]
public static extern IntPtr wglGetCurrentDC();
[DllImport("opengl32.dll", CharSet = CharSet.Ansi)]
public static extern IntPtr wglGetProcAddress(string name);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr CreateFileMapping(IntPtr hFile,
IntPtr lpFileMappingAttributes,
@ -2121,4 +2160,57 @@ namespace Avalonia.Win32.Interop
public bool fNC;
public bool fWide;
}
[Flags]
internal enum PixelFormatDescriptorFlags : uint
{
PFD_DOUBLEBUFFER = 0x00000001,
PFD_STEREO = 0x00000002,
PFD_DRAW_TO_WINDOW = 0x00000004,
PFD_DRAW_TO_BITMAP = 0x00000008,
PFD_SUPPORT_GDI = 0x00000010,
PFD_SUPPORT_OPENGL = 0x00000020,
PFD_GENERIC_FORMAT = 0x00000040,
PFD_NEED_PALETTE = 0x00000080,
PFD_NEED_SYSTEM_PALETTE = 0x00000100,
PFD_SWAP_EXCHANGE = 0x00000200,
PFD_SWAP_COPY = 0x00000400,
PFD_SWAP_LAYER_BUFFERS = 0x00000800,
PFD_GENERIC_ACCELERATED = 0x00001000,
PFD_SUPPORT_DIRECTDRAW = 0x00002000,
PFD_DEPTH_DONTCARE = 0x20000000,
PFD_DOUBLEBUFFER_DONTCARE = 0x40000000,
PFD_STEREO_DONTCARE = 0x80000000,
}
[StructLayout(LayoutKind.Sequential)]
internal struct PixelFormatDescriptor
{
public ushort Size;
public ushort Version;
public PixelFormatDescriptorFlags Flags;
public byte PixelType;
public byte ColorBits;
public byte RedBits;
public byte RedShift;
public byte GreenBits;
public byte GreenShift;
public byte BlueBits;
public byte BlueShift;
public byte AlphaBits;
public byte AlphaShift;
public byte AccumBits;
public byte AccumRedBits;
public byte AccumGreenBits;
public byte AccumBlueBits;
public byte AccumAlphaBits;
public byte DepthBits;
public byte StencilBits;
public byte AuxBuffers;
public byte LayerType;
private byte Reserved;
public uint LayerMask;
public uint VisibleMask;
public uint DamageMask;
}
}

62
src/Windows/Avalonia.Win32/OpenGl/WglConsts.cs

@ -0,0 +1,62 @@
namespace Avalonia.Win32.OpenGl
{
internal class WglConsts
{
public const int WGL_CONTEXT_MAJOR_VERSION_ARB = 0x2091;
public const int WGL_CONTEXT_MINOR_VERSION_ARB = 0x2092;
public const int WGL_CONTEXT_LAYER_PLANE_ARB = 0x2093;
public const int WGL_CONTEXT_FLAGS_ARB = 0x2094;
public const int WGL_CONTEXT_PROFILE_MASK_ARB = 0x9126;
public const int WGL_NUMBER_PIXEL_FORMATS_ARB = 0x2000;
public const int WGL_DRAW_TO_WINDOW_ARB = 0x2001;
public const int WGL_DRAW_TO_BITMAP_ARB = 0x2002;
public const int WGL_ACCELERATION_ARB = 0x2003;
public const int WGL_NEED_PALETTE_ARB = 0x2004;
public const int WGL_NEED_SYSTEM_PALETTE_ARB = 0x2005;
public const int WGL_SWAP_LAYER_BUFFERS_ARB = 0x2006;
public const int WGL_SWAP_METHOD_ARB = 0x2007;
public const int WGL_NUMBER_OVERLAYS_ARB = 0x2008;
public const int WGL_NUMBER_UNDERLAYS_ARB = 0x2009;
public const int WGL_TRANSPARENT_ARB = 0x200A;
public const int WGL_TRANSPARENT_RED_VALUE_ARB = 0x2037;
public const int WGL_TRANSPARENT_GREEN_VALUE_ARB = 0x2038;
public const int WGL_TRANSPARENT_BLUE_VALUE_ARB = 0x2039;
public const int WGL_TRANSPARENT_ALPHA_VALUE_ARB = 0x203A;
public const int WGL_TRANSPARENT_INDEX_VALUE_ARB = 0x203B;
public const int WGL_SHARE_DEPTH_ARB = 0x200C;
public const int WGL_SHARE_STENCIL_ARB = 0x200D;
public const int WGL_SHARE_ACCUM_ARB = 0x200E;
public const int WGL_SUPPORT_GDI_ARB = 0x200F;
public const int WGL_SUPPORT_OPENGL_ARB = 0x2010;
public const int WGL_DOUBLE_BUFFER_ARB = 0x2011;
public const int WGL_STEREO_ARB = 0x2012;
public const int WGL_PIXEL_TYPE_ARB = 0x2013;
public const int WGL_COLOR_BITS_ARB = 0x2014;
public const int WGL_RED_BITS_ARB = 0x2015;
public const int WGL_RED_SHIFT_ARB = 0x2016;
public const int WGL_GREEN_BITS_ARB = 0x2017;
public const int WGL_GREEN_SHIFT_ARB = 0x2018;
public const int WGL_BLUE_BITS_ARB = 0x2019;
public const int WGL_BLUE_SHIFT_ARB = 0x201A;
public const int WGL_ALPHA_BITS_ARB = 0x201B;
public const int WGL_ALPHA_SHIFT_ARB = 0x201C;
public const int WGL_ACCUM_BITS_ARB = 0x201D;
public const int WGL_ACCUM_RED_BITS_ARB = 0x201E;
public const int WGL_ACCUM_GREEN_BITS_ARB = 0x201F;
public const int WGL_ACCUM_BLUE_BITS_ARB = 0x2020;
public const int WGL_ACCUM_ALPHA_BITS_ARB = 0x2021;
public const int WGL_DEPTH_BITS_ARB = 0x2022;
public const int WGL_STENCIL_BITS_ARB = 0x2023;
public const int WGL_AUX_BUFFERS_ARB = 0x2024;
public const int WGL_NO_ACCELERATION_ARB = 0x2025;
public const int WGL_GENERIC_ACCELERATION_ARB = 0x2026;
public const int WGL_FULL_ACCELERATION_ARB = 0x2027;
public const int WGL_SWAP_EXCHANGE_ARB = 0x2028;
public const int WGL_SWAP_COPY_ARB = 0x2029;
public const int WGL_SWAP_UNDEFINED_ARB = 0x202A;
public const int WGL_TYPE_RGBA_ARB = 0x202B;
public const int WGL_TYPE_COLORINDEX_ARB = 0x202C;
}
}

85
src/Windows/Avalonia.Win32/OpenGl/WglContext.cs

@ -0,0 +1,85 @@
using System;
using System.Reactive.Disposables;
using Avalonia.OpenGL;
using Avalonia.Win32.Interop;
using static Avalonia.Win32.Interop.UnmanagedMethods;
using static Avalonia.Win32.OpenGl.WglConsts;
namespace Avalonia.Win32.OpenGl
{
class WglContext : IGlContext
{
private object _lock = new object();
private readonly WglContext _sharedWith;
private readonly IntPtr _context;
private readonly IntPtr _hWnd;
private readonly IntPtr _dc;
private readonly int _pixelFormat;
private readonly PixelFormatDescriptor _formatDescriptor;
public IntPtr Handle => _context;
public WglContext(WglContext sharedWith, GlVersion version, IntPtr context, IntPtr hWnd, IntPtr dc, int pixelFormat,
PixelFormatDescriptor formatDescriptor)
{
Version = version;
_sharedWith = sharedWith;
_context = context;
_hWnd = hWnd;
_dc = dc;
_pixelFormat = pixelFormat;
_formatDescriptor = formatDescriptor;
StencilSize = formatDescriptor.StencilBits;
using (MakeCurrent())
GlInterface = new GlInterface(version, proc =>
{
var ext = wglGetProcAddress(proc);
if (ext != IntPtr.Zero)
return ext;
return GetProcAddress(WglDisplay.OpenGl32Handle, proc);
});
}
public void Dispose()
{
wglDeleteContext(_context);
ReleaseDC(_hWnd, _dc);
DestroyWindow(_hWnd);
}
public GlVersion Version { get; }
public GlInterface GlInterface { get; }
public int SampleCount { get; }
public int StencilSize { get; }
private bool IsCurrent => wglGetCurrentContext() == _context && wglGetCurrentDC() == _dc;
public IDisposable MakeCurrent()
{
if(IsCurrent)
return Disposable.Empty;
return new WglRestoreContext(_dc, _context, _lock);
}
public IDisposable EnsureCurrent() => MakeCurrent();
public IntPtr CreateConfiguredDeviceContext(IntPtr hWnd)
{
var dc = GetDC(hWnd);
var fmt = _formatDescriptor;
SetPixelFormat(dc, _pixelFormat, ref fmt);
return dc;
}
public IDisposable MakeCurrent(IntPtr hdc) => new WglRestoreContext(hdc, _context, _lock);
public bool IsSharedWith(IGlContext context)
{
var c = (WglContext)context;
return c == this
|| c._sharedWith == this
|| _sharedWith == context
|| _sharedWith != null && _sharedWith == c._sharedWith;
}
}
}

183
src/Windows/Avalonia.Win32/OpenGl/WglDisplay.cs

@ -0,0 +1,183 @@
using System;
using System.Runtime.InteropServices;
using Avalonia.OpenGL;
using Avalonia.Win32.Interop;
using static Avalonia.Win32.Interop.UnmanagedMethods;
using static Avalonia.Win32.OpenGl.WglConsts;
namespace Avalonia.Win32.OpenGl
{
internal class WglDisplay
{
private static bool? _initialized;
private static ushort _windowClass;
private static readonly WndProc _wndProcDelegate = WndProc;
private static readonly DebugCallbackDelegate _debugCallback = DebugCallback;
private static IntPtr _bootstrapContext;
private static IntPtr _bootstrapWindow;
private static IntPtr _bootstrapDc;
private static PixelFormatDescriptor _defaultPfd;
private static int _defaultPixelFormat;
public static IntPtr OpenGl32Handle = LoadLibrary("opengl32");
private delegate bool WglChoosePixelFormatARBDelegate(IntPtr hdc, int[] piAttribIList, float[] pfAttribFList,
int nMaxFormats, int[] piFormats, out int nNumFormats);
private static WglChoosePixelFormatARBDelegate WglChoosePixelFormatArb;
private delegate IntPtr WglCreateContextAttribsARBDelegate(IntPtr hDC, IntPtr hShareContext, int[] attribList);
private static WglCreateContextAttribsARBDelegate WglCreateContextAttribsArb;
private delegate void GlDebugMessageCallbackDelegate(IntPtr callback, IntPtr userParam);
private static GlDebugMessageCallbackDelegate GlDebugMessageCallback;
private delegate void DebugCallbackDelegate(int source, int type, int id, int severity, int len, IntPtr message,
IntPtr userParam);
static bool Initialize()
{
if (!_initialized.HasValue)
_initialized = InitializeCore();
return _initialized.Value;
}
static bool InitializeCore()
{
var wndClassEx = new WNDCLASSEX
{
cbSize = Marshal.SizeOf<WNDCLASSEX>(),
hInstance = GetModuleHandle(null),
lpfnWndProc = _wndProcDelegate,
lpszClassName = "AvaloniaGlWindow-" + Guid.NewGuid(),
style = (int)ClassStyles.CS_OWNDC
};
_windowClass = RegisterClassEx(ref wndClassEx);
_bootstrapWindow = CreateOffscreenWindow();
_bootstrapDc = GetDC(_bootstrapWindow);
_defaultPfd = new PixelFormatDescriptor
{
Size = (ushort)Marshal.SizeOf<PixelFormatDescriptor>(),
Version = 1,
Flags = PixelFormatDescriptorFlags.PFD_DRAW_TO_WINDOW |
PixelFormatDescriptorFlags.PFD_SUPPORT_OPENGL | PixelFormatDescriptorFlags.PFD_DOUBLEBUFFER,
DepthBits = 24,
StencilBits = 8,
ColorBits = 32
};
_defaultPixelFormat = ChoosePixelFormat(_bootstrapDc, ref _defaultPfd);
SetPixelFormat(_bootstrapDc, _defaultPixelFormat, ref _defaultPfd);
_bootstrapContext = wglCreateContext(_bootstrapDc);
if (_bootstrapContext == IntPtr.Zero)
return false;
wglMakeCurrent(_bootstrapDc, _bootstrapContext);
WglCreateContextAttribsArb = Marshal.GetDelegateForFunctionPointer<WglCreateContextAttribsARBDelegate>(
wglGetProcAddress("wglCreateContextAttribsARB"));
WglChoosePixelFormatArb =
Marshal.GetDelegateForFunctionPointer<WglChoosePixelFormatARBDelegate>(
wglGetProcAddress("wglChoosePixelFormatARB"));
GlDebugMessageCallback =
Marshal.GetDelegateForFunctionPointer<GlDebugMessageCallbackDelegate>(
wglGetProcAddress("glDebugMessageCallback"));
var formats = new int[1];
WglChoosePixelFormatArb(_bootstrapDc, new int[]
{
WGL_DRAW_TO_WINDOW_ARB, 1,
WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB,
WGL_SUPPORT_OPENGL_ARB, 1,
WGL_DOUBLE_BUFFER_ARB, 1,
WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
WGL_COLOR_BITS_ARB, 32,
WGL_DEPTH_BITS_ARB, 0,
WGL_STENCIL_BITS_ARB, 0,
0, // End
}, null, 1, formats, out int numFormats);
if (numFormats != 0)
{
DescribePixelFormat(_bootstrapDc, formats[0], Marshal.SizeOf<PixelFormatDescriptor>(), ref _defaultPfd);
_defaultPixelFormat = formats[0];
}
wglMakeCurrent(IntPtr.Zero, IntPtr.Zero);
return true;
}
static IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam)
{
return DefWindowProc(hWnd, msg, wParam, lParam);
}
private static void DebugCallback(int source, int type, int id, int severity, int len, IntPtr message, IntPtr userparam)
{
var err = Marshal.PtrToStringAnsi(message, len);
Console.Error.WriteLine(err);
}
public static WglContext CreateContext(GlVersion[] versions, IGlContext share)
{
if (!Initialize())
return null;
var shareContext = (WglContext)share;
using (new WglRestoreContext(_bootstrapDc, _bootstrapContext, null))
{
var window = CreateOffscreenWindow();
var dc = GetDC(window);
SetPixelFormat(dc, _defaultPixelFormat, ref _defaultPfd);
foreach (var version in versions)
{
if(version.Type != GlProfileType.OpenGL)
continue;
var context = WglCreateContextAttribsArb(dc, shareContext?.Handle ?? IntPtr.Zero,
new[]
{
// major
WGL_CONTEXT_MAJOR_VERSION_ARB, version.Major,
// minor
WGL_CONTEXT_MINOR_VERSION_ARB, version.Minor,
// core profile
WGL_CONTEXT_PROFILE_MASK_ARB, 1,
// debug
WGL_CONTEXT_FLAGS_ARB, 1,
// end
0, 0
});
using(new WglRestoreContext(dc, context, null))
GlDebugMessageCallback(Marshal.GetFunctionPointerForDelegate(_debugCallback), IntPtr.Zero);
if (context != IntPtr.Zero)
return new WglContext(shareContext, version, context, window, dc,
_defaultPixelFormat, _defaultPfd);
}
ReleaseDC(window, dc);
DestroyWindow(window);
return null;
}
}
static IntPtr CreateOffscreenWindow() =>
CreateWindowEx(
0,
_windowClass,
null,
(int)WindowStyles.WS_OVERLAPPEDWINDOW,
0,
0,
640,
480,
IntPtr.Zero,
IntPtr.Zero,
IntPtr.Zero,
IntPtr.Zero);
}
}

85
src/Windows/Avalonia.Win32/OpenGl/WglGlPlatformSurface.cs

@ -0,0 +1,85 @@
using System;
using System.Diagnostics;
using Avalonia.OpenGL;
using Avalonia.OpenGL.Egl;
using Avalonia.OpenGL.Surfaces;
using Avalonia.Win32.Interop;
using static Avalonia.OpenGL.GlConsts;
using static Avalonia.Win32.Interop.UnmanagedMethods;
namespace Avalonia.Win32.OpenGl
{
class WglGlPlatformSurface: IGlPlatformSurface
{
private readonly WglContext _context;
private readonly EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo _info;
public WglGlPlatformSurface(WglContext context, EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo info)
{
_context = context;
_info = info;
}
public IGlPlatformSurfaceRenderTarget CreateGlRenderTarget()
{
return new RenderTarget(_context, _info);
}
class RenderTarget : IGlPlatformSurfaceRenderTarget
{
private readonly WglContext _context;
private readonly EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo _info;
private IntPtr _hdc;
public RenderTarget(WglContext context, EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo info)
{
_context = context;
_info = info;
_hdc = context.CreateConfiguredDeviceContext(info.Handle);
}
public void Dispose()
{
UnmanagedMethods.ReleaseDC(_hdc, _info.Handle);
}
public IGlPlatformSurfaceRenderingSession BeginDraw()
{
var oldContext = _context.MakeCurrent(_hdc);
// Reset to default FBO first
_context.GlInterface.BindFramebuffer(GL_FRAMEBUFFER, 0);
return new Session(_context, _hdc, _info, oldContext);
}
class Session : IGlPlatformSurfaceRenderingSession
{
private readonly WglContext _context;
private readonly IntPtr _hdc;
private readonly EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo _info;
private readonly IDisposable _clearContext;
public IGlContext Context => _context;
public Session(WglContext context, IntPtr hdc, EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo info,
IDisposable clearContext)
{
_context = context;
_hdc = hdc;
_info = info;
_clearContext = clearContext;
}
public void Dispose()
{
_context.GlInterface.Flush();
UnmanagedMethods.SwapBuffers(_hdc);
_clearContext.Dispose();
}
public PixelSize Size => _info.Size;
public double Scaling => _info.Scaling;
public bool IsYFlipped { get; }
}
}
}
}

39
src/Windows/Avalonia.Win32/OpenGl/WglPlatformOpenGlInterface.cs

@ -0,0 +1,39 @@
using System;
using System.Linq;
using Avalonia.Logging;
using Avalonia.OpenGL;
namespace Avalonia.Win32.OpenGl
{
class WglPlatformOpenGlInterface : IPlatformOpenGlInterface
{
public WglContext PrimaryContext { get; }
IGlContext IPlatformOpenGlInterface.PrimaryContext => PrimaryContext;
public IGlContext CreateSharedContext() => WglDisplay.CreateContext(new[] { PrimaryContext.Version }, PrimaryContext);
public bool CanShareContexts => true;
public bool CanCreateContexts => true;
public IGlContext CreateContext() => WglDisplay.CreateContext(new[] { PrimaryContext.Version }, null);
private WglPlatformOpenGlInterface(WglContext primary)
{
PrimaryContext = primary;
}
public static WglPlatformOpenGlInterface TryCreate()
{
try
{
var opts = AvaloniaLocator.Current.GetService<Win32PlatformOptions>() ?? new Win32PlatformOptions();
var primary = WglDisplay.CreateContext(opts.WglProfiles.ToArray(), null);
return new WglPlatformOpenGlInterface(primary);
}
catch (Exception e)
{
Logger.TryGet(LogEventLevel.Error, "OpenGL")?.Log("WGL", "Unable to initialize WGL: " + e);
}
return null;
}
}
}

39
src/Windows/Avalonia.Win32/OpenGl/WglRestoreContext.cs

@ -0,0 +1,39 @@
using System;
using System.Threading;
using Avalonia.OpenGL;
using static Avalonia.Win32.Interop.UnmanagedMethods;
namespace Avalonia.Win32.OpenGl
{
internal class WglRestoreContext : IDisposable
{
private readonly object _monitor;
private readonly IntPtr _oldDc;
private readonly IntPtr _oldContext;
public WglRestoreContext(IntPtr gc, IntPtr context, object monitor, bool takeMonitor = true)
{
_monitor = monitor;
_oldDc = wglGetCurrentDC();
_oldContext = wglGetCurrentContext();
if (monitor != null && takeMonitor)
Monitor.Enter(monitor);
if (!wglMakeCurrent(gc, context))
{
if(monitor != null && takeMonitor)
Monitor.Exit(monitor);
throw new OpenGlException("Unable to make the context current");
}
}
public void Dispose()
{
if (!wglMakeCurrent(_oldDc, _oldContext))
wglMakeCurrent(IntPtr.Zero, IntPtr.Zero);
if (_monitor != null)
Monitor.Exit(_monitor);
}
}
}

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

@ -1,27 +1,29 @@
using Avalonia.OpenGL;
using Avalonia.OpenGL.Angle;
using Avalonia.OpenGL.Egl;
using Avalonia.Win32.OpenGl;
namespace Avalonia.Win32
{
static class Win32GlManager
{
/// <summary>This property is initialized if drawing platform requests OpenGL support</summary>
public static EglPlatformOpenGlInterface EglPlatformInterface { get; private set; }
private static bool s_attemptedToInitialize;
public static void Initialize()
{
AvaloniaLocator.CurrentMutable.Bind<IPlatformOpenGlInterface>().ToFunc(() =>
AvaloniaLocator.CurrentMutable.Bind<IPlatformOpenGlInterface>().ToLazy<IPlatformOpenGlInterface>(() =>
{
if (!s_attemptedToInitialize)
var opts = AvaloniaLocator.Current.GetService<Win32PlatformOptions>();
if (opts?.UseWgl == true)
{
EglPlatformInterface = EglPlatformOpenGlInterface.TryCreate(() => new AngleWin32EglDisplay());
s_attemptedToInitialize = true;
var wgl = WglPlatformOpenGlInterface.TryCreate();
return wgl;
}
if (opts?.AllowEglInitialization == true)
return EglPlatformOpenGlInterface.TryCreate(() => new AngleWin32EglDisplay());
return EglPlatformInterface;
return null;
});
}
}

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

@ -11,6 +11,7 @@ using Avalonia.Controls;
using Avalonia.Controls.Platform;
using Avalonia.Input;
using Avalonia.Input.Platform;
using Avalonia.OpenGL;
using Avalonia.Platform;
using Avalonia.Rendering;
using Avalonia.Threading;
@ -39,6 +40,12 @@ namespace Avalonia
public bool AllowEglInitialization { get; set; } = true;
public bool? EnableMultitouch { get; set; }
public bool OverlayPopups { get; set; }
public bool UseWgl { get; set; }
public IList<GlVersion> WglProfiles { get; set; } = new List<GlVersion>
{
new GlVersion(GlProfileType.OpenGL, 4, 0),
new GlVersion(GlProfileType.OpenGL, 3, 2),
};
}
}
@ -96,8 +103,7 @@ namespace Avalonia.Win32
.Bind<AvaloniaSynchronizationContext.INonPumpingPlatformWaitProvider>().ToConstant(new NonPumpingWaitProvider())
.Bind<IMountedVolumeInfoProvider>().ToConstant(new WindowsMountedVolumeInfoProvider());
if (options.AllowEglInitialization)
Win32GlManager.Initialize();
Win32GlManager.Initialize();
_uiThread = Thread.CurrentThread;

13
src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs

@ -338,19 +338,14 @@ namespace Avalonia.Win32
}
case WindowsMessage.WM_PAINT:
{
{
using (_rendererLock.Lock())
{
if (BeginPaint(_hwnd, out PAINTSTRUCT ps) != IntPtr.Zero)
{
var f = RenderScaling;
var r = ps.rcPaint;
Paint?.Invoke(new Rect(r.left / f, r.top / f, (r.right - r.left) / f,
(r.bottom - r.top) / f));
EndPaint(_hwnd, ref ps);
}
Paint?.Invoke(default);
}
ValidateRect(hWnd, IntPtr.Zero);
return IntPtr.Zero;
}

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

@ -13,6 +13,7 @@ using Avalonia.Platform;
using Avalonia.Rendering;
using Avalonia.Win32.Input;
using Avalonia.Win32.Interop;
using Avalonia.Win32.OpenGl;
using static Avalonia.Win32.Interop.UnmanagedMethods;
namespace Avalonia.Win32
@ -105,8 +106,12 @@ namespace Avalonia.Win32
CreateWindow();
_framebuffer = new FramebufferManager(_hwnd);
if (Win32GlManager.EglPlatformInterface != null)
_gl = new EglGlPlatformSurface(Win32GlManager.EglPlatformInterface, this);
var glPlatform = AvaloniaLocator.Current.GetService<IPlatformOpenGlInterface>();
if(glPlatform is EglPlatformOpenGlInterface egl)
_gl = new EglGlPlatformSurface(egl, this);
else if (glPlatform is WglPlatformOpenGlInterface wgl)
_gl = new WglGlPlatformSurface(wgl.PrimaryContext, this);
Screen = new ScreenImpl();

Loading…
Cancel
Save