diff --git a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs
index 2bb6f1dc7e..eededb2836 100644
--- a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs
+++ b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs
@@ -365,15 +365,7 @@ namespace Avalonia.Skia
SKRoundRect skRoundRect = null;
if (needRoundRect)
{
- skRoundRect = SKRoundRectCache.Shared.Get();
- skRoundRect.SetRectRadii(rc,
- new[]
- {
- rect.RadiiTopLeft.ToSKPoint(),
- rect.RadiiTopRight.ToSKPoint(),
- rect.RadiiBottomRight.ToSKPoint(),
- rect.RadiiBottomLeft.ToSKPoint(),
- });
+ skRoundRect = SKRoundRectCache.Shared.GetAndSetRadii(rc, rect);
}
foreach (var boxShadow in boxShadows)
@@ -389,8 +381,7 @@ namespace Avalonia.Skia
Canvas.Save();
if (isRounded)
{
- var shadowRect = SKRoundRectCache.Shared.Get();
- shadowRect.SetRectRadii(skRoundRect!.Rect, skRoundRect.Radii);
+ var shadowRect = SKRoundRectCache.Shared.GetAndSetRadii(skRoundRect!.Rect, skRoundRect.Radii);
if (spread != 0)
shadowRect.Inflate(spread, spread);
Canvas.ClipRoundRect(skRoundRect,
@@ -446,8 +437,7 @@ namespace Avalonia.Skia
var outerRect = AreaCastingShadowInHole(rc, (float)boxShadow.Blur, spread, offsetX, offsetY);
Canvas.Save();
- var shadowRect = SKRoundRectCache.Shared.Get();
- shadowRect.SetRectRadii(skRoundRect!.Rect, skRoundRect.Radii);
+ var shadowRect = SKRoundRectCache.Shared.GetAndSetRadii(skRoundRect!.Rect, skRoundRect.Radii);
if (spread != 0)
shadowRect.Deflate(spread, spread);
Canvas.ClipRoundRect(skRoundRect,
diff --git a/src/Skia/Avalonia.Skia/SKRoundRectCache.cs b/src/Skia/Avalonia.Skia/SKRoundRectCache.cs
index e164f97d6a..8de9e65553 100644
--- a/src/Skia/Avalonia.Skia/SKRoundRectCache.cs
+++ b/src/Skia/Avalonia.Skia/SKRoundRectCache.cs
@@ -1,13 +1,73 @@
-using System.Collections.Concurrent;
+using System.Buffers;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
using SkiaSharp;
namespace Avalonia.Skia
{
///
- /// Cache for SKPaints.
+ /// Cache for SKRoundRectCache.
///
internal class SKRoundRectCache : SKCacheBase
{
+ ///
+ /// Cache for points to use for setting the radii.
+ ///
+ private readonly ConcurrentBag _radiiCache = new();
+
+ ///
+ /// Gets a cached SKRoundRect and sets it with the passed rectangle and Radii.
+ ///
+ /// Rectangle size to set the cached rectangle to.
+ /// Rounded rectangle to copy the radii from.
+ /// Configured rounded rectangle
+ public SKRoundRect GetAndSetRadii(in SKRect rectangle, in RoundedRect roundedRect)
+ {
+ if (!Cache.TryTake(out var item))
+ {
+ item = new SKRoundRect();
+ }
+
+ // Try and acquire a cached point array.
+ if (!_radiiCache.TryTake(out var skArray))
+ {
+ skArray = new SKPoint[4];
+ }
+
+ skArray[0].X = (float)roundedRect.RadiiTopLeft.X;
+ skArray[0].Y = (float)roundedRect.RadiiTopLeft.Y;
+ skArray[1].X = (float)roundedRect.RadiiTopRight.X;
+ skArray[1].Y = (float)roundedRect.RadiiTopRight.Y;
+ skArray[2].X = (float)roundedRect.RadiiBottomRight.X;
+ skArray[2].Y = (float)roundedRect.RadiiBottomRight.Y;
+ skArray[3].X = (float)roundedRect.RadiiBottomLeft.X;
+ skArray[3].Y = (float)roundedRect.RadiiBottomLeft.Y;
+
+ item.SetRectRadii(rectangle, skArray);
+
+ // Add the array back to the cache.
+ _radiiCache.Add(skArray);
+
+ return item;
+ }
+
+ ///
+ /// Gets a cached SKRoundRect and sets it with the passed rectangle and Radii.
+ ///
+ /// Rectangle size to set the cached rectangle to.
+ /// point array of radii.
+ /// Configured rounded rectangle
+ public SKRoundRect GetAndSetRadii(in SKRect rectangle, in SKPoint[] radii)
+ {
+ if (!Cache.TryTake(out var item))
+ {
+ item = new SKRoundRect();
+ }
+
+ item.SetRectRadii(rectangle, radii);
+
+ return item;
+ }
///
/// Returns a SKPaint and resets it for reuse later.
///
@@ -22,5 +82,17 @@ namespace Avalonia.Skia
rect.SetEmpty();
Cache.Add(rect);
}
+
+ ///
+ /// Clears and disposes all cached items.
+ ///
+ public new void Clear()
+ {
+ base.Clear();
+
+ // Clear out the cache of SKPoint arrays.
+ _radiiCache.Clear();
+ }
+
}
}