From ead6ac81b13c4e6e81749094c83705c6e1580f38 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Tue, 11 Feb 2025 04:03:50 +0500 Subject: [PATCH] [SKIA] Don't re-create SKImage on every WriteableBitmap draw call (#18164) --- src/Skia/Avalonia.Skia/WriteableBitmapImpl.cs | 27 ++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/src/Skia/Avalonia.Skia/WriteableBitmapImpl.cs b/src/Skia/Avalonia.Skia/WriteableBitmapImpl.cs index 865bcae99c..313c7e06de 100644 --- a/src/Skia/Avalonia.Skia/WriteableBitmapImpl.cs +++ b/src/Skia/Avalonia.Skia/WriteableBitmapImpl.cs @@ -15,7 +15,9 @@ namespace Avalonia.Skia internal class WriteableBitmapImpl : IWriteableBitmapImpl, IDrawableBitmapImpl { private static readonly SKBitmapReleaseDelegate s_releaseDelegate = ReleaseProc; - private readonly SKBitmap _bitmap; + private SKBitmap _bitmap; + private SKImage? _image; + private bool _imageValid; private readonly object _lock = new(); /// @@ -119,13 +121,31 @@ namespace Avalonia.Skia public void Draw(DrawingContextImpl context, SKRect sourceRect, SKRect destRect, SKPaint paint) { lock (_lock) - context.Canvas.DrawBitmap(_bitmap, sourceRect, destRect, paint); + { + if (_image == null || !_imageValid) + { + _image?.Dispose(); + _image = null; + // NOTE: this does a snapshot of the bitmap. If SKCanvas is not GPU-backed we might want to avoid + // that by force-sharing the pixel data with SKBitmap, but that would require manual pixel + // buffer management + _image = GetSnapshot(); + _imageValid = true; + } + context.Canvas.DrawImage(_image, sourceRect, destRect, paint); + } } /// public virtual void Dispose() { - _bitmap.Dispose(); + lock (_lock) + { + _image?.Dispose(); + _image = null; + _bitmap.Dispose(); + _bitmap = null!; + } } /// @@ -198,6 +218,7 @@ namespace Avalonia.Skia { _bitmap.NotifyPixelsChanged(); _parent.Version++; + _parent._imageValid = false; Monitor.Exit(_parent._lock); _bitmap = null!; _parent = null!;