From 72f766e5d6c72ea0637694365ece8391686d52ff Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Tue, 14 Nov 2017 17:27:03 +0300 Subject: [PATCH] Ref-counting infrastructure for bitmaps --- src/Avalonia.Base/Utilities/Ref.cs | 143 ++++++++++++++++++ src/Avalonia.Controls/WindowIcon.cs | 2 +- src/Avalonia.Visuals/Media/Imaging/Bitmap.cs | 41 +++-- src/Avalonia.Visuals/Media/Imaging/IBitmap.cs | 6 +- .../Media/Imaging/RenderTargetBitmap.cs | 16 +- .../Media/Imaging/WritableBitmap.cs | 5 +- src/Avalonia.Visuals/Platform/IBitmapImpl.cs | 3 +- .../Platform/IDrawingContextImpl.cs | 5 +- .../Rendering/DeferredRenderer.cs | 21 +-- src/Avalonia.Visuals/Rendering/RenderLayer.cs | 9 +- .../SceneGraph/DeferredDrawingContextImpl.cs | 5 +- .../Rendering/SceneGraph/ImageNode.cs | 18 ++- src/Skia/Avalonia.Skia/DrawingContextImpl.cs | 13 +- .../Media/DrawingContextImpl.cs | 9 +- .../Media/ImageBrushImpl.cs | 4 +- 15 files changed, 241 insertions(+), 59 deletions(-) create mode 100644 src/Avalonia.Base/Utilities/Ref.cs diff --git a/src/Avalonia.Base/Utilities/Ref.cs b/src/Avalonia.Base/Utilities/Ref.cs new file mode 100644 index 0000000000..eb73488bd0 --- /dev/null +++ b/src/Avalonia.Base/Utilities/Ref.cs @@ -0,0 +1,143 @@ +using System; +using System.Runtime.ConstrainedExecution; +using System.Threading; + +namespace Avalonia.Utilities +{ + public interface IRef : IDisposable where T : class + { + T Item { get; } + IRef Clone(); + IRef CloneAs() where TResult : class; + } + + + + public static class RefCountable + { + public static IRef Create(T item) where T : class, IDisposable + { + return new Ref(item, new RefCounter(item)); + } + + public static IRef CreateUnownedNotClonable(T item) where T : class + => new TempRef(item); + + class TempRef : IRef where T : class + { + public void Dispose() + { + + } + + public TempRef(T item) + { + Item = item; + } + + public T Item { get; } + public IRef Clone() => throw new NotSupportedException(); + + public IRef CloneAs() where TResult : class + => throw new NotSupportedException(); + } + + class RefCounter + { + private IDisposable _item; + private volatile int _refs; + private object _lock = new object(); + + public RefCounter(IDisposable item) + { + _item = item; + } + + public void AddRef() + { + Interlocked.Increment(ref _refs); + } + + public void Release() + { + if (Interlocked.Decrement(ref _refs) == 0) + { + lock (_lock) + { + _item?.Dispose(); + _item = null; + } + } + + } + } + + class Ref : CriticalFinalizerObject, IRef where T : class + { + private T _item; + private RefCounter _counter; + private object _lock = new object(); + + public Ref(T item, RefCounter counter) + { + _item = item; + _counter = counter; + Thread.MemoryBarrier(); + _counter.AddRef(); + } + + public void Dispose() + { + lock (_lock) + { + if (_item != null) + { + _counter.Release(); + _item = null; + } + GC.SuppressFinalize(this); + } + } + + ~Ref() + { + _counter?.Release(); + } + + public T Item + { + get + { + lock (_lock) + { + return _item; + } + } + } + + public IRef Clone() + { + lock (_lock) + { + if (_item != null) + return new Ref(_item, _counter); + throw new ObjectDisposedException("Ref<" + typeof(T) + ">"); + } + } + + public IRef CloneAs() where TResult : class + { + lock (_lock) + { + lock (_lock) + { + if (_item != null) + return new Ref((TResult) (object) _item, _counter); + throw new ObjectDisposedException("Ref<" + typeof(T) + ">"); + } + } + } + } + } + +} \ No newline at end of file diff --git a/src/Avalonia.Controls/WindowIcon.cs b/src/Avalonia.Controls/WindowIcon.cs index dff84ff6ef..26195e6d76 100644 --- a/src/Avalonia.Controls/WindowIcon.cs +++ b/src/Avalonia.Controls/WindowIcon.cs @@ -16,7 +16,7 @@ namespace Avalonia.Controls { public WindowIcon(IBitmap bitmap) { - PlatformImpl = AvaloniaLocator.Current.GetService().LoadIcon(bitmap.PlatformImpl); + PlatformImpl = AvaloniaLocator.Current.GetService().LoadIcon(bitmap.PlatformImpl.Item); } public WindowIcon(string fileName) diff --git a/src/Avalonia.Visuals/Media/Imaging/Bitmap.cs b/src/Avalonia.Visuals/Media/Imaging/Bitmap.cs index c9f7e0f7ac..892cd935cf 100644 --- a/src/Avalonia.Visuals/Media/Imaging/Bitmap.cs +++ b/src/Avalonia.Visuals/Media/Imaging/Bitmap.cs @@ -4,6 +4,7 @@ using System; using System.IO; using Avalonia.Platform; +using Avalonia.Utilities; namespace Avalonia.Media.Imaging { @@ -19,7 +20,7 @@ namespace Avalonia.Media.Imaging public Bitmap(string fileName) { IPlatformRenderInterface factory = AvaloniaLocator.Current.GetService(); - PlatformImpl = factory.LoadBitmap(fileName); + PlatformImpl = RefCountable.Create(factory.LoadBitmap(fileName)); } /// @@ -29,18 +30,33 @@ namespace Avalonia.Media.Imaging public Bitmap(Stream stream) { IPlatformRenderInterface factory = AvaloniaLocator.Current.GetService(); - PlatformImpl = factory.LoadBitmap(stream); + PlatformImpl = RefCountable.Create(factory.LoadBitmap(stream)); } /// /// Initializes a new instance of the class. /// /// A platform-specific bitmap implementation. + protected Bitmap(IRef impl) + { + PlatformImpl = impl.Clone(); + } + + /// + /// Initializes a new instance of the class. + /// + /// A platform-specific bitmap implementation. Bitmap class takes the ownership. protected Bitmap(IBitmapImpl impl) { - PlatformImpl = impl; + PlatformImpl = RefCountable.Create(impl); } - + + /// + public virtual void Dispose() + { + PlatformImpl.Dispose(); + } + /// /// Initializes a new instance of the class. /// @@ -51,27 +67,24 @@ namespace Avalonia.Media.Imaging /// Bytes per row public Bitmap(PixelFormat format, IntPtr data, int width, int height, int stride) { - PlatformImpl = AvaloniaLocator.Current.GetService() - .LoadBitmap(format, data, width, height, stride); + PlatformImpl = RefCountable.Create(AvaloniaLocator.Current.GetService() + .LoadBitmap(format, data, width, height, stride)); } /// /// Gets the width of the bitmap, in pixels. /// - public int PixelWidth => PlatformImpl.PixelWidth; + public int PixelWidth => PlatformImpl.Item.PixelWidth; /// /// Gets the height of the bitmap, in pixels. /// - public int PixelHeight => PlatformImpl.PixelHeight; + public int PixelHeight => PlatformImpl.Item.PixelHeight; /// /// Gets the platform-specific bitmap implementation. /// - public IBitmapImpl PlatformImpl - { - get; - } + public IRef PlatformImpl { get; } /// /// Saves the bitmap to a file. @@ -79,12 +92,12 @@ namespace Avalonia.Media.Imaging /// The filename. public void Save(string fileName) { - PlatformImpl.Save(fileName); + PlatformImpl.Item.Save(fileName); } public void Save(Stream stream) { - PlatformImpl.Save(stream); + PlatformImpl.Item.Save(stream); } } } diff --git a/src/Avalonia.Visuals/Media/Imaging/IBitmap.cs b/src/Avalonia.Visuals/Media/Imaging/IBitmap.cs index 5a10145d84..465173059e 100644 --- a/src/Avalonia.Visuals/Media/Imaging/IBitmap.cs +++ b/src/Avalonia.Visuals/Media/Imaging/IBitmap.cs @@ -1,15 +1,17 @@ // Copyright (c) The Avalonia Project. All rights reserved. // Licensed under the MIT license. See licence.md file in the project root for full license information. +using System; using System.IO; using Avalonia.Platform; +using Avalonia.Utilities; namespace Avalonia.Media.Imaging { /// /// Represents a bitmap image. /// - public interface IBitmap + public interface IBitmap : IDisposable { /// /// Gets the width of the bitmap, in pixels. @@ -24,7 +26,7 @@ namespace Avalonia.Media.Imaging /// /// Gets the platform-specific bitmap implementation. /// - IBitmapImpl PlatformImpl { get; } + IRef PlatformImpl { get; } /// /// Saves the bitmap to a file. diff --git a/src/Avalonia.Visuals/Media/Imaging/RenderTargetBitmap.cs b/src/Avalonia.Visuals/Media/Imaging/RenderTargetBitmap.cs index 9d3f15f69a..3968c05efb 100644 --- a/src/Avalonia.Visuals/Media/Imaging/RenderTargetBitmap.cs +++ b/src/Avalonia.Visuals/Media/Imaging/RenderTargetBitmap.cs @@ -2,8 +2,10 @@ // Licensed under the MIT license. See licence.md file in the project root for full license information. using System; +using System.Runtime.CompilerServices; using Avalonia.Platform; using Avalonia.Rendering; +using Avalonia.Utilities; using Avalonia.VisualTree; namespace Avalonia.Media.Imaging @@ -21,14 +23,19 @@ namespace Avalonia.Media.Imaging /// The horizontal DPI of the bitmap. /// The vertical DPI of the bitmap. public RenderTargetBitmap(int pixelWidth, int pixelHeight, double dpiX = 96, double dpiY = 96) - : base(CreateImpl(pixelWidth, pixelHeight, dpiX, dpiY)) + : this(RefCountable.Create(CreateImpl(pixelWidth, pixelHeight, dpiX, dpiY))) { } + private RenderTargetBitmap(IRef impl) : base(impl) + { + PlatformImpl = impl; + } + /// /// Gets the platform-specific bitmap implementation. /// - public new IRenderTargetBitmapImpl PlatformImpl => (IRenderTargetBitmapImpl)base.PlatformImpl; + public new IRef PlatformImpl { get; } /// /// Disposes of the bitmap. @@ -36,6 +43,7 @@ namespace Avalonia.Media.Imaging public void Dispose() { PlatformImpl.Dispose(); + base.Dispose(); } /// @@ -52,13 +60,13 @@ namespace Avalonia.Media.Imaging /// The horizontal DPI of the bitmap. /// The vertical DPI of the bitmap. /// The platform-specific implementation. - private static IBitmapImpl CreateImpl(int width, int height, double dpiX, double dpiY) + private static IRenderTargetBitmapImpl CreateImpl(int width, int height, double dpiX, double dpiY) { IPlatformRenderInterface factory = AvaloniaLocator.Current.GetService(); return factory.CreateRenderTargetBitmap(width, height, dpiX, dpiY); } /// - public IDrawingContextImpl CreateDrawingContext(IVisualBrushRenderer vbr) => PlatformImpl.CreateDrawingContext(vbr); + public IDrawingContextImpl CreateDrawingContext(IVisualBrushRenderer vbr) => PlatformImpl.Item.CreateDrawingContext(vbr); } } diff --git a/src/Avalonia.Visuals/Media/Imaging/WritableBitmap.cs b/src/Avalonia.Visuals/Media/Imaging/WritableBitmap.cs index 5c5b516ddd..df3e71dc85 100644 --- a/src/Avalonia.Visuals/Media/Imaging/WritableBitmap.cs +++ b/src/Avalonia.Visuals/Media/Imaging/WritableBitmap.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using Avalonia.Platform; +using Avalonia.Utilities; namespace Avalonia.Media.Imaging { @@ -16,7 +17,7 @@ namespace Avalonia.Media.Imaging : base(AvaloniaLocator.Current.GetService().CreateWritableBitmap(width, height, format)) { } - - public ILockedFramebuffer Lock() => ((IWritableBitmapImpl) PlatformImpl).Lock(); + + public ILockedFramebuffer Lock() => ((IWritableBitmapImpl) PlatformImpl.Item).Lock(); } } diff --git a/src/Avalonia.Visuals/Platform/IBitmapImpl.cs b/src/Avalonia.Visuals/Platform/IBitmapImpl.cs index 12ac28e880..d60838452e 100644 --- a/src/Avalonia.Visuals/Platform/IBitmapImpl.cs +++ b/src/Avalonia.Visuals/Platform/IBitmapImpl.cs @@ -1,6 +1,7 @@ // Copyright (c) The Avalonia Project. All rights reserved. // Licensed under the MIT license. See licence.md file in the project root for full license information. +using System; using System.IO; namespace Avalonia.Platform @@ -8,7 +9,7 @@ namespace Avalonia.Platform /// /// Defines the platform-specific interface for a . /// - public interface IBitmapImpl + public interface IBitmapImpl : IDisposable { /// /// Gets the width of the bitmap, in pixels. diff --git a/src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs b/src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs index 3db4527bfb..04bbe713f2 100644 --- a/src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs +++ b/src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs @@ -3,6 +3,7 @@ using System; using Avalonia.Media; +using Avalonia.Utilities; namespace Avalonia.Platform { @@ -29,7 +30,7 @@ namespace Avalonia.Platform /// The opacity to draw with. /// The rect in the image to draw. /// The rect in the output to draw to. - void DrawImage(IBitmapImpl source, double opacity, Rect sourceRect, Rect destRect); + void DrawImage(IRef source, double opacity, Rect sourceRect, Rect destRect); /// /// Draws a bitmap image. @@ -38,7 +39,7 @@ namespace Avalonia.Platform /// The opacity mask to draw with. /// The destination rect for the opacity mask. /// The rect in the output to draw to. - void DrawImage(IBitmapImpl source, IBrush opacityMask, Rect opacityMaskRect, Rect destRect); + void DrawImage(IRef source, IBrush opacityMask, Rect opacityMaskRect, Rect destRect); /// /// Draws a line. diff --git a/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs b/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs index f7befa646a..26b5244b00 100644 --- a/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs +++ b/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs @@ -12,6 +12,7 @@ using System.IO; using Avalonia.Media.Immutable; using System.Threading; using System.Linq; +using Avalonia.Utilities; namespace Avalonia.Rendering { @@ -31,7 +32,7 @@ namespace Avalonia.Rendering private Scene _scene; private IRenderTarget _renderTarget; private DirtyVisuals _dirty; - private IRenderTargetBitmapImpl _overlay; + private IRef _overlay; private bool _updateQueued; private object _rendering = new object(); private int _lastSceneId = -1; @@ -267,7 +268,7 @@ namespace Avalonia.Rendering if (node != null) { - using (var context = renderTarget.CreateDrawingContext(this)) + using (var context = renderTarget.Item.CreateDrawingContext(this)) { foreach (var rect in layer.Dirty) { @@ -294,7 +295,7 @@ namespace Avalonia.Rendering { var overlay = GetOverlay(parentContent, scene.Size, scene.Scaling); - using (var context = overlay.CreateDrawingContext(this)) + using (var context = overlay.Item.CreateDrawingContext(this)) { context.Clear(Colors.Transparent); RenderDirtyRects(context); @@ -323,7 +324,7 @@ namespace Avalonia.Rendering foreach (var layer in scene.Layers) { var bitmap = _layers[layer.LayerRoot].Bitmap; - var sourceRect = new Rect(0, 0, bitmap.PixelWidth, bitmap.PixelHeight); + var sourceRect = new Rect(0, 0, bitmap.Item.PixelWidth, bitmap.Item.PixelHeight); if (layer.GeometryClip != null) { @@ -347,7 +348,7 @@ namespace Avalonia.Rendering if (_overlay != null) { - var sourceRect = new Rect(0, 0, _overlay.PixelWidth, _overlay.PixelHeight); + var sourceRect = new Rect(0, 0, _overlay.Item.PixelWidth, _overlay.Item.PixelHeight); context.DrawImage(_overlay, 0.5, sourceRect, clientRect); } @@ -420,7 +421,7 @@ namespace Avalonia.Rendering } } - private IRenderTargetBitmapImpl GetOverlay( + private IRef GetOverlay( IDrawingContextImpl parentContext, Size size, double scaling) @@ -428,11 +429,11 @@ namespace Avalonia.Rendering var pixelSize = size * scaling; if (_overlay == null || - _overlay.PixelWidth != pixelSize.Width || - _overlay.PixelHeight != pixelSize.Height) + _overlay.Item.PixelWidth != pixelSize.Width || + _overlay.Item.PixelHeight != pixelSize.Height) { _overlay?.Dispose(); - _overlay = parentContext.CreateLayer(size); + _overlay = RefCountable.Create(parentContext.CreateLayer(size)); } return _overlay; @@ -445,7 +446,7 @@ namespace Avalonia.Rendering foreach (var layer in _layers) { var fileName = Path.Combine(DebugFramesPath, $"frame-{id}-layer-{index++}.png"); - layer.Bitmap.Save(fileName); + layer.Bitmap.Item.Save(fileName); } } } diff --git a/src/Avalonia.Visuals/Rendering/RenderLayer.cs b/src/Avalonia.Visuals/Rendering/RenderLayer.cs index ed33295db6..d1b1f1440a 100644 --- a/src/Avalonia.Visuals/Rendering/RenderLayer.cs +++ b/src/Avalonia.Visuals/Rendering/RenderLayer.cs @@ -1,6 +1,7 @@ using System; using Avalonia.Media; using Avalonia.Platform; +using Avalonia.Utilities; using Avalonia.VisualTree; namespace Avalonia.Rendering @@ -16,13 +17,13 @@ namespace Avalonia.Rendering IVisual layerRoot) { _drawingContext = drawingContext; - Bitmap = drawingContext.CreateLayer(size); + Bitmap = RefCountable.Create(drawingContext.CreateLayer(size)); Size = size; Scaling = scaling; LayerRoot = layerRoot; } - public IRenderTargetBitmapImpl Bitmap { get; private set; } + public IRef Bitmap { get; private set; } public double Scaling { get; private set; } public Size Size { get; private set; } public IVisual LayerRoot { get; } @@ -31,9 +32,9 @@ namespace Avalonia.Rendering { if (Size != size || Scaling != scaling) { - var resized = _drawingContext.CreateLayer(size); + var resized = RefCountable.Create(_drawingContext.CreateLayer(size)); - using (var context = resized.CreateDrawingContext(null)) + using (var context = resized.Item.CreateDrawingContext(null)) { context.Clear(Colors.Transparent); context.DrawImage(Bitmap, 1, new Rect(Size), new Rect(Size)); diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs index 29c482c336..38a10a7b7f 100644 --- a/src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs +++ b/src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using Avalonia.Media; using Avalonia.Platform; +using Avalonia.Utilities; using Avalonia.VisualTree; namespace Avalonia.Rendering.SceneGraph @@ -113,7 +114,7 @@ namespace Avalonia.Rendering.SceneGraph } /// - public void DrawImage(IBitmapImpl source, double opacity, Rect sourceRect, Rect destRect) + public void DrawImage(IRef source, double opacity, Rect sourceRect, Rect destRect) { var next = NextDrawAs(); @@ -128,7 +129,7 @@ namespace Avalonia.Rendering.SceneGraph } /// - public void DrawImage(IBitmapImpl source, IBrush opacityMask, Rect opacityMaskRect, Rect sourceRect) + public void DrawImage(IRef source, IBrush opacityMask, Rect opacityMaskRect, Rect sourceRect) { // This method is currently only used to composite layers so shouldn't be called here. throw new NotSupportedException(); diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/ImageNode.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/ImageNode.cs index 8291d1c0bb..8a1a5cb481 100644 --- a/src/Avalonia.Visuals/Rendering/SceneGraph/ImageNode.cs +++ b/src/Avalonia.Visuals/Rendering/SceneGraph/ImageNode.cs @@ -3,13 +3,14 @@ using System; using Avalonia.Platform; +using Avalonia.Utilities; namespace Avalonia.Rendering.SceneGraph { /// /// A node in the scene graph which represents an image draw. /// - internal class ImageNode : DrawOperation + internal class ImageNode : DrawOperation, IDisposable { /// /// Initializes a new instance of the class. @@ -19,11 +20,11 @@ namespace Avalonia.Rendering.SceneGraph /// The draw opacity. /// The source rect. /// The destination rect. - public ImageNode(Matrix transform, IBitmapImpl source, double opacity, Rect sourceRect, Rect destRect) + public ImageNode(Matrix transform, IRef source, double opacity, Rect sourceRect, Rect destRect) : base(destRect, transform, null) { Transform = transform; - Source = source; + Source = source.Clone(); Opacity = opacity; SourceRect = sourceRect; DestRect = destRect; @@ -37,7 +38,7 @@ namespace Avalonia.Rendering.SceneGraph /// /// Gets the image to draw. /// - public IBitmapImpl Source { get; } + public IRef Source { get; } /// /// Gets the draw opacity. @@ -67,10 +68,10 @@ namespace Avalonia.Rendering.SceneGraph /// The properties of the other draw operation are passed in as arguments to prevent /// allocation of a not-yet-constructed draw operation object. /// - public bool Equals(Matrix transform, IBitmapImpl source, double opacity, Rect sourceRect, Rect destRect) + public bool Equals(Matrix transform, IRef source, double opacity, Rect sourceRect, Rect destRect) { return transform == Transform && - Equals(source, Source) && + Equals(source.Item, Source.Item) && opacity == Opacity && sourceRect == SourceRect && destRect == DestRect; @@ -87,5 +88,10 @@ namespace Avalonia.Rendering.SceneGraph /// public override bool HitTest(Point p) => Bounds.Contains(p); + + public void Dispose() + { + Source?.Dispose(); + } } } diff --git a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs index dd3ced1d89..0bc133e9df 100644 --- a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs +++ b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs @@ -6,6 +6,7 @@ using System.Linq; using Avalonia.Platform; using Avalonia.Rendering; using Avalonia.Rendering.Utilities; +using Avalonia.Utilities; namespace Avalonia.Skia { @@ -39,9 +40,9 @@ namespace Avalonia.Skia Canvas.Clear(color.ToSKColor()); } - public void DrawImage(IBitmapImpl source, double opacity, Rect sourceRect, Rect destRect) + public void DrawImage(IRef source, double opacity, Rect sourceRect, Rect destRect) { - var impl = (BitmapImpl)source; + var impl = (BitmapImpl)source.Item; var s = sourceRect.ToSKRect(); var d = destRect.ToSKRect(); using (var paint = new SKPaint() @@ -51,10 +52,10 @@ namespace Avalonia.Skia } } - public void DrawImage(IBitmapImpl source, IBrush opacityMask, Rect opacityMaskRect, Rect destRect) + public void DrawImage(IRef source, IBrush opacityMask, Rect opacityMaskRect, Rect destRect) { PushOpacityMask(opacityMask, opacityMaskRect); - DrawImage(source, 1, new Rect(0, 0, source.PixelWidth, source.PixelHeight), destRect); + DrawImage(source, 1, new Rect(0, 0, source.Item.PixelWidth, source.Item.PixelHeight), destRect); PopOpacityMask(); } @@ -237,7 +238,7 @@ namespace Avalonia.Skia } else { - tileBrushImage = (BitmapImpl)((tileBrush as IImageBrush)?.Source?.PlatformImpl); + tileBrushImage = (BitmapImpl)((tileBrush as IImageBrush)?.Source?.PlatformImpl.Item); } if (tileBrush != null && tileBrushImage != null) @@ -252,7 +253,7 @@ namespace Avalonia.Skia context.Clear(Colors.Transparent); context.PushClip(calc.IntermediateClip); context.Transform = calc.IntermediateTransform; - context.DrawImage(tileBrushImage, 1, rect, rect); + context.DrawImage(RefCountable.CreateUnownedNotClonable(tileBrushImage), 1, rect, rect); context.PopClip(); } diff --git a/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs index 6a72923ce3..afbca14346 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using Avalonia.Media; using Avalonia.Platform; using Avalonia.Rendering; +using Avalonia.Utilities; using SharpDX; using SharpDX.Direct2D1; using SharpDX.Mathematics.Interop; @@ -100,9 +101,9 @@ namespace Avalonia.Direct2D1.Media /// The opacity to draw with. /// The rect in the image to draw. /// The rect in the output to draw to. - public void DrawImage(IBitmapImpl source, double opacity, Rect sourceRect, Rect destRect) + public void DrawImage(IRef source, double opacity, Rect sourceRect, Rect destRect) { - using (var d2d = ((BitmapImpl)source).GetDirect2DBitmap(_renderTarget)) + using (var d2d = ((BitmapImpl)source.Item).GetDirect2DBitmap(_renderTarget)) { _renderTarget.DrawBitmap( d2d.Value, @@ -120,9 +121,9 @@ namespace Avalonia.Direct2D1.Media /// The opacity mask to draw with. /// The destination rect for the opacity mask. /// The rect in the output to draw to. - public void DrawImage(IBitmapImpl source, IBrush opacityMask, Rect opacityMaskRect, Rect destRect) + public void DrawImage(IRef source, IBrush opacityMask, Rect opacityMaskRect, Rect destRect) { - using (var d2dSource = ((BitmapImpl)source).GetDirect2DBitmap(_renderTarget)) + using (var d2dSource = ((BitmapImpl)source.Item).GetDirect2DBitmap(_renderTarget)) 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())) diff --git a/src/Windows/Avalonia.Direct2D1/Media/ImageBrushImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/ImageBrushImpl.cs index 08cfed2ace..75b397edd6 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/ImageBrushImpl.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/ImageBrushImpl.cs @@ -4,6 +4,7 @@ using System; using Avalonia.Media; using Avalonia.Rendering.Utilities; +using Avalonia.Utilities; using SharpDX.Direct2D1; namespace Avalonia.Direct2D1.Media @@ -100,7 +101,8 @@ namespace Avalonia.Direct2D1.Media context.Clear(Colors.Transparent); context.PushClip(calc.IntermediateClip); context.Transform = calc.IntermediateTransform; - context.DrawImage(bitmap, 1, rect, rect); + + context.DrawImage(RefCountable.CreateUnownedNotClonable(bitmap), 1, rect, rect); context.PopClip(); }