Browse Source
# Conflicts: # src/Avalonia.OpenGL/Angle/AngleEglInterface.cs # src/Avalonia.OpenGL/Angle/AngleWin32EglDisplay.cs # src/Windows/Avalonia.Win32/WindowImpl.cstmp-winuicomp_with_manual_fbo
67 changed files with 947 additions and 535 deletions
@ -0,0 +1,3 @@ |
|||||
|
Compat issues with assembly Avalonia.Base: |
||||
|
CannotAddAbstractMembers : Member 'protected System.IObservable<Avalonia.AvaloniaPropertyChangedEventArgs> Avalonia.AvaloniaProperty.GetChanged()' is abstract in the implementation but is missing in the contract. |
||||
|
Total Issues: 1 |
||||
@ -1,6 +1,6 @@ |
|||||
// ReSharper disable UnusedMember.Global
|
// ReSharper disable UnusedMember.Global
|
||||
// ReSharper disable IdentifierTypo
|
// ReSharper disable IdentifierTypo
|
||||
namespace Avalonia.OpenGL |
namespace Avalonia.OpenGL.Egl |
||||
{ |
{ |
||||
public static class EglConsts |
public static class EglConsts |
||||
{ |
{ |
||||
@ -1,4 +1,4 @@ |
|||||
namespace Avalonia.OpenGL |
namespace Avalonia.OpenGL.Egl |
||||
{ |
{ |
||||
public enum EglErrors |
public enum EglErrors |
||||
{ |
{ |
||||
@ -0,0 +1,54 @@ |
|||||
|
using Avalonia.OpenGL.Surfaces; |
||||
|
|
||||
|
namespace Avalonia.OpenGL.Egl |
||||
|
{ |
||||
|
public class EglGlPlatformSurface : EglGlPlatformSurfaceBase |
||||
|
{ |
||||
|
private readonly EglPlatformOpenGlInterface _egl; |
||||
|
private readonly IEglWindowGlPlatformSurfaceInfo _info; |
||||
|
|
||||
|
public EglGlPlatformSurface(EglPlatformOpenGlInterface egl, IEglWindowGlPlatformSurfaceInfo info) : base() |
||||
|
{ |
||||
|
_egl = egl; |
||||
|
_info = info; |
||||
|
} |
||||
|
|
||||
|
public override IGlPlatformSurfaceRenderTarget CreateGlRenderTarget() |
||||
|
{ |
||||
|
var glSurface = _egl.CreateWindowSurface(_info.Handle); |
||||
|
return new RenderTarget(_egl, glSurface, _info); |
||||
|
} |
||||
|
|
||||
|
class RenderTarget : EglPlatformSurfaceRenderTargetBase |
||||
|
{ |
||||
|
private readonly EglPlatformOpenGlInterface _egl; |
||||
|
private EglSurface _glSurface; |
||||
|
private readonly IEglWindowGlPlatformSurfaceInfo _info; |
||||
|
private PixelSize _currentSize; |
||||
|
|
||||
|
public RenderTarget(EglPlatformOpenGlInterface egl, |
||||
|
EglSurface glSurface, IEglWindowGlPlatformSurfaceInfo info) : base(egl) |
||||
|
{ |
||||
|
_egl = egl; |
||||
|
_glSurface = glSurface; |
||||
|
_info = info; |
||||
|
_currentSize = info.Size; |
||||
|
} |
||||
|
|
||||
|
public override void Dispose() => _glSurface.Dispose(); |
||||
|
|
||||
|
public override IGlPlatformSurfaceRenderingSession BeginDraw() |
||||
|
{ |
||||
|
if (_info.Size != _currentSize || _glSurface == null) |
||||
|
{ |
||||
|
_glSurface?.Dispose(); |
||||
|
_glSurface = null; |
||||
|
_glSurface = _egl.CreateWindowSurface(_info.Handle); |
||||
|
_currentSize = _info.Size; |
||||
|
} |
||||
|
return base.BeginDraw(_glSurface, _info); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
@ -0,0 +1,72 @@ |
|||||
|
using System; |
||||
|
using Avalonia.Logging; |
||||
|
using static Avalonia.OpenGL.Egl.EglConsts; |
||||
|
|
||||
|
namespace Avalonia.OpenGL.Egl |
||||
|
{ |
||||
|
public class EglPlatformOpenGlInterface : IPlatformOpenGlInterface |
||||
|
{ |
||||
|
public EglDisplay Display { get; private set; } |
||||
|
public bool CanCreateContexts => true; |
||||
|
public bool CanShareContexts => Display.SupportsSharing; |
||||
|
|
||||
|
public EglContext PrimaryEglContext { get; } |
||||
|
public IGlContext PrimaryContext => PrimaryEglContext; |
||||
|
|
||||
|
public EglPlatformOpenGlInterface(EglDisplay display) |
||||
|
{ |
||||
|
Display = display; |
||||
|
PrimaryEglContext = display.CreateContext(null); |
||||
|
} |
||||
|
|
||||
|
public static void TryInitialize() |
||||
|
{ |
||||
|
var feature = TryCreate(); |
||||
|
if (feature != null) |
||||
|
AvaloniaLocator.CurrentMutable.Bind<IPlatformOpenGlInterface>().ToConstant(feature); |
||||
|
} |
||||
|
|
||||
|
public static EglPlatformOpenGlInterface TryCreate() => TryCreate(() => new EglDisplay()); |
||||
|
public static EglPlatformOpenGlInterface TryCreate(Func<EglDisplay> displayFactory) |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
return new EglPlatformOpenGlInterface(displayFactory()); |
||||
|
} |
||||
|
catch(Exception e) |
||||
|
{ |
||||
|
Logger.TryGet(LogEventLevel.Error, "OpenGL")?.Log(null, "Unable to initialize EGL-based rendering: {0}", e); |
||||
|
return null; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public IGlContext CreateContext() => Display.CreateContext(null); |
||||
|
public IGlContext CreateSharedContext() => Display.CreateContext(PrimaryEglContext); |
||||
|
|
||||
|
|
||||
|
public EglSurface CreateWindowSurface(IntPtr window) |
||||
|
{ |
||||
|
using (PrimaryContext.MakeCurrent()) |
||||
|
{ |
||||
|
var s = Display.EglInterface.CreateWindowSurface(Display.Handle, Display.Config, window, |
||||
|
new[] { EGL_NONE, EGL_NONE }); |
||||
|
if (s == IntPtr.Zero) |
||||
|
throw OpenGlException.GetFormattedException("eglCreateWindowSurface", Display.EglInterface); |
||||
|
return new EglSurface(Display, PrimaryEglContext, s); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public EglSurface CreatePBufferFromClientBuffer (int bufferType, IntPtr handle, int[] attribs) |
||||
|
{ |
||||
|
using (PrimaryContext.MakeCurrent()) |
||||
|
{ |
||||
|
var s = Display.EglInterface.CreatePbufferFromClientBuffer(Display.Handle, bufferType, handle, |
||||
|
Display.Config, attribs); |
||||
|
|
||||
|
if (s == IntPtr.Zero) |
||||
|
throw OpenGlException.GetFormattedException("eglCreatePbufferFromClientBuffer", Display.EglInterface); |
||||
|
return new EglSurface(Display, PrimaryEglContext, s); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,22 +1,25 @@ |
|||||
using System; |
using System; |
||||
using System.Runtime.InteropServices; |
using System.Runtime.InteropServices; |
||||
|
|
||||
namespace Avalonia.OpenGL |
namespace Avalonia.OpenGL.Egl |
||||
{ |
{ |
||||
public class EglSurface : SafeHandle |
public class EglSurface : SafeHandle |
||||
{ |
{ |
||||
private readonly EglDisplay _display; |
private readonly EglDisplay _display; |
||||
|
private readonly EglContext _context; |
||||
private readonly EglInterface _egl; |
private readonly EglInterface _egl; |
||||
|
|
||||
public EglSurface(EglDisplay display, EglInterface egl, IntPtr surface) : base(surface, true) |
public EglSurface(EglDisplay display, EglContext context, IntPtr surface) : base(surface, true) |
||||
{ |
{ |
||||
_display = display; |
_display = display; |
||||
_egl = egl; |
_context = context; |
||||
|
_egl = display.EglInterface; |
||||
} |
} |
||||
|
|
||||
protected override bool ReleaseHandle() |
protected override bool ReleaseHandle() |
||||
{ |
{ |
||||
_egl.DestroySurface(_display.Handle, handle); |
using (_context.MakeCurrent()) |
||||
|
_egl.DestroySurface(_display.Handle, handle); |
||||
return true; |
return true; |
||||
} |
} |
||||
|
|
||||
@ -1,43 +0,0 @@ |
|||||
using System; |
|
||||
using Avalonia.Logging; |
|
||||
|
|
||||
namespace Avalonia.OpenGL |
|
||||
{ |
|
||||
public class EglGlPlatformFeature : IWindowingPlatformGlFeature |
|
||||
{ |
|
||||
private EglDisplay _display; |
|
||||
public EglDisplay Display => _display; |
|
||||
public IGlContext CreateContext() |
|
||||
{ |
|
||||
return _display.CreateContext(DeferredContext); |
|
||||
} |
|
||||
public EglContext DeferredContext { get; private set; } |
|
||||
public IGlContext MainContext => DeferredContext; |
|
||||
|
|
||||
public static void TryInitialize() |
|
||||
{ |
|
||||
var feature = TryCreate(); |
|
||||
if (feature != null) |
|
||||
AvaloniaLocator.CurrentMutable.Bind<IWindowingPlatformGlFeature>().ToConstant(feature); |
|
||||
} |
|
||||
|
|
||||
public static EglGlPlatformFeature TryCreate() => TryCreate(() => new EglDisplay()); |
|
||||
public static EglGlPlatformFeature TryCreate(Func<EglDisplay> displayFactory) |
|
||||
{ |
|
||||
try |
|
||||
{ |
|
||||
var disp = displayFactory(); |
|
||||
return new EglGlPlatformFeature |
|
||||
{ |
|
||||
_display = disp, |
|
||||
DeferredContext = disp.CreateContext(null) |
|
||||
}; |
|
||||
} |
|
||||
catch(Exception e) |
|
||||
{ |
|
||||
Logger.TryGet(LogEventLevel.Error, "OpenGL")?.Log(null, "Unable to initialize EGL-based rendering: {0}", e); |
|
||||
return null; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,51 +0,0 @@ |
|||||
using System; |
|
||||
using System.Threading; |
|
||||
|
|
||||
namespace Avalonia.OpenGL |
|
||||
{ |
|
||||
public class EglGlPlatformSurface : EglGlPlatformSurfaceBase |
|
||||
{ |
|
||||
private readonly EglDisplay _display; |
|
||||
private readonly EglContext _context; |
|
||||
private readonly IEglWindowGlPlatformSurfaceInfo _info; |
|
||||
|
|
||||
public EglGlPlatformSurface(EglContext context, IEglWindowGlPlatformSurfaceInfo info) : base() |
|
||||
{ |
|
||||
_display = context.Display; |
|
||||
_context = context; |
|
||||
_info = info; |
|
||||
} |
|
||||
|
|
||||
public override IGlPlatformSurfaceRenderTarget CreateGlRenderTarget() |
|
||||
{ |
|
||||
var glSurface = _display.CreateWindowSurface(_info.Handle); |
|
||||
return new RenderTarget(_display, _context, glSurface, _info); |
|
||||
} |
|
||||
|
|
||||
class RenderTarget : EglPlatformSurfaceRenderTargetBase |
|
||||
{ |
|
||||
private readonly EglDisplay _display; |
|
||||
private readonly EglContext _context; |
|
||||
private readonly EglSurface _glSurface; |
|
||||
private readonly IEglWindowGlPlatformSurfaceInfo _info; |
|
||||
private PixelSize _initialSize; |
|
||||
|
|
||||
public RenderTarget(EglDisplay display, EglContext context, |
|
||||
EglSurface glSurface, IEglWindowGlPlatformSurfaceInfo info) : base(display, context) |
|
||||
{ |
|
||||
_display = display; |
|
||||
_context = context; |
|
||||
_glSurface = glSurface; |
|
||||
_info = info; |
|
||||
_initialSize = info.Size; |
|
||||
} |
|
||||
|
|
||||
public override void Dispose() => _glSurface.Dispose(); |
|
||||
|
|
||||
public override bool IsCorrupted => _initialSize != _info.Size; |
|
||||
|
|
||||
public override IGlPlatformSurfaceRenderingSession BeginDraw() => base.BeginDraw(_glSurface, _info); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
@ -0,0 +1,13 @@ |
|||||
|
namespace Avalonia.OpenGL |
||||
|
{ |
||||
|
public interface IPlatformOpenGlInterface |
||||
|
{ |
||||
|
IGlContext PrimaryContext { get; } |
||||
|
IGlContext CreateSharedContext(); |
||||
|
bool CanShareContexts { get; } |
||||
|
bool CanCreateContexts { get; } |
||||
|
IGlContext CreateContext(); |
||||
|
/*IGlContext TryCreateContext(GlVersion version); |
||||
|
*/ |
||||
|
} |
||||
|
} |
||||
@ -1,8 +0,0 @@ |
|||||
namespace Avalonia.OpenGL |
|
||||
{ |
|
||||
public interface IWindowingPlatformGlFeature |
|
||||
{ |
|
||||
IGlContext CreateContext(); |
|
||||
IGlContext MainContext { get; } |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,17 @@ |
|||||
|
using System; |
||||
|
using Avalonia.Media.Imaging; |
||||
|
using Avalonia.Platform; |
||||
|
|
||||
|
namespace Avalonia.OpenGL.Imaging |
||||
|
{ |
||||
|
public interface IOpenGlBitmapImpl : IBitmapImpl |
||||
|
{ |
||||
|
IOpenGlBitmapAttachment CreateFramebufferAttachment(IGlContext context, Action presentCallback); |
||||
|
bool SupportsContext(IGlContext context); |
||||
|
} |
||||
|
|
||||
|
public interface IOpenGlBitmapAttachment : IDisposable |
||||
|
{ |
||||
|
void Present(); |
||||
|
} |
||||
|
} |
||||
@ -1,13 +0,0 @@ |
|||||
using System; |
|
||||
using Avalonia.Media.Imaging; |
|
||||
using Avalonia.Platform; |
|
||||
|
|
||||
namespace Avalonia.OpenGL.Imaging |
|
||||
{ |
|
||||
public interface IOpenGlTextureBitmapImpl : IBitmapImpl |
|
||||
{ |
|
||||
IDisposable Lock(); |
|
||||
void SetBackBuffer(int textureId, int internalFormat, PixelSize pixelSize, double dpiScaling); |
|
||||
void SetDirty(); |
|
||||
} |
|
||||
} |
|
||||
@ -1,4 +1,4 @@ |
|||||
namespace Avalonia.OpenGL |
namespace Avalonia.OpenGL.Surfaces |
||||
{ |
{ |
||||
public interface IGlPlatformSurface |
public interface IGlPlatformSurface |
||||
{ |
{ |
||||
@ -1,6 +1,6 @@ |
|||||
using System; |
using System; |
||||
|
|
||||
namespace Avalonia.OpenGL |
namespace Avalonia.OpenGL.Surfaces |
||||
{ |
{ |
||||
public interface IGlPlatformSurfaceRenderTarget : IDisposable |
public interface IGlPlatformSurfaceRenderTarget : IDisposable |
||||
{ |
{ |
||||
@ -1,6 +1,6 @@ |
|||||
using System; |
using System; |
||||
|
|
||||
namespace Avalonia.OpenGL |
namespace Avalonia.OpenGL.Surfaces |
||||
{ |
{ |
||||
public interface IGlPlatformSurfaceRenderingSession : IDisposable |
public interface IGlPlatformSurfaceRenderingSession : IDisposable |
||||
{ |
{ |
||||
@ -0,0 +1,9 @@ |
|||||
|
using Avalonia.OpenGL; |
||||
|
|
||||
|
namespace Avalonia.LinuxFramebuffer.Output |
||||
|
{ |
||||
|
public interface IGlOutputBackend : IOutputBackend |
||||
|
{ |
||||
|
public IPlatformOpenGlInterface PlatformOpenGlInterface { get; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,207 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.IO; |
||||
|
using Avalonia.OpenGL; |
||||
|
using Avalonia.OpenGL.Imaging; |
||||
|
using Avalonia.Utilities; |
||||
|
using SkiaSharp; |
||||
|
using static Avalonia.OpenGL.GlConsts; |
||||
|
|
||||
|
namespace Avalonia.Skia |
||||
|
{ |
||||
|
class GlOpenGlBitmapImpl : IOpenGlBitmapImpl, IDrawableBitmapImpl |
||||
|
{ |
||||
|
private readonly IGlContext _context; |
||||
|
private readonly object _lock = new object(); |
||||
|
private IGlPresentableOpenGlSurface _surface; |
||||
|
|
||||
|
public GlOpenGlBitmapImpl(IGlContext context, PixelSize pixelSize, Vector dpi) |
||||
|
{ |
||||
|
_context = context; |
||||
|
PixelSize = pixelSize; |
||||
|
Dpi = dpi; |
||||
|
} |
||||
|
|
||||
|
public Vector Dpi { get; } |
||||
|
public PixelSize PixelSize { get; } |
||||
|
public int Version { get; private set; } |
||||
|
public void Save(string fileName) => throw new NotSupportedException(); |
||||
|
|
||||
|
public void Save(Stream stream) => throw new NotSupportedException(); |
||||
|
|
||||
|
public void Draw(DrawingContextImpl context, SKRect sourceRect, SKRect destRect, SKPaint paint) |
||||
|
{ |
||||
|
lock (_lock) |
||||
|
{ |
||||
|
if (_surface == null) |
||||
|
return; |
||||
|
using (_surface.Lock()) |
||||
|
{ |
||||
|
using (var backendTexture = new GRBackendTexture(PixelSize.Width, PixelSize.Height, false, |
||||
|
new GRGlTextureInfo( |
||||
|
GlConsts.GL_TEXTURE_2D, (uint)_surface.GetTextureId(), |
||||
|
(uint)_surface.InternalFormat))) |
||||
|
using (var surface = SKSurface.Create(context.GrContext, backendTexture, GRSurfaceOrigin.TopLeft, |
||||
|
SKColorType.Rgba8888)) |
||||
|
{ |
||||
|
// Again, silently ignore, if something went wrong it's not our fault
|
||||
|
if (surface == null) |
||||
|
return; |
||||
|
|
||||
|
using (var snapshot = surface.Snapshot()) |
||||
|
context.Canvas.DrawImage(snapshot, sourceRect, destRect, paint); |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public IOpenGlBitmapAttachment CreateFramebufferAttachment(IGlContext context, Action presentCallback) |
||||
|
{ |
||||
|
if (!SupportsContext(context)) |
||||
|
throw new OpenGlException("Context is not supported for texture sharing"); |
||||
|
return new SharedOpenGlBitmapAttachment(this, context, presentCallback); |
||||
|
} |
||||
|
|
||||
|
public bool SupportsContext(IGlContext context) |
||||
|
{ |
||||
|
// TODO: negotiated platform surface sharing
|
||||
|
return _context.IsSharedWith(context); |
||||
|
} |
||||
|
|
||||
|
public void Dispose() |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
|
||||
|
internal void Present(IGlPresentableOpenGlSurface surface) |
||||
|
{ |
||||
|
lock (_lock) |
||||
|
{ |
||||
|
_surface = surface; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
interface IGlPresentableOpenGlSurface : IDisposable |
||||
|
{ |
||||
|
int GetTextureId(); |
||||
|
int InternalFormat { get; } |
||||
|
IDisposable Lock(); |
||||
|
} |
||||
|
|
||||
|
class SharedOpenGlBitmapAttachment : IOpenGlBitmapAttachment, IGlPresentableOpenGlSurface |
||||
|
{ |
||||
|
private readonly GlOpenGlBitmapImpl _bitmap; |
||||
|
private readonly IGlContext _context; |
||||
|
private readonly Action _presentCallback; |
||||
|
private readonly int _fbo; |
||||
|
private readonly int _texture; |
||||
|
private readonly int _frontBuffer; |
||||
|
private bool _disposed; |
||||
|
private readonly DisposableLock _lock = new DisposableLock(); |
||||
|
|
||||
|
public SharedOpenGlBitmapAttachment(GlOpenGlBitmapImpl bitmap, IGlContext context, Action presentCallback) |
||||
|
{ |
||||
|
_bitmap = bitmap; |
||||
|
_context = context; |
||||
|
_presentCallback = presentCallback; |
||||
|
using (_context.EnsureCurrent()) |
||||
|
{ |
||||
|
var glVersion = _context.Version; |
||||
|
InternalFormat = glVersion.Type == GlProfileType.OpenGLES ? GL_RGBA : GL_RGBA8; |
||||
|
|
||||
|
_context.GlInterface.GetIntegerv(GL_FRAMEBUFFER_BINDING, out _fbo); |
||||
|
if (_fbo == 0) |
||||
|
throw new OpenGlException("Current FBO is 0"); |
||||
|
|
||||
|
{ |
||||
|
var gl = _context.GlInterface; |
||||
|
|
||||
|
var textures = new int[2]; |
||||
|
gl.GenTextures(2, textures); |
||||
|
_texture = textures[0]; |
||||
|
_frontBuffer = textures[1]; |
||||
|
|
||||
|
gl.GetIntegerv(GL_TEXTURE_BINDING_2D, out var oldTexture); |
||||
|
foreach (var t in textures) |
||||
|
{ |
||||
|
gl.BindTexture(GL_TEXTURE_2D, t); |
||||
|
gl.TexImage2D(GL_TEXTURE_2D, 0, |
||||
|
InternalFormat, |
||||
|
_bitmap.PixelSize.Width, _bitmap.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); |
||||
|
gl.BindTexture(GL_TEXTURE_2D, oldTexture); |
||||
|
|
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public void Present() |
||||
|
{ |
||||
|
using (_context.MakeCurrent()) |
||||
|
{ |
||||
|
if (_disposed) |
||||
|
throw new ObjectDisposedException(nameof(SharedOpenGlBitmapAttachment)); |
||||
|
|
||||
|
var gl = _context.GlInterface; |
||||
|
|
||||
|
gl.Finish(); |
||||
|
using (Lock()) |
||||
|
{ |
||||
|
gl.GetIntegerv(GL_FRAMEBUFFER_BINDING, out var oldFbo); |
||||
|
gl.GetIntegerv(GL_TEXTURE_BINDING_2D, out var oldTexture); |
||||
|
gl.GetIntegerv(GL_ACTIVE_TEXTURE, out var oldActive); |
||||
|
|
||||
|
gl.BindFramebuffer(GL_FRAMEBUFFER, _fbo); |
||||
|
gl.BindTexture(GL_TEXTURE_2D, _frontBuffer); |
||||
|
gl.ActiveTexture(GL_TEXTURE0); |
||||
|
|
||||
|
gl.CopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, _bitmap.PixelSize.Width, |
||||
|
_bitmap.PixelSize.Height); |
||||
|
|
||||
|
gl.BindFramebuffer(GL_FRAMEBUFFER, oldFbo); |
||||
|
gl.BindTexture(GL_TEXTURE_2D, oldTexture); |
||||
|
gl.ActiveTexture(oldActive); |
||||
|
|
||||
|
gl.Finish(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
_bitmap.Present(this); |
||||
|
_presentCallback(); |
||||
|
} |
||||
|
|
||||
|
public void Dispose() |
||||
|
{ |
||||
|
var gl = _context.GlInterface; |
||||
|
_bitmap.Present(null); |
||||
|
|
||||
|
if(_disposed) |
||||
|
return; |
||||
|
using (_context.MakeCurrent()) |
||||
|
using (Lock()) |
||||
|
{ |
||||
|
if(_disposed) |
||||
|
return; |
||||
|
_disposed = true; |
||||
|
gl.DeleteTextures(2, new[] { _texture, _frontBuffer }); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
int IGlPresentableOpenGlSurface.GetTextureId() |
||||
|
{ |
||||
|
return _frontBuffer; |
||||
|
} |
||||
|
|
||||
|
public int InternalFormat { get; } |
||||
|
|
||||
|
public IDisposable Lock() => _lock.Lock(); |
||||
|
} |
||||
|
} |
||||
@ -1,81 +0,0 @@ |
|||||
using System; |
|
||||
using System.IO; |
|
||||
using Avalonia.OpenGL; |
|
||||
using Avalonia.OpenGL.Imaging; |
|
||||
using Avalonia.Skia.Helpers; |
|
||||
using Avalonia.Utilities; |
|
||||
using SkiaSharp; |
|
||||
|
|
||||
namespace Avalonia.Skia |
|
||||
{ |
|
||||
class OpenGlTextureBitmapImpl : IOpenGlTextureBitmapImpl, IDrawableBitmapImpl |
|
||||
{ |
|
||||
private DisposableLock _lock = new DisposableLock(); |
|
||||
private int _textureId; |
|
||||
private int _internalFormat; |
|
||||
|
|
||||
public void Dispose() |
|
||||
{ |
|
||||
using (Lock()) |
|
||||
{ |
|
||||
_textureId = 0; |
|
||||
PixelSize = new PixelSize(1, 1); |
|
||||
Version++; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public Vector Dpi { get; private set; } = new Vector(96, 96); |
|
||||
public PixelSize PixelSize { get; private set; } = new PixelSize(1, 1); |
|
||||
public int Version { get; private set; } = 0; |
|
||||
|
|
||||
public void Save(string fileName) => throw new System.NotSupportedException(); |
|
||||
public void Save(Stream stream) => throw new System.NotSupportedException(); |
|
||||
|
|
||||
public void Draw(DrawingContextImpl context, SKRect sourceRect, SKRect destRect, SKPaint paint) |
|
||||
{ |
|
||||
// For now silently ignore
|
|
||||
if (context.GrContext == null) |
|
||||
return; |
|
||||
|
|
||||
using (Lock()) |
|
||||
{ |
|
||||
if (_textureId == 0) |
|
||||
return; |
|
||||
using (var backendTexture = new GRBackendTexture(PixelSize.Width, PixelSize.Height, false, |
|
||||
new GRGlTextureInfo( |
|
||||
GlConsts.GL_TEXTURE_2D, (uint)_textureId, |
|
||||
(uint)_internalFormat))) |
|
||||
using (var surface = SKSurface.Create(context.GrContext, backendTexture, GRSurfaceOrigin.TopLeft, |
|
||||
SKColorType.Rgba8888)) |
|
||||
{ |
|
||||
// Again, silently ignore, if something went wrong it's not our fault
|
|
||||
if (surface == null) |
|
||||
return; |
|
||||
|
|
||||
using (var snapshot = surface.Snapshot()) |
|
||||
context.Canvas.DrawImage(snapshot, sourceRect, destRect, paint); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public IDisposable Lock() => _lock.Lock(); |
|
||||
|
|
||||
public void SetBackBuffer(int textureId, int internalFormat, PixelSize pixelSize, double dpiScaling) |
|
||||
{ |
|
||||
using (_lock.Lock()) |
|
||||
{ |
|
||||
_textureId = textureId; |
|
||||
_internalFormat = internalFormat; |
|
||||
PixelSize = pixelSize; |
|
||||
Dpi = new Vector(96 * dpiScaling, 96 * dpiScaling); |
|
||||
Version++; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public void SetDirty() |
|
||||
{ |
|
||||
using (_lock.Lock()) |
|
||||
Version++; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
Loading…
Reference in new issue