瀏覽代碼

Implemented pixel format converter for framebuffer render target

Nikita Tsukanov 8 年之前
父節點
當前提交
9d64f9ddb0
共有 2 個文件被更改,包括 52 次插入27 次删除
  1. 6 1
      src/Skia/Avalonia.Skia/DrawingContextImpl.cs
  2. 46 26
      src/Skia/Avalonia.Skia/FramebufferRenderTarget.cs

+ 6 - 1
src/Skia/Avalonia.Skia/DrawingContextImpl.cs

@@ -10,12 +10,14 @@ namespace Avalonia.Skia
 {
     internal class DrawingContextImpl : IDrawingContextImpl
     {
+        private readonly IDisposable[] _disposables;
         private Stack<PaintWrapper> maskStack = new Stack<PaintWrapper>();
         
         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)

+ 46 - 26
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));
         }
     }