Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added SKImage field to WriteableBitmapImpl for improved drawing performance #17717

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 33 additions & 5 deletions src/Skia/Avalonia.Skia/WriteableBitmapImpl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using Avalonia.Platform;
using Avalonia.Platform.Internal;
using Avalonia.Skia.Helpers;
using Avalonia.Utilities;
using SkiaSharp;

namespace Avalonia.Skia
Expand All @@ -16,6 +17,8 @@ internal class WriteableBitmapImpl : IWriteableBitmapImpl, IDrawableBitmapImpl
{
private static readonly SKBitmapReleaseDelegate s_releaseDelegate = ReleaseProc;
private readonly SKBitmap _bitmap;
private readonly SKImage _image;
private readonly SKPixmap _pixmap;
private readonly object _lock = new();

/// <summary>
Expand All @@ -34,7 +37,10 @@ public WriteableBitmapImpl(Stream stream)
throw new ArgumentException("Unable to load bitmap from provided data");
}

PixelSize = new PixelSize(_bitmap.Width, _bitmap.Height);
var info = _bitmap.Info;
_pixmap = new SKPixmap(info, _bitmap.GetPixels(), info.RowBytes);
_image = SKImage.FromPixels(_pixmap, null);
PixelSize = new PixelSize(info.Width, info.Height);
Dpi = SkiaPlatform.DefaultDpi;
}
}
Expand Down Expand Up @@ -77,6 +83,8 @@ public WriteableBitmapImpl(Stream stream, int decodeSize, bool horizontal, Bitma
}

_bitmap = bmp;
_pixmap = new SKPixmap(info, _bitmap.GetPixels(), info.RowBytes);
_image = SKImage.FromPixels(_pixmap, null);

PixelSize = new PixelSize(bmp.Width, bmp.Height);
Dpi = SkiaPlatform.DefaultDpi;
Expand All @@ -102,10 +110,13 @@ public WriteableBitmapImpl(PixelSize size, Vector dpi, PixelFormat format, Alpha

var nfo = new SKImageInfo(size.Width, size.Height, colorType, alphaType);
var blob = new UnmanagedBlob(nfo.BytesSize);
var addr = blob.Address;

_bitmap.InstallPixels(nfo, blob.Address, nfo.RowBytes, s_releaseDelegate, blob);

_bitmap.InstallPixels(nfo, addr, nfo.RowBytes, s_releaseDelegate, blob);
_bitmap.Erase(SKColor.Empty);

_pixmap = new SKPixmap(nfo, addr, nfo.RowBytes);
_image = SKImage.FromPixels(_pixmap);
}

public Vector Dpi { get; }
Expand All @@ -119,13 +130,30 @@ public WriteableBitmapImpl(PixelSize size, Vector dpi, PixelFormat format, Alpha
public void Draw(DrawingContextImpl context, SKRect sourceRect, SKRect destRect, SKPaint paint)
{
lock (_lock)
context.Canvas.DrawBitmap(_bitmap, sourceRect, destRect, paint);
{
if (sourceRect == destRect &&
MathUtilities.IsZero(sourceRect.Left) &&
MathUtilities.IsZero(sourceRect.Top) &&
// I'm using Right and Bottom since they are effectively the Width
// and Height since Left and Top will be zero at this point
MathUtilities.AreClose(sourceRect.Right, PixelSize.Width) &&
MathUtilities.AreClose(sourceRect.Bottom, PixelSize.Height))
{
context.Canvas.DrawImage(_image, 0, 0, paint);
}
else
{
context.Canvas.DrawImage(_image, sourceRect, destRect, paint);
}
}
}

/// <inheritdoc />
public virtual void Dispose()
{
_bitmap.Dispose();
_pixmap.Dispose();
_image.Dispose();
}

/// <inheritdoc />
Expand Down
Loading