Browse Source

Introduce Version for writable bitmaps

Nikita Tsukanov 7 years ago
parent
commit
c18001b69d

+ 5 - 0
src/Avalonia.Visuals/Platform/IBitmapImpl.cs

@@ -20,6 +20,11 @@ namespace Avalonia.Platform
         /// Gets the height of the bitmap, in pixels.
         /// </summary>
         int PixelHeight { get; }
+        
+        /// <summary>
+        /// Version of the pixel data
+        /// </summary>
+        int Version { get; }
 
         /// <summary>
         /// Saves the bitmap to a file.

+ 7 - 2
src/Avalonia.Visuals/Rendering/SceneGraph/ImageNode.cs

@@ -30,6 +30,7 @@ namespace Avalonia.Rendering.SceneGraph
             SourceRect = sourceRect;
             DestRect = destRect;
             BitmapInterpolationMode = bitmapInterpolationMode;
+            SourceVersion = Source.Item.Version;
         }        
 
         /// <summary>
@@ -42,6 +43,11 @@ namespace Avalonia.Rendering.SceneGraph
         /// </summary>
         public IRef<IBitmapImpl> Source { get; }
 
+        /// <summary>
+        /// Source bitmap Version
+        /// </summary>
+        public int SourceVersion { get; }
+
         /// <summary>
         /// Gets the draw opacity.
         /// </summary>
@@ -83,6 +89,7 @@ namespace Avalonia.Rendering.SceneGraph
         {
             return transform == Transform &&
                 Equals(source.Item, Source.Item) &&
+                source.Item.Version == SourceVersion &&
                 opacity == Opacity &&
                 sourceRect == SourceRect &&
                 destRect == DestRect &&
@@ -92,8 +99,6 @@ namespace Avalonia.Rendering.SceneGraph
         /// <inheritdoc/>
         public override void Render(IDrawingContextImpl context)
         {
-            // TODO: Probably need to introduce some kind of locking mechanism in the case of
-            // WriteableBitmap.
             context.Transform = Transform;
             context.DrawImage(Source, Opacity, SourceRect, DestRect, BitmapInterpolationMode);
         }

+ 2 - 0
src/Skia/Avalonia.Skia/ImmutableBitmap.cs

@@ -65,6 +65,8 @@ namespace Avalonia.Skia
         /// <inheritdoc />
         public int PixelHeight { get; }
 
+        public int Version { get; } = 1;
+
         /// <inheritdoc />
         public void Dispose()
         {

+ 4 - 1
src/Skia/Avalonia.Skia/SurfaceRenderTarget.cs

@@ -3,6 +3,7 @@
 
 using System;
 using System.IO;
+using System.Reactive.Disposables;
 using Avalonia.Platform;
 using Avalonia.Rendering;
 using Avalonia.Skia.Helpers;
@@ -79,7 +80,7 @@ namespace Avalonia.Skia
                 GrContext = _grContext
             };
 
-            return new DrawingContextImpl(createInfo);
+            return new DrawingContextImpl(createInfo, Disposable.Create(() => Version++));
         }
 
         /// <inheritdoc />
@@ -88,6 +89,8 @@ namespace Avalonia.Skia
         /// <inheritdoc />
         public int PixelHeight { get; }
 
+        public int Version { get; private set; } = 1;
+
         /// <inheritdoc />
         public void Save(string fileName)
         {

+ 17 - 5
src/Skia/Avalonia.Skia/WriteableBitmapImpl.cs

@@ -3,6 +3,7 @@
 
 using System;
 using System.IO;
+using System.Threading;
 using Avalonia.Platform;
 using Avalonia.Skia.Helpers;
 using SkiaSharp;
@@ -16,6 +17,7 @@ namespace Avalonia.Skia
     {
         private static readonly SKBitmapReleaseDelegate s_releaseDelegate = ReleaseProc;
         private readonly SKBitmap _bitmap;
+        private readonly object _lock = new object();
 
         /// <summary>
         /// Create new writeable bitmap.
@@ -55,10 +57,13 @@ namespace Avalonia.Skia
         /// <inheritdoc />
         public int PixelHeight { get; }
 
+        public int Version { get; private set; } = 1;
+
         /// <inheritdoc />
         public void Draw(DrawingContextImpl context, SKRect sourceRect, SKRect destRect, SKPaint paint)
         {
-            context.Canvas.DrawBitmap(_bitmap, sourceRect, destRect, paint);
+            lock (_lock)
+                context.Canvas.DrawBitmap(_bitmap, sourceRect, destRect, paint);
         }
 
         /// <inheritdoc />
@@ -86,7 +91,7 @@ namespace Avalonia.Skia
         }
 
         /// <inheritdoc />
-        public ILockedFramebuffer Lock() => new BitmapFramebuffer(_bitmap);
+        public ILockedFramebuffer Lock() => new BitmapFramebuffer(this, _bitmap);
 
         /// <summary>
         /// Get snapshot as image.
@@ -94,7 +99,8 @@ namespace Avalonia.Skia
         /// <returns>Image snapshot.</returns>
         public SKImage GetSnapshot()
         {
-            return SKImage.FromPixels(_bitmap.Info, _bitmap.GetPixels(), _bitmap.RowBytes);
+            lock (_lock)
+                return SKImage.FromPixels(_bitmap.Info, _bitmap.GetPixels(), _bitmap.RowBytes);
         }
 
         /// <summary>
@@ -112,22 +118,28 @@ namespace Avalonia.Skia
         /// </summary>
         private class BitmapFramebuffer : ILockedFramebuffer
         {
+            private WriteableBitmapImpl _parent;
             private SKBitmap _bitmap;
 
             /// <summary>
             /// Create framebuffer from given bitmap.
             /// </summary>
             /// <param name="bitmap">Bitmap.</param>
-            public BitmapFramebuffer(SKBitmap bitmap)
+            public BitmapFramebuffer(WriteableBitmapImpl parent, SKBitmap bitmap)
             {
+                _parent = parent;
                 _bitmap = bitmap;
+                Monitor.Enter(parent._lock);
             }
 
             /// <inheritdoc />
             public void Dispose()
             {
                 _bitmap.NotifyPixelsChanged();
+                _parent.Version++;
+                Monitor.Exit(_parent._lock);
                 _bitmap = null;
+                _parent = null;
             }
             
             /// <inheritdoc />
@@ -149,4 +161,4 @@ namespace Avalonia.Skia
             public PixelFormat Format => _bitmap.ColorType.ToPixelFormat();
         }
     }
-}
+}

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

@@ -9,6 +9,7 @@ namespace Avalonia.Direct2D1.Media
     {
         public abstract int PixelWidth { get; }
         public abstract int PixelHeight { get; }
+        public int Version { get; protected set; } = 1;
 
         public abstract OptionalDispose<D2DBitmap> GetDirect2DBitmap(SharpDX.Direct2D1.RenderTarget target);
 

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

@@ -35,7 +35,7 @@ namespace Avalonia.Direct2D1.Media.Imaging
 
         public IDrawingContextImpl CreateDrawingContext(IVisualBrushRenderer visualBrushRenderer)
         {
-            return new DrawingContextImpl(visualBrushRenderer, this, _renderTarget);
+            return new DrawingContextImpl(visualBrushRenderer, this, _renderTarget, null, () => Version++);
         }
 
         public IRenderTargetBitmapImpl CreateLayer(Size size)

+ 5 - 1
src/Windows/Avalonia.Direct2D1/Media/Imaging/WicRenderTargetBitmapImpl.cs

@@ -44,7 +44,11 @@ namespace Avalonia.Direct2D1.Media
 
         public IDrawingContextImpl CreateDrawingContext(IVisualBrushRenderer visualBrushRenderer, Action finishedCallback)
         {
-            return new DrawingContextImpl(visualBrushRenderer, null, _renderTarget, finishedCallback: finishedCallback);
+            return new DrawingContextImpl(visualBrushRenderer, null, _renderTarget, finishedCallback: () =>
+                {
+                    Version++;
+                    finishedCallback?.Invoke();
+                });
         }
     }
 }

+ 6 - 2
src/Windows/Avalonia.Direct2D1/Media/Imaging/WriteableWicBitmapImpl.cs

@@ -17,11 +17,13 @@ namespace Avalonia.Direct2D1.Media.Imaging
 
         class LockedBitmap : ILockedFramebuffer
         {
+            private readonly WriteableWicBitmapImpl _parent;
             private readonly BitmapLock _lock;
             private readonly PixelFormat _format;
 
-            public LockedBitmap(BitmapLock l, PixelFormat format)
+            public LockedBitmap(WriteableWicBitmapImpl parent, BitmapLock l, PixelFormat format)
             {
+                _parent = parent;
                 _lock = l;
                 _format = format;
             }
@@ -30,6 +32,7 @@ namespace Avalonia.Direct2D1.Media.Imaging
             public void Dispose()
             {
                 _lock.Dispose();
+                _parent.Version++;
             }
 
             public IntPtr Address => _lock.Data.DataPointer;
@@ -41,6 +44,7 @@ namespace Avalonia.Direct2D1.Media.Imaging
 
         }
 
-        public ILockedFramebuffer Lock() => new LockedBitmap(WicImpl.Lock(BitmapLockFlags.Write), PixelFormat.Value);
+        public ILockedFramebuffer Lock() =>
+            new LockedBitmap(this, WicImpl.Lock(BitmapLockFlags.Write), PixelFormat.Value);
     }
 }