Procházet zdrojové kódy

Added methods for creating D2D render layers.

Craetes a compatible render target depending on the type of `IRenderTargetBitmapImpl`.
Steven Kirk před 8 roky
rodič
revize
e7247a2c12

+ 2 - 1
samples/interop/Direct3DInteropSample/MainWindow.cs

@@ -254,7 +254,8 @@ namespace Direct3DInteropSample
             public IDrawingContextImpl CreateDrawingContext(IVisualBrushRenderer visualBrushRenderer)
             {
                 return new DrawingContextImpl(visualBrushRenderer, _window._d2dRenderTarget,
-                    AvaloniaLocator.Current.GetService<SharpDX.DirectWrite.Factory>());
+                    AvaloniaLocator.Current.GetService<SharpDX.DirectWrite.Factory>(),
+                    AvaloniaLocator.Current.GetService<ImagingFactory>());
             }
         }
 

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

@@ -145,7 +145,7 @@ namespace Avalonia.Direct2D1
                     return new HwndRenderTarget(nativeWindow);
                 }
                 if (s is IExternalDirect2DRenderTargetSurface external)
-                    return new ExternalRenderTarget(external, s_dwfactory);
+                    return new ExternalRenderTarget(external, s_dwfactory, s_imagingFactory);
             }
             throw new NotSupportedException("Don't know how to create a Direct2D1 renderer from any of provided surfaces");
         }
@@ -156,7 +156,7 @@ namespace Avalonia.Direct2D1
             double dpiX,
             double dpiY)
         {
-            return new RenderTargetBitmapImpl(
+            return new WicRenderTargetBitmapImpl(
                 s_imagingFactory,
                 s_d2D1Factory,
                 s_dwfactory,

+ 8 - 7
src/Windows/Avalonia.Direct2D1/ExternalRenderTarget.cs

@@ -1,8 +1,4 @@
 using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
 using Avalonia.Direct2D1.Media;
 using Avalonia.Platform;
 using Avalonia.Rendering;
@@ -15,11 +11,16 @@ namespace Avalonia.Direct2D1
     {
         private readonly IExternalDirect2DRenderTargetSurface _externalRenderTargetProvider;
         private readonly DirectWriteFactory _dwFactory;
-        public ExternalRenderTarget(IExternalDirect2DRenderTargetSurface externalRenderTargetProvider,
-            DirectWriteFactory dwFactory)
+        private readonly SharpDX.WIC.ImagingFactory _wicFactory;
+
+        public ExternalRenderTarget(
+            IExternalDirect2DRenderTargetSurface externalRenderTargetProvider,
+            DirectWriteFactory dwFactory,
+            SharpDX.WIC.ImagingFactory wicFactory)
         {
             _externalRenderTargetProvider = externalRenderTargetProvider;
             _dwFactory = dwFactory;
+            _wicFactory = wicFactory;
         }
 
         public void Dispose()
@@ -31,7 +32,7 @@ namespace Avalonia.Direct2D1
         {
             var target =  _externalRenderTargetProvider.GetOrCreateRenderTarget();
             _externalRenderTargetProvider.BeforeDrawing();
-            return new DrawingContextImpl(visualBrushRenderer, target, _dwFactory, null, () =>
+            return new DrawingContextImpl(visualBrushRenderer, target, _dwFactory, _wicFactory, null, () =>
             {
                 try
                 {

+ 10 - 0
src/Windows/Avalonia.Direct2D1/ICreateLayer.cs

@@ -0,0 +1,10 @@
+using System;
+using Avalonia.Platform;
+
+namespace Avalonia.Direct2D1
+{
+    internal interface ICreateLayer
+    {
+        IRenderTargetBitmapImpl CreateLayer(int pixelWidth, int pixelHeight);
+    }
+}

+ 7 - 6
src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs

@@ -2,16 +2,13 @@
 // Licensed under the MIT license. See licence.md file in the project root for full license information.
 
 using System;
-using System.Collections;
 using System.Collections.Generic;
 using Avalonia.Media;
 using Avalonia.Platform;
-using Avalonia.RenderHelpers;
 using Avalonia.Rendering;
 using SharpDX;
 using SharpDX.Direct2D1;
 using SharpDX.Mathematics.Interop;
-using IBitmap = Avalonia.Media.Imaging.IBitmap;
 
 namespace Avalonia.Direct2D1.Media
 {
@@ -24,6 +21,7 @@ namespace Avalonia.Direct2D1.Media
         private readonly SharpDX.Direct2D1.RenderTarget _renderTarget;
         private readonly SharpDX.DXGI.SwapChain1 _swapChain;
         private readonly Action _finishedCallback;
+        private readonly SharpDX.WIC.ImagingFactory _imagingFactory;
         private SharpDX.DirectWrite.Factory _directWriteFactory;
 
         /// <summary>
@@ -32,12 +30,14 @@ namespace Avalonia.Direct2D1.Media
         /// <param name="visualBrushRenderer">The visual brush renderer.</param>
         /// <param name="renderTarget">The render target to draw to.</param>
         /// <param name="directWriteFactory">The DirectWrite factory.</param>
+        /// <param name="imagingFactory">The WIC imaging factory.</param>
         /// <param name="swapChain">An optional swap chain associated with this drawing context.</param>
         /// <param name="finishedCallback">An optional delegate to be called when context is disposed.</param>
         public DrawingContextImpl(
             IVisualBrushRenderer visualBrushRenderer,
             SharpDX.Direct2D1.RenderTarget renderTarget,
             SharpDX.DirectWrite.Factory directWriteFactory,
+            SharpDX.WIC.ImagingFactory imagingFactory,
             SharpDX.DXGI.SwapChain1 swapChain = null,
             Action finishedCallback = null)
         {
@@ -46,6 +46,7 @@ namespace Avalonia.Direct2D1.Media
             _swapChain = swapChain;
             _finishedCallback = finishedCallback;
             _directWriteFactory = directWriteFactory;
+            _imagingFactory = imagingFactory;
             _swapChain = swapChain;
             _renderTarget.BeginDraw();
         }
@@ -97,7 +98,7 @@ namespace Avalonia.Direct2D1.Media
             using (var d2d = ((BitmapImpl)source).GetDirect2DBitmap(_renderTarget))
             {
                 _renderTarget.DrawBitmap(
-                    d2d,
+                    d2d.Value,
                     destRect.ToSharpDX(),
                     (float)opacity,
                     BitmapInterpolationMode.Linear,
@@ -115,7 +116,7 @@ namespace Avalonia.Direct2D1.Media
         public void DrawImage(IBitmapImpl source, IBrush opacityMask, Rect opacityMaskRect, Rect destRect)
         {
             using (var d2dSource = ((BitmapImpl)source).GetDirect2DBitmap(_renderTarget))
-            using (var sourceBrush = new BitmapBrush(_renderTarget, d2dSource))
+            using (var sourceBrush = new BitmapBrush(_renderTarget, d2dSource.Value))
             using (var d2dOpacityMask = CreateBrush(opacityMask, opacityMaskRect.Size))
             using (var geometry = new SharpDX.Direct2D1.RectangleGeometry(_renderTarget.Factory, destRect.ToDirect2D()))
             {
@@ -397,7 +398,7 @@ namespace Avalonia.Direct2D1.Media
                             return new ImageBrushImpl(
                                 visualBrush,
                                 _renderTarget,
-                                new D2DBitmapImpl(intermediate.Bitmap),
+                                new D2DBitmapImpl(_imagingFactory, intermediate.Bitmap),
                                 destinationSize);
                         }
                     }

+ 5 - 2
src/Windows/Avalonia.Direct2D1/Media/ImageBrushImpl.cs

@@ -10,6 +10,8 @@ namespace Avalonia.Direct2D1.Media
 {
     public sealed class ImageBrushImpl : BrushImpl
     {
+        OptionalDispose<Bitmap> _bitmap;
+
         public ImageBrushImpl(
             ITileBrush brush,
             SharpDX.Direct2D1.RenderTarget target,
@@ -20,9 +22,10 @@ namespace Avalonia.Direct2D1.Media
 
             if (!calc.NeedsIntermediate)
             {
+                _bitmap = bitmap.GetDirect2DBitmap(target);
                 PlatformBrush = new BitmapBrush(
                     target,
-                    bitmap.GetDirect2DBitmap(target),
+                    _bitmap.Value,
                     GetBitmapBrushProperties(brush),
                     GetBrushProperties(brush, calc.DestinationRect));
             }
@@ -41,7 +44,7 @@ namespace Avalonia.Direct2D1.Media
 
         public override void Dispose()
         {
-            ((BitmapBrush)PlatformBrush)?.Bitmap.Dispose();
+            _bitmap.Dispose();
             base.Dispose();
         }
 

+ 25 - 7
src/Windows/Avalonia.Direct2D1/Media/Imaging/BitmapImpl.cs

@@ -1,20 +1,38 @@
 using System;
-using System.Collections.Generic;
 using System.IO;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
 using Avalonia.Platform;
-using SharpDX.Direct2D1;
+using SharpDX.WIC;
+using D2DBitmap = SharpDX.Direct2D1.Bitmap;
 
 namespace Avalonia.Direct2D1.Media
 {
     public abstract class BitmapImpl : IBitmapImpl, IDisposable
     {
-        public abstract Bitmap GetDirect2DBitmap(SharpDX.Direct2D1.RenderTarget target);
+        public BitmapImpl(ImagingFactory imagingFactory)
+        {
+            WicImagingFactory = imagingFactory;
+        }
+
+        public ImagingFactory WicImagingFactory { get; }
         public abstract int PixelWidth { get; }
         public abstract int PixelHeight { get; }
-        public abstract void Save(string fileName);
+
+        public abstract OptionalDispose<D2DBitmap> GetDirect2DBitmap(SharpDX.Direct2D1.RenderTarget target);
+
+        public void Save(string fileName)
+        {
+            if (Path.GetExtension(fileName) != ".png")
+            {
+                // Yeah, we need to support other formats.
+                throw new NotSupportedException("Use PNG, stoopid.");
+            }
+
+            using (FileStream s = new FileStream(fileName, FileMode.Create))
+            {
+                Save(s);
+            }
+        }
+
         public abstract void Save(Stream stream);
 
         public virtual void Dispose()

+ 28 - 19
src/Windows/Avalonia.Direct2D1/Media/Imaging/D2DBitmapImpl.cs

@@ -1,11 +1,10 @@
 using System;
-using System.Collections.Generic;
 using System.IO;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using Avalonia.Platform;
 using SharpDX.Direct2D1;
+using WICFactory = SharpDX.WIC.ImagingFactory;
+using ImagingFactory2 = SharpDX.WIC.ImagingFactory2;
+using ImageParameters = SharpDX.WIC.ImageParameters;
+using PngBitmapEncoder = SharpDX.WIC.PngBitmapEncoder;
 
 namespace Avalonia.Direct2D1.Media
 {
@@ -26,32 +25,42 @@ namespace Avalonia.Direct2D1.Media
         /// or if the render target is a <see cref="SharpDX.Direct2D1.DeviceContext"/>,
         /// the device associated with this context, to be renderable.
         /// </remarks>
-        public D2DBitmapImpl(Bitmap d2DBitmap)
+        public D2DBitmapImpl(WICFactory imagingFactory, Bitmap d2DBitmap)
+            : base(imagingFactory)
         {
-            if (d2DBitmap == null) throw new ArgumentNullException(nameof(d2DBitmap));
-
-            _direct2D = d2DBitmap;
+            _direct2D = d2DBitmap ?? throw new ArgumentNullException(nameof(d2DBitmap));
         }
-
-        public override Bitmap GetDirect2DBitmap(SharpDX.Direct2D1.RenderTarget target) => _direct2D;
-               
+              
         public override int PixelWidth => _direct2D.PixelSize.Width;
         public override int PixelHeight => _direct2D.PixelSize.Height;
 
-        public override void Save(string fileName)
+        public override void Dispose()
         {
-            throw new NotImplementedException();
+            base.Dispose();
+            _direct2D.Dispose();
         }
 
-        public override void Save(Stream stream)
+        public override OptionalDispose<Bitmap> GetDirect2DBitmap(SharpDX.Direct2D1.RenderTarget target)
         {
-            throw new NotImplementedException();
+            return new OptionalDispose<Bitmap>(_direct2D, false);
         }
 
-        public override void Dispose()
+        public override void Save(Stream stream)
         {
-            base.Dispose();
-            _direct2D.Dispose();
+            using (var encoder = new PngBitmapEncoder(WicImagingFactory, stream))
+            using (var frameEncode = new SharpDX.WIC.BitmapFrameEncode(encoder))
+            using (var imageEncoder = new SharpDX.WIC.ImageEncoder((ImagingFactory2)WicImagingFactory, null))
+            {
+                var parameters = new ImageParameters(
+                    new PixelFormat(SharpDX.DXGI.Format.R8G8B8A8_UNorm, AlphaMode.Premultiplied),
+                    _direct2D.DotsPerInch.Width,
+                    _direct2D.DotsPerInch.Height,
+                    0, 0, PixelWidth, PixelHeight);
+
+                imageEncoder.WriteFrame(_direct2D, frameEncode, parameters);
+                frameEncode.Commit();
+                encoder.Commit();
+            }
         }
     }
 }

+ 68 - 0
src/Windows/Avalonia.Direct2D1/Media/Imaging/D2DRenderTargetBitmapImpl.cs

@@ -0,0 +1,68 @@
+using System;
+using Avalonia.Platform;
+using Avalonia.Rendering;
+using SharpDX;
+using SharpDX.Direct2D1;
+using SharpDX.WIC;
+using D2DBitmap = SharpDX.Direct2D1.Bitmap;
+using DirectWriteFactory = SharpDX.DirectWrite.Factory;
+
+namespace Avalonia.Direct2D1.Media.Imaging
+{
+    public class D2DRenderTargetBitmapImpl : D2DBitmapImpl, IRenderTargetBitmapImpl, ICreateLayer
+    {
+        private readonly DirectWriteFactory _dwriteFactory;
+        private readonly BitmapRenderTarget _target;
+
+        public D2DRenderTargetBitmapImpl(
+            ImagingFactory imagingFactory,
+            DirectWriteFactory dwriteFactory,
+            BitmapRenderTarget target)
+            : base(imagingFactory, target.Bitmap)
+        {
+            _dwriteFactory = dwriteFactory;
+            _target = target;
+        }
+
+        public override int PixelWidth => _target.PixelSize.Width;
+        public override int PixelHeight => _target.PixelSize.Height;
+
+        public static D2DRenderTargetBitmapImpl CreateCompatible(
+            ImagingFactory imagingFactory,
+            DirectWriteFactory dwriteFactory,
+            SharpDX.Direct2D1.RenderTarget renderTarget,
+            int pixelWidth,
+            int pixelHeight)
+        {
+            var bitmapRenderTarget = new BitmapRenderTarget(
+                renderTarget,
+                CompatibleRenderTargetOptions.None,
+                new Size2F(pixelWidth, pixelHeight));
+            return new D2DRenderTargetBitmapImpl(imagingFactory, dwriteFactory, bitmapRenderTarget);
+        }
+
+        public IDrawingContextImpl CreateDrawingContext(IVisualBrushRenderer visualBrushRenderer)
+        {
+            return new DrawingContextImpl(
+                visualBrushRenderer,
+                _target,
+                _dwriteFactory,
+                WicImagingFactory);
+        }
+
+        public IRenderTargetBitmapImpl CreateLayer(int pixelWidth, int pixelHeight)
+        {
+            return CreateCompatible(WicImagingFactory, _dwriteFactory, _target, pixelWidth, pixelHeight);
+        }
+
+        public override void Dispose()
+        {
+            _target.Dispose();
+        }
+
+        public override OptionalDispose<D2DBitmap> GetDirect2DBitmap(SharpDX.Direct2D1.RenderTarget target)
+        {
+            return new OptionalDispose<D2DBitmap>(_target.Bitmap, false);
+        }
+    }
+}

+ 17 - 40
src/Windows/Avalonia.Direct2D1/Media/Imaging/WicBitmapImpl.cs

@@ -3,11 +3,10 @@
 
 using System;
 using System.IO;
-using Avalonia.Platform;
 using Avalonia.Win32.Interop;
-using PixelFormat  = SharpDX.WIC.PixelFormat;
-using APixelFormat  = Avalonia.Platform.PixelFormat;
 using SharpDX.WIC;
+using APixelFormat = Avalonia.Platform.PixelFormat;
+using D2DBitmap = SharpDX.Direct2D1.Bitmap;
 
 namespace Avalonia.Direct2D1.Media
 {
@@ -16,18 +15,14 @@ namespace Avalonia.Direct2D1.Media
     /// </summary>
     public class WicBitmapImpl : BitmapImpl
     {
-        private readonly ImagingFactory _factory;
-        
-
         /// <summary>
         /// Initializes a new instance of the <see cref="WicBitmapImpl"/> class.
         /// </summary>
         /// <param name="factory">The WIC imaging factory to use.</param>
         /// <param name="fileName">The filename of the bitmap to load.</param>
         public WicBitmapImpl(ImagingFactory factory, string fileName)
+            : base(factory)
         {
-            _factory = factory;
-
             using (BitmapDecoder decoder = new BitmapDecoder(factory, fileName, DecodeOptions.CacheOnDemand))
             {
                 WicImpl = new Bitmap(factory, decoder.GetFrame(0), BitmapCreateCacheOption.CacheOnDemand);
@@ -40,9 +35,8 @@ namespace Avalonia.Direct2D1.Media
         /// <param name="factory">The WIC imaging factory to use.</param>
         /// <param name="stream">The stream to read the bitmap from.</param>
         public WicBitmapImpl(ImagingFactory factory, Stream stream)
+            : base(factory)
         {
-            _factory = factory;
-
             using (BitmapDecoder decoder = new BitmapDecoder(factory, stream, DecodeOptions.CacheOnLoad))
             {
                 WicImpl = new Bitmap(factory, decoder.GetFrame(0), BitmapCreateCacheOption.CacheOnLoad);
@@ -57,11 +51,11 @@ namespace Avalonia.Direct2D1.Media
         /// <param name="height">The height of the bitmap.</param>
         /// <param name="pixelFormat">Pixel format</param>
         public WicBitmapImpl(ImagingFactory factory, int width, int height, APixelFormat? pixelFormat = null)
+            : base(factory)
         {
             if (!pixelFormat.HasValue)
                 pixelFormat = APixelFormat.Bgra8888;
 
-            _factory = factory;
             PixelFormat = pixelFormat;
             WicImpl = new Bitmap(
                 factory,
@@ -71,7 +65,8 @@ namespace Avalonia.Direct2D1.Media
                 BitmapCreateCacheOption.CacheOnLoad);
         }
 
-        public WicBitmapImpl(ImagingFactory factory, Platform.PixelFormat format, IntPtr data, int width, int height, int stride)
+        public WicBitmapImpl(ImagingFactory factory, APixelFormat format, IntPtr data, int width, int height, int stride)
+            : base(factory)
         {
             WicImpl = new Bitmap(factory, width, height, format.ToWic(), BitmapCreateCacheOption.CacheOnDemand);
             PixelFormat = format;
@@ -112,41 +107,23 @@ namespace Avalonia.Direct2D1.Media
         /// </summary>
         /// <param name="renderTarget">The render target.</param>
         /// <returns>The Direct2D bitmap.</returns>
-        public override SharpDX.Direct2D1.Bitmap GetDirect2DBitmap(SharpDX.Direct2D1.RenderTarget renderTarget)
+        public override OptionalDispose<D2DBitmap> GetDirect2DBitmap(SharpDX.Direct2D1.RenderTarget renderTarget)
         {
-            FormatConverter converter = new FormatConverter(_factory);
+            FormatConverter converter = new FormatConverter(WicImagingFactory);
             converter.Initialize(WicImpl, SharpDX.WIC.PixelFormat.Format32bppPBGRA);
-            return SharpDX.Direct2D1.Bitmap.FromWicBitmap(renderTarget, converter);
+            return new OptionalDispose<D2DBitmap>(D2DBitmap.FromWicBitmap(renderTarget, converter), true);
         }
 
-        /// <summary>
-        /// Saves the bitmap to a file.
-        /// </summary>
-        /// <param name="fileName">The filename.</param>
-        public override void Save(string fileName)
+        public override void Save(Stream stream)
         {
-            if (Path.GetExtension(fileName) != ".png")
-            {
-                // Yeah, we need to support other formats.
-                throw new NotSupportedException("Use PNG, stoopid.");
-            }
-
-            using (FileStream s = new FileStream(fileName, FileMode.Create))
+            using (var encoder = new PngBitmapEncoder(WicImagingFactory, stream))
+            using (var frame = new BitmapFrameEncode(encoder))
             {
-                Save(s);
+                frame.Initialize();
+                frame.WriteSource(WicImpl);
+                frame.Commit();
+                encoder.Commit();
             }
         }
-
-        public override void Save(Stream stream)
-        {
-            PngBitmapEncoder encoder = new PngBitmapEncoder(_factory);
-            encoder.Initialize(stream);
-
-            BitmapFrameEncode frame = new BitmapFrameEncode(encoder);
-            frame.Initialize();
-            frame.WriteSource(WicImpl);
-            frame.Commit();
-            encoder.Commit();
-        }
     }
 }

+ 3 - 3
src/Windows/Avalonia.Direct2D1/Media/Imaging/RenderTargetBitmapImpl.cs → src/Windows/Avalonia.Direct2D1/Media/Imaging/WicRenderTargetBitmapImpl.cs

@@ -10,12 +10,12 @@ using DirectWriteFactory = SharpDX.DirectWrite.Factory;
 
 namespace Avalonia.Direct2D1.Media
 {
-    public class RenderTargetBitmapImpl : WicBitmapImpl, IRenderTargetBitmapImpl
+    public class WicRenderTargetBitmapImpl : WicBitmapImpl, IRenderTargetBitmapImpl
     {
         private readonly DirectWriteFactory _dwriteFactory;
         private readonly WicRenderTarget _target;
 
-        public RenderTargetBitmapImpl(
+        public WicRenderTargetBitmapImpl(
             ImagingFactory imagingFactory,
             Factory d2dFactory,
             DirectWriteFactory dwriteFactory,
@@ -47,7 +47,7 @@ namespace Avalonia.Direct2D1.Media
 
         public IDrawingContextImpl CreateDrawingContext(IVisualBrushRenderer visualBrushRenderer)
         {
-            return new DrawingContextImpl(visualBrushRenderer, _target, _dwriteFactory);
+            return new DrawingContextImpl(visualBrushRenderer, _target, _dwriteFactory, WicImagingFactory);
         }
     }
 }

+ 22 - 0
src/Windows/Avalonia.Direct2D1/OptionalDispose.cs

@@ -0,0 +1,22 @@
+using System;
+
+namespace Avalonia.Direct2D1
+{
+    public struct OptionalDispose<T> : IDisposable where T : IDisposable
+    {
+        private readonly bool _dispose;
+
+        public OptionalDispose(T value, bool dispose)
+        {
+            Value = value;
+            _dispose = dispose;
+        }
+
+        public T Value { get; }
+
+        public void Dispose()
+        {
+            if (_dispose) Value?.Dispose();
+        }
+    }
+}

+ 6 - 16
src/Windows/Avalonia.Direct2D1/RenderTarget.cs

@@ -7,6 +7,7 @@ using Avalonia.Platform;
 using Avalonia.Rendering;
 using SharpDX.Direct2D1;
 using DwFactory = SharpDX.DirectWrite.Factory;
+using WicFactory = SharpDX.WIC.ImagingFactory;
 
 namespace Avalonia.Direct2D1
 {
@@ -25,24 +26,13 @@ namespace Avalonia.Direct2D1
         {
             Direct2DFactory = AvaloniaLocator.Current.GetService<Factory>();
             DirectWriteFactory = AvaloniaLocator.Current.GetService<DwFactory>();
+            WicFactory = AvaloniaLocator.Current.GetService<WicFactory>();
             _renderTarget = renderTarget;
         }
 
-        /// <summary>
-        /// Gets the Direct2D factory.
-        /// </summary>
-        public Factory Direct2DFactory
-        {
-            get;
-        }
-
-        /// <summary>
-        /// Gets the DirectWrite factory.
-        /// </summary>
-        public DwFactory DirectWriteFactory
-        {
-            get;
-        }
+        public Factory Direct2DFactory { get; }
+        public DwFactory DirectWriteFactory { get; }
+        public WicFactory WicFactory { get; }
 
         /// <summary>
         /// Creates a drawing context for a rendering session.
@@ -50,7 +40,7 @@ namespace Avalonia.Direct2D1
         /// <returns>An <see cref="Avalonia.Platform.IDrawingContextImpl"/>.</returns>
         public IDrawingContextImpl CreateDrawingContext(IVisualBrushRenderer visualBrushRenderer)
         {
-            return new DrawingContextImpl(visualBrushRenderer, _renderTarget, DirectWriteFactory);
+            return new DrawingContextImpl(visualBrushRenderer, _renderTarget, DirectWriteFactory, WicFactory);
         }
 
         public void Dispose()

+ 22 - 18
src/Windows/Avalonia.Direct2D1/SwapChainRenderTarget.cs

@@ -10,10 +10,11 @@ using Factory = SharpDX.Direct2D1.Factory;
 using Factory2 = SharpDX.DXGI.Factory2;
 using Avalonia.Rendering;
 using Avalonia.Direct2D1.Media;
+using Avalonia.Direct2D1.Media.Imaging;
 
 namespace Avalonia.Direct2D1
 {
-    public abstract class SwapChainRenderTarget : IRenderTarget
+    public abstract class SwapChainRenderTarget : IRenderTarget, ICreateLayer
     {
         private Size2 _savedSize;
         private Size2F _savedDpi;
@@ -26,24 +27,12 @@ namespace Avalonia.Direct2D1
             D2DDevice = AvaloniaLocator.Current.GetService<Device>();
             Direct2DFactory = AvaloniaLocator.Current.GetService<Factory>();
             DirectWriteFactory = AvaloniaLocator.Current.GetService<SharpDX.DirectWrite.Factory>();
+            WicImagingFactory = AvaloniaLocator.Current.GetService<SharpDX.WIC.ImagingFactory>();
         }
 
-
-        /// <summary>
-        /// Gets the Direct2D factory.
-        /// </summary>
-        public Factory Direct2DFactory
-        {
-            get;
-        }
-
-        /// <summary>
-        /// Gets the DirectWrite factory.
-        /// </summary>
-        public SharpDX.DirectWrite.Factory DirectWriteFactory
-        {
-            get;
-        }
+        public Factory Direct2DFactory { get; }
+        public SharpDX.DirectWrite.Factory DirectWriteFactory { get; }
+        public SharpDX.WIC.ImagingFactory WicImagingFactory { get; }
 
         protected SharpDX.DXGI.Device DxgiDevice { get; }
         
@@ -69,9 +58,25 @@ namespace Avalonia.Direct2D1
                 visualBrushRenderer,
                 _deviceContext,
                 DirectWriteFactory,
+                WicImagingFactory,
                 _swapChain);
         }
 
+        public IRenderTargetBitmapImpl CreateLayer(int pixelWidth, int pixelHeight)
+        {
+            if (_deviceContext == null)
+            {
+                CreateSwapChain();
+            }
+
+            return D2DRenderTargetBitmapImpl.CreateCompatible(
+                WicImagingFactory,
+                DirectWriteFactory,
+                _deviceContext,
+                pixelWidth,
+                pixelHeight);
+        }
+
         public void Dispose()
         {
             _deviceContext?.Dispose();
@@ -86,7 +91,6 @@ namespace Avalonia.Direct2D1
                 _deviceContext?.Dispose();
                 _deviceContext = new DeviceContext(D2DDevice, DeviceContextOptions.None) {DotsPerInch = _savedDpi};
 
-
                 var swapChainDesc = new SwapChainDescription1
                 {
                     Width = _savedSize.Width,