From 1321c7996e81d34f19fc6bf3704e09939960a076 Mon Sep 17 00:00:00 2001 From: Sebastian Hartte Date: Sun, 10 Jan 2021 10:39:46 +0100 Subject: [PATCH] Fix various Direct2D resource leak issues, as well as an unclosed geometry stream. --- .../Avalonia.Direct2D1/Media/DrawingContextImpl.cs | 12 +++++++++++- src/Windows/Avalonia.Direct2D1/Media/GeometryImpl.cs | 6 +++--- .../Media/Imaging/WicBitmapImpl.cs | 6 +++--- .../Avalonia.Direct2D1/Media/StreamGeometryImpl.cs | 9 ++++++--- .../Avalonia.Direct2D1/PrimitiveExtensions.cs | 2 +- 5 files changed, 24 insertions(+), 11 deletions(-) diff --git a/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs index 136ff63f3d..47a19aad8c 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs @@ -21,6 +21,7 @@ namespace Avalonia.Direct2D1.Media private readonly ILayerFactory _layerFactory; private readonly SharpDX.Direct2D1.RenderTarget _renderTarget; private readonly DeviceContext _deviceContext; + private readonly bool _ownsDeviceContext; private readonly SharpDX.DXGI.SwapChain1 _swapChain; private readonly Action _finishedCallback; @@ -51,10 +52,12 @@ namespace Avalonia.Direct2D1.Media if (_renderTarget is DeviceContext deviceContext) { _deviceContext = deviceContext; + _ownsDeviceContext = false; } else { _deviceContext = _renderTarget.QueryInterface(); + _ownsDeviceContext = true; } _deviceContext.BeginDraw(); @@ -96,6 +99,13 @@ namespace Avalonia.Direct2D1.Media { throw new RenderTargetCorruptedException(ex); } + finally + { + if (_ownsDeviceContext) + { + _deviceContext.Dispose(); + } + } } /// @@ -151,7 +161,7 @@ namespace Avalonia.Direct2D1.Media using (var d2dSource = ((BitmapImpl)source.Item).GetDirect2DBitmap(_deviceContext)) using (var sourceBrush = new BitmapBrush(_deviceContext, d2dSource.Value)) using (var d2dOpacityMask = CreateBrush(opacityMask, opacityMaskRect.Size)) - using (var geometry = new SharpDX.Direct2D1.RectangleGeometry(_deviceContext.Factory, destRect.ToDirect2D())) + using (var geometry = new SharpDX.Direct2D1.RectangleGeometry(Direct2D1Platform.Direct2D1Factory, destRect.ToDirect2D())) { if (d2dOpacityMask.PlatformBrush != null) { diff --git a/src/Windows/Avalonia.Direct2D1/Media/GeometryImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/GeometryImpl.cs index 636309ad1a..d04e2b3110 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/GeometryImpl.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/GeometryImpl.cs @@ -33,13 +33,13 @@ namespace Avalonia.Direct2D1.Media /// public IGeometryImpl Intersect(IGeometryImpl geometry) { - var result = new PathGeometry(Geometry.Factory); - + var result = new PathGeometry(Direct2D1Platform.Direct2D1Factory); using (var sink = result.Open()) { Geometry.Combine(((GeometryImpl)geometry).Geometry, CombineMode.Intersect, sink); - return new StreamGeometryImpl(result); + sink.Close(); } + return new StreamGeometryImpl(result); } /// diff --git a/src/Windows/Avalonia.Direct2D1/Media/Imaging/WicBitmapImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/Imaging/WicBitmapImpl.cs index 49193afd78..90592ea806 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/Imaging/WicBitmapImpl.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/Imaging/WicBitmapImpl.cs @@ -13,7 +13,7 @@ namespace Avalonia.Direct2D1.Media /// public class WicBitmapImpl : BitmapImpl { - private BitmapDecoder _decoder; + private readonly BitmapDecoder _decoder; private static BitmapInterpolationMode ConvertInterpolationMode(Avalonia.Visuals.Media.Imaging.BitmapInterpolationMode interpolationMode) { @@ -41,7 +41,7 @@ namespace Avalonia.Direct2D1.Media /// The filename of the bitmap to load. public WicBitmapImpl(string fileName) { - using (BitmapDecoder decoder = new BitmapDecoder(Direct2D1Platform.ImagingFactory, fileName, DecodeOptions.CacheOnDemand)) + using (var decoder = new BitmapDecoder(Direct2D1Platform.ImagingFactory, fileName, DecodeOptions.CacheOnDemand)) { WicImpl = new Bitmap(Direct2D1Platform.ImagingFactory, decoder.GetFrame(0), BitmapCreateCacheOption.CacheOnDemand); Dpi = new Vector(96, 96); @@ -177,7 +177,7 @@ namespace Avalonia.Direct2D1.Media /// The Direct2D bitmap. public override OptionalDispose GetDirect2DBitmap(SharpDX.Direct2D1.RenderTarget renderTarget) { - FormatConverter converter = new FormatConverter(Direct2D1Platform.ImagingFactory); + using var converter = new FormatConverter(Direct2D1Platform.ImagingFactory); converter.Initialize(WicImpl, SharpDX.WIC.PixelFormat.Format32bppPBGRA); return new OptionalDispose(D2DBitmap.FromWicBitmap(renderTarget, converter), true); } diff --git a/src/Windows/Avalonia.Direct2D1/Media/StreamGeometryImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/StreamGeometryImpl.cs index 9104be64b2..2bc2b2db71 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/StreamGeometryImpl.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/StreamGeometryImpl.cs @@ -29,9 +29,12 @@ namespace Avalonia.Direct2D1.Media public IStreamGeometryImpl Clone() { var result = new PathGeometry(Direct2D1Platform.Direct2D1Factory); - var sink = result.Open(); - ((PathGeometry)Geometry).Stream(sink); - sink.Close(); + using (var sink = result.Open()) + { + ((PathGeometry)Geometry).Stream(sink); + sink.Close(); + } + return new StreamGeometryImpl(result); } diff --git a/src/Windows/Avalonia.Direct2D1/PrimitiveExtensions.cs b/src/Windows/Avalonia.Direct2D1/PrimitiveExtensions.cs index 31e9c260e0..669e139d8f 100644 --- a/src/Windows/Avalonia.Direct2D1/PrimitiveExtensions.cs +++ b/src/Windows/Avalonia.Direct2D1/PrimitiveExtensions.cs @@ -111,7 +111,7 @@ namespace Avalonia.Direct2D1 /// The Direct2D brush. public static StrokeStyle ToDirect2DStrokeStyle(this Avalonia.Media.IPen pen, SharpDX.Direct2D1.RenderTarget renderTarget) { - return pen.ToDirect2DStrokeStyle(renderTarget.Factory); + return pen.ToDirect2DStrokeStyle(Direct2D1Platform.Direct2D1Factory); } ///