33 changed files with 5278 additions and 162 deletions
@ -0,0 +1,50 @@ |
|||||
|
using System; |
||||
|
using System.Threading; |
||||
|
|
||||
|
namespace Avalonia.Utilities |
||||
|
{ |
||||
|
public class DisposableLock |
||||
|
{ |
||||
|
private readonly object _lock = new object(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Tries to take a lock
|
||||
|
/// </summary>
|
||||
|
/// <returns>IDisposable if succeeded to obtain the lock</returns>
|
||||
|
public IDisposable TryLock() |
||||
|
{ |
||||
|
if (Monitor.TryEnter(_lock)) |
||||
|
return new UnlockDisposable(_lock); |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Enters a waiting lock
|
||||
|
/// </summary>
|
||||
|
public IDisposable Lock() |
||||
|
{ |
||||
|
Monitor.Enter(_lock); |
||||
|
return new UnlockDisposable(_lock); |
||||
|
} |
||||
|
|
||||
|
private sealed class UnlockDisposable : IDisposable |
||||
|
{ |
||||
|
private object _lock; |
||||
|
|
||||
|
public UnlockDisposable(object @lock) |
||||
|
{ |
||||
|
_lock = @lock; |
||||
|
} |
||||
|
|
||||
|
public void Dispose() |
||||
|
{ |
||||
|
object @lock = Interlocked.Exchange(ref _lock, null); |
||||
|
|
||||
|
if (@lock != null) |
||||
|
{ |
||||
|
Monitor.Exit(@lock); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
File diff suppressed because it is too large
@ -1,8 +1,10 @@ |
|||||
|
using System; |
||||
|
|
||||
namespace Avalonia.OpenGL |
namespace Avalonia.OpenGL |
||||
{ |
{ |
||||
public interface IGlContext |
public interface IGlContext : IDisposable |
||||
{ |
{ |
||||
IGlDisplay Display { get; } |
IGlDisplay Display { get; } |
||||
void MakeCurrent(); |
IDisposable MakeCurrent(); |
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -0,0 +1,9 @@ |
|||||
|
using Avalonia.OpenGL.Imaging; |
||||
|
|
||||
|
namespace Avalonia.OpenGL |
||||
|
{ |
||||
|
public interface IOpenGlAwarePlatformRenderInterface |
||||
|
{ |
||||
|
IOpenGlTextureBitmapImpl CreateOpenGlTextureBitmap(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,13 @@ |
|||||
|
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(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,46 @@ |
|||||
|
using System; |
||||
|
using Avalonia.Media; |
||||
|
using Avalonia.Media.Imaging; |
||||
|
using Avalonia.Platform; |
||||
|
using Avalonia.Threading; |
||||
|
|
||||
|
namespace Avalonia.OpenGL.Imaging |
||||
|
{ |
||||
|
public class OpenGlTextureBitmap : Bitmap, IAffectsRender |
||||
|
{ |
||||
|
private IOpenGlTextureBitmapImpl _impl; |
||||
|
static IOpenGlTextureBitmapImpl CreateOrThrow() |
||||
|
{ |
||||
|
if (!(AvaloniaLocator.Current.GetService<IPlatformRenderInterface>() is IOpenGlAwarePlatformRenderInterface |
||||
|
glAware)) |
||||
|
throw new PlatformNotSupportedException("Rendering platform does not support OpenGL integration"); |
||||
|
return glAware.CreateOpenGlTextureBitmap(); |
||||
|
} |
||||
|
|
||||
|
public OpenGlTextureBitmap() |
||||
|
: base(CreateOrThrow()) |
||||
|
{ |
||||
|
_impl = (IOpenGlTextureBitmapImpl)PlatformImpl.Item; |
||||
|
} |
||||
|
|
||||
|
public IDisposable Lock() => _impl.Lock(); |
||||
|
|
||||
|
public void SetTexture(int textureId, int internalFormat, PixelSize size, double dpiScaling) |
||||
|
{ |
||||
|
_impl.SetBackBuffer(textureId, internalFormat, size, dpiScaling); |
||||
|
SetIsDirty(); |
||||
|
} |
||||
|
|
||||
|
public void SetIsDirty() |
||||
|
{ |
||||
|
if (Dispatcher.UIThread.CheckAccess()) |
||||
|
CallInvalidated(); |
||||
|
else |
||||
|
Dispatcher.UIThread.Post(CallInvalidated); |
||||
|
} |
||||
|
|
||||
|
private void CallInvalidated() => Invalidated?.Invoke(this, EventArgs.Empty); |
||||
|
|
||||
|
public event EventHandler Invalidated; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,43 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
using Avalonia.OpenGL; |
||||
|
using Avalonia.OpenGL.Imaging; |
||||
|
using SkiaSharp; |
||||
|
|
||||
|
namespace Avalonia.Skia |
||||
|
{ |
||||
|
class GlSkiaGpu : IOpenGlAwareSkiaGpu |
||||
|
{ |
||||
|
private GRContext _grContext; |
||||
|
|
||||
|
public GlSkiaGpu(IWindowingPlatformGlFeature gl) |
||||
|
{ |
||||
|
|
||||
|
var immediateContext = gl.CreateContext(); |
||||
|
using (immediateContext.MakeCurrent()) |
||||
|
{ |
||||
|
var display = gl.Display; |
||||
|
using (var iface = display.Type == GlDisplayType.OpenGL2 ? |
||||
|
GRGlInterface.AssembleGlInterface((_, proc) => display.GlInterface.GetProcAddress(proc)) : |
||||
|
GRGlInterface.AssembleGlesInterface((_, proc) => display.GlInterface.GetProcAddress(proc))) |
||||
|
{ |
||||
|
_grContext = GRContext.Create(GRBackend.OpenGL, iface); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public ISkiaGpuRenderTarget TryCreateRenderTarget(IEnumerable<object> surfaces) |
||||
|
{ |
||||
|
foreach (var surface in surfaces) |
||||
|
{ |
||||
|
if (surface is IGlPlatformSurface glSurface) |
||||
|
{ |
||||
|
return new GlRenderTarget(_grContext, glSurface); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
public IOpenGlTextureBitmapImpl CreateOpenGlTextureBitmap() => new OpenGlTextureBitmapImpl(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,81 @@ |
|||||
|
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