diff --git a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs index 7744e15104..e72e7514fb 100644 --- a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs +++ b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs @@ -10,12 +10,14 @@ namespace Avalonia.Skia { internal class DrawingContextImpl : IDrawingContextImpl { + private readonly IDisposable[] _disposables; private Stack maskStack = new Stack(); public SKCanvas Canvas { get; private set; } - public DrawingContextImpl(SKCanvas canvas) + public DrawingContextImpl(SKCanvas canvas, params IDisposable[] disposables) { + _disposables = disposables; Canvas = canvas; Canvas.Clear(); } @@ -314,6 +316,9 @@ namespace Avalonia.Skia public virtual void Dispose() { + if(_disposables!=null) + foreach (var disposable in _disposables) + disposable?.Dispose(); } public void PushGeometryClip(Geometry clip) diff --git a/src/Skia/Avalonia.Skia/FramebufferRenderTarget.cs b/src/Skia/Avalonia.Skia/FramebufferRenderTarget.cs index 3d3e322e0d..7aa487808a 100644 --- a/src/Skia/Avalonia.Skia/FramebufferRenderTarget.cs +++ b/src/Skia/Avalonia.Skia/FramebufferRenderTarget.cs @@ -22,27 +22,6 @@ namespace Avalonia.Skia //Nothing to do here, since we don't own framebuffer } - class FramebufferDrawingContextImpl : DrawingContextImpl - { - private readonly SKCanvas _canvas; - private readonly SKSurface _surface; - private readonly ILockedFramebuffer _framebuffer; - - public FramebufferDrawingContextImpl(SKCanvas canvas, SKSurface surface, ILockedFramebuffer framebuffer) : base(canvas) - { - _canvas = canvas; - _surface = surface; - _framebuffer = framebuffer; - } - - public override void Dispose() - { - _canvas.Dispose(); - _surface.Dispose(); - _framebuffer.Dispose(); - base.Dispose(); - } - } SKColorType TranslatePixelFormat(PixelFormat fmt) { @@ -55,22 +34,63 @@ namespace Avalonia.Skia throw new ArgumentException("Unknown pixel format: " + fmt); } + + class PixelFormatShim : IDisposable + { + private readonly SKImageInfo _nfo; + private readonly IntPtr _fb; + private readonly int _rowBytes; + private SKBitmap _bitmap; + + public PixelFormatShim(SKImageInfo nfo, IntPtr fb, int rowBytes) + { + _nfo = nfo; + _fb = fb; + _rowBytes = rowBytes; + + + _bitmap = new SKBitmap(nfo.Width, nfo.Height); + if (!_bitmap.CanCopyTo(nfo.ColorType)) + { + _bitmap.Dispose(); + throw new Exception( + $"Unable to create pixel format shim for conversion from {_bitmap.ColorType} to {nfo.ColorType}"); + } + } + + public SKSurface CreateSurface() => SKSurface.Create(_bitmap.Info, _bitmap.GetPixels(), _bitmap.RowBytes); + + public void Dispose() + { + using (var tmp = _bitmap.Copy(_nfo.ColorType)) + tmp.CopyPixelsTo(_fb, _nfo.BytesPerPixel * _nfo.Height * _rowBytes, _rowBytes); + _bitmap.Dispose(); + } + + } + public DrawingContext CreateDrawingContext() { var fb = _surface.Lock(); - - SKImageInfo nfo = new SKImageInfo(fb.Width, fb.Height, TranslatePixelFormat(fb.Format), + PixelFormatShim shim = null; + SKImageInfo framebuffer = new SKImageInfo(fb.Width, fb.Height, TranslatePixelFormat(fb.Format), SKAlphaType.Opaque); - var surface = SKSurface.Create(nfo, fb.Address, fb.RowBytes); + var surface = SKSurface.Create(framebuffer, fb.Address, fb.RowBytes) ?? + (shim = new PixelFormatShim(framebuffer, fb.Address, fb.RowBytes)) + .CreateSurface(); if (surface == null) - throw new Exception("Unable to create a surface for pixel format " + fb.Format); + throw new Exception("Unable to create a surface for pixel format " + fb.Format + + " or pixel format translator"); var canvas = surface.Canvas; + + + canvas.RestoreToCount(0); canvas.Save(); canvas.Clear(SKColors.Red); canvas.ResetMatrix(); - return new DrawingContext(new FramebufferDrawingContextImpl(canvas, surface, fb), + return new DrawingContext(new DrawingContextImpl(canvas, canvas, surface, shim, fb), Matrix.CreateScale(fb.Dpi.Width / 96, fb.Dpi.Height / 96)); } }