瀏覽代碼

[D2D1] Implement support for IFramebufferPlatformSurface

Nikita Tsukanov 8 年之前
父節點
當前提交
3e09457e10

+ 2 - 0
src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs

@@ -146,6 +146,8 @@ namespace Avalonia.Direct2D1
                 }
                 if (s is IExternalDirect2DRenderTargetSurface external)
                     return new ExternalRenderTarget(external, s_dwfactory);
+                if (s is IFramebufferPlatformSurface fb)
+                    return new FramebufferShimRenderTarget(fb, s_imagingFactory, s_d2D1Factory, s_dwfactory);
             }
             throw new NotSupportedException("Don't know how to create a Direct2D1 renderer from any of provided surfaces");
         }

+ 84 - 0
src/Windows/Avalonia.Direct2D1/FramebufferShimRenderTarget.cs

@@ -0,0 +1,84 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Avalonia.Controls.Platform.Surfaces;
+using Avalonia.Direct2D1.Media;
+using Avalonia.Direct2D1.Media.Imaging;
+using Avalonia.Platform;
+using Avalonia.Rendering;
+using Avalonia.Win32.Interop;
+using SharpDX.Direct2D1;
+using SharpDX.WIC;
+using PixelFormat = Avalonia.Platform.PixelFormat;
+
+namespace Avalonia.Direct2D1
+{
+    class FramebufferShimRenderTarget : IRenderTarget
+    {
+        private readonly IFramebufferPlatformSurface _surface;
+        private readonly ImagingFactory _imagingFactory;
+        private readonly Factory _d2DFactory;
+        private readonly SharpDX.DirectWrite.Factory _dwriteFactory;
+
+        public FramebufferShimRenderTarget(IFramebufferPlatformSurface surface,
+            ImagingFactory imagingFactory, Factory d2dFactory, SharpDX.DirectWrite.Factory dwriteFactory)
+        {
+            _surface = surface;
+            _imagingFactory = imagingFactory;
+            _d2DFactory = d2dFactory;
+            _dwriteFactory = dwriteFactory;
+        }
+
+        public void Dispose()
+        {
+            
+        }
+
+        public IDrawingContextImpl CreateDrawingContext(IVisualBrushRenderer visualBrushRenderer)
+        {
+            var locked = _surface.Lock();
+            if (locked.Format == PixelFormat.Rgb565)
+            {
+                locked.Dispose();
+                throw new ArgumentException("Unsupported pixel format: " + locked.Format);
+            }
+
+            return new FramebufferShim(locked, _imagingFactory, _d2DFactory, _dwriteFactory)
+                .CreateDrawingContext(visualBrushRenderer);
+        }
+
+        class FramebufferShim : RenderTargetBitmapImpl
+        {
+            private readonly ILockedFramebuffer _target;
+
+            public FramebufferShim(ILockedFramebuffer target,
+                ImagingFactory imagingFactory, Factory d2dFactory, SharpDX.DirectWrite.Factory dwriteFactory
+                ) : base(imagingFactory, d2dFactory, dwriteFactory,
+                    target.Width, target.Height, target.Dpi.X, target.Dpi.Y, target.Format)
+            {
+                _target = target;
+            }
+            
+            public override IDrawingContextImpl CreateDrawingContext(IVisualBrushRenderer visualBrushRenderer)
+            {
+                return base.CreateDrawingContext(visualBrushRenderer, () =>
+                {
+                    using (var l = WicImpl.Lock(BitmapLockFlags.Read))
+                    {
+                        for (var y = 0; y < _target.Height; y++)
+                        {
+                            UnmanagedMethods.CopyMemory(
+                                _target.Address + _target.RowBytes * y,
+                                l.Data.DataPointer + l.Stride * y,
+                                (uint) Math.Min(l.Stride, _target.RowBytes));
+                        }
+                    }
+                    Dispose();
+                    _target.Dispose();
+
+                });
+            }
+        }
+
+    }
+}

+ 9 - 4
src/Windows/Avalonia.Direct2D1/Media/Imaging/RenderTargetBitmapImpl.cs

@@ -22,8 +22,9 @@ namespace Avalonia.Direct2D1.Media
             int width,
             int height,
             double dpiX,
-            double dpiY)
-            : base(imagingFactory, width, height)
+            double dpiY,
+            Platform.PixelFormat? pixelFormat = null)
+            : base(imagingFactory, width, height, pixelFormat)
         {
             var props = new RenderTargetProperties
             {
@@ -45,9 +46,13 @@ namespace Avalonia.Direct2D1.Media
             base.Dispose();
         }
 
-        public IDrawingContextImpl CreateDrawingContext(IVisualBrushRenderer visualBrushRenderer)
+        public virtual IDrawingContextImpl CreateDrawingContext(IVisualBrushRenderer visualBrushRenderer)
+            => CreateDrawingContext(visualBrushRenderer, null);
+
+        public IDrawingContextImpl CreateDrawingContext(IVisualBrushRenderer visualBrushRenderer, Action finishedCallback)
         {
-            return new DrawingContextImpl(visualBrushRenderer, _target, _dwriteFactory);
+            return new DrawingContextImpl(visualBrushRenderer, _target, _dwriteFactory,
+                finishedCallback: finishedCallback);
         }
     }
 }

+ 1 - 0
src/Windows/Avalonia.Direct2D1/Media/Imaging/WicBitmapImpl.cs

@@ -74,6 +74,7 @@ namespace Avalonia.Direct2D1.Media
         public WicBitmapImpl(ImagingFactory factory, Platform.PixelFormat format, IntPtr data, int width, int height, int stride)
         {
             WicImpl = new Bitmap(factory, width, height, format.ToWic(), BitmapCreateCacheOption.CacheOnDemand);
+            _factory = factory;
             PixelFormat = format;
             using (var l = WicImpl.Lock(BitmapLockFlags.Write))
             {

+ 6 - 5
tests/Avalonia.RenderTests/Media/BitmapTests.cs

@@ -64,13 +64,13 @@ namespace Avalonia.Direct2D1.RenderTests.Media
             public void Deallocate() => Marshal.FreeHGlobal(Address);
         }
 
-
-#if AVALONIA_SKIA
+        
         [Theory]
-#else
-        [Theory(Skip = "Framebuffer not supported")]
+        [InlineData(PixelFormat.Rgba8888), InlineData(PixelFormat.Bgra8888),
+#if SKIA
+             InlineData(PixelFormat.Rgb565)
 #endif
-        [InlineData(PixelFormat.Rgba8888), InlineData(PixelFormat.Bgra8888), InlineData(PixelFormat.Rgb565)]
+            ]
         public void FramebufferRenderResultsShouldBeUsableAsBitmap(PixelFormat fmt)
         {
             var testName = nameof(FramebufferRenderResultsShouldBeUsableAsBitmap) + "_" + fmt;
@@ -84,6 +84,7 @@ namespace Avalonia.Direct2D1.RenderTests.Media
                 ctx.FillRectangle(Brushes.Chartreuse, new Rect(0, 0, 20, 100));
                 ctx.FillRectangle(Brushes.Crimson, new Rect(20, 0, 20, 100));
                 ctx.FillRectangle(Brushes.Gold, new Rect(40, 0, 20, 100));
+                ctx.PopOpacity();
             }
 
             var bmp = new Bitmap(fmt, fb.Address, fb.Width, fb.Height, fb.RowBytes);

二進制
tests/TestFiles/Direct2D1/Media/Bitmap/FramebufferRenderResultsShouldBeUsableAsBitmap_Bgra8888.expected.png


二進制
tests/TestFiles/Direct2D1/Media/Bitmap/FramebufferRenderResultsShouldBeUsableAsBitmap_Rgb565.expected.png


二進制
tests/TestFiles/Direct2D1/Media/Bitmap/FramebufferRenderResultsShouldBeUsableAsBitmap_Rgba8888.expected.png