committed by
GitHub
45 changed files with 1085 additions and 139 deletions
@ -0,0 +1,134 @@ |
|||
using System; |
|||
using Avalonia.OpenGL; |
|||
using SkiaSharp; |
|||
using static Avalonia.OpenGL.GlConsts; |
|||
namespace Avalonia.Skia |
|||
{ |
|||
public class FboSkiaSurface : ISkiaSurface |
|||
{ |
|||
private readonly GRContext _grContext; |
|||
private readonly IGlContext _glContext; |
|||
private readonly PixelSize _pixelSize; |
|||
private int _fbo; |
|||
private int _depthStencil; |
|||
private int _texture; |
|||
|
|||
private static readonly bool[] TrueFalse = new[] { true, false }; |
|||
public FboSkiaSurface(GRContext grContext, IGlContext glContext, PixelSize pixelSize) |
|||
{ |
|||
_grContext = grContext; |
|||
_glContext = glContext; |
|||
_pixelSize = pixelSize; |
|||
var InternalFormat = glContext.Version.Type == GlProfileType.OpenGLES ? GL_RGBA : GL_RGBA8; |
|||
var gl = glContext.GlInterface; |
|||
|
|||
// Save old bindings
|
|||
gl.GetIntegerv(GL_FRAMEBUFFER_BINDING, out var oldFbo); |
|||
gl.GetIntegerv(GL_RENDERBUFFER_BINDING, out var oldRenderbuffer); |
|||
gl.GetIntegerv(GL_TEXTURE_BINDING_2D, out var oldTexture); |
|||
|
|||
var arr = new int[2]; |
|||
|
|||
// Generate FBO
|
|||
gl.GenFramebuffers(1, arr); |
|||
_fbo = arr[0]; |
|||
gl.BindFramebuffer(GL_FRAMEBUFFER, _fbo); |
|||
|
|||
// Create a texture to render into
|
|||
gl.GenTextures(1, arr); |
|||
_texture = arr[0]; |
|||
gl.BindTexture(GL_TEXTURE_2D, _texture); |
|||
gl.TexImage2D(GL_TEXTURE_2D, 0, |
|||
InternalFormat, pixelSize.Width, pixelSize.Height, |
|||
0, GL_RGBA, GL_UNSIGNED_BYTE, IntPtr.Zero); |
|||
gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
|||
gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
|||
gl.FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _texture, 0); |
|||
|
|||
var success = false; |
|||
foreach (var useStencil8 in TrueFalse) |
|||
{ |
|||
gl.GenRenderbuffers(1, arr); |
|||
_depthStencil = arr[0]; |
|||
gl.BindRenderbuffer(GL_RENDERBUFFER, _depthStencil); |
|||
|
|||
if (useStencil8) |
|||
{ |
|||
gl.RenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, pixelSize.Width, pixelSize.Height); |
|||
gl.FramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, _depthStencil); |
|||
} |
|||
else |
|||
{ |
|||
gl.RenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, pixelSize.Width, pixelSize.Height); |
|||
gl.FramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, _depthStencil); |
|||
gl.FramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, _depthStencil); |
|||
} |
|||
|
|||
var status = gl.CheckFramebufferStatus(GL_FRAMEBUFFER); |
|||
if (status == GL_FRAMEBUFFER_COMPLETE) |
|||
{ |
|||
success = true; |
|||
break; |
|||
} |
|||
else |
|||
{ |
|||
gl.BindRenderbuffer(GL_RENDERBUFFER, oldRenderbuffer); |
|||
gl.DeleteRenderbuffers(1, arr); |
|||
} |
|||
} |
|||
|
|||
gl.BindRenderbuffer(GL_RENDERBUFFER, oldRenderbuffer); |
|||
gl.BindTexture(GL_TEXTURE_2D, oldTexture); |
|||
gl.BindFramebuffer(GL_FRAMEBUFFER, oldFbo); |
|||
|
|||
if (!success) |
|||
{ |
|||
arr[0] = _fbo; |
|||
gl.DeleteFramebuffers(1, arr); |
|||
arr[0] = _texture; |
|||
gl.DeleteTextures(1, arr); |
|||
throw new OpenGlException("Unable to create FBO with stencil"); |
|||
} |
|||
|
|||
var target = new GRBackendRenderTarget(pixelSize.Width, pixelSize.Height, 0, 8, |
|||
new GRGlFramebufferInfo((uint)_fbo, SKColorType.Rgba8888.ToGlSizedFormat())); |
|||
Surface = SKSurface.Create(_grContext, target, |
|||
GRSurfaceOrigin.BottomLeft, SKColorType.Rgba8888); |
|||
CanBlit = gl.BlitFramebuffer != null; |
|||
} |
|||
|
|||
public void Dispose() |
|||
{ |
|||
using (_glContext.EnsureCurrent()) |
|||
{ |
|||
Surface?.Dispose(); |
|||
Surface = null; |
|||
var gl = _glContext.GlInterface; |
|||
if (_fbo != 0) |
|||
{ |
|||
gl.DeleteFramebuffers(1, new[] { _fbo }); |
|||
gl.DeleteTextures(1, new[] { _texture }); |
|||
gl.DeleteRenderbuffers(1, new[] { _depthStencil }); |
|||
_fbo = _texture = _depthStencil = 0; |
|||
} |
|||
} |
|||
} |
|||
|
|||
public SKSurface Surface { get; private set; } |
|||
public bool CanBlit { get; } |
|||
public void Blit(SKCanvas canvas) |
|||
{ |
|||
// This should set the render target as the current FBO
|
|||
// which is definitely not the best method, but it works
|
|||
canvas.Clear(); |
|||
canvas.Flush(); |
|||
|
|||
var gl = _glContext.GlInterface; |
|||
gl.GetIntegerv(GL_READ_FRAMEBUFFER_BINDING, out var oldRead); |
|||
gl.BindFramebuffer(GL_READ_FRAMEBUFFER, _fbo); |
|||
gl.BlitFramebuffer(0, 0, _pixelSize.Width, _pixelSize.Height, 0, 0, _pixelSize.Width, _pixelSize.Height, |
|||
GL_COLOR_BUFFER_BIT, GL_LINEAR); |
|||
gl.BindFramebuffer(GL_READ_FRAMEBUFFER, oldRead); |
|||
} |
|||
} |
|||
} |
|||
@ -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; |
|||
|
|||
} |
|||
} |
|||
@ -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; |
|||
} |
|||
} |
|||
} |
|||
@ -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); |
|||
} |
|||
} |
|||
@ -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; } |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -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; |
|||
} |
|||
} |
|||
} |
|||
@ -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); |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue