Skip to content

Commit 2baeb2e

Browse files
mattleibowCopilot
andcommitted
Eliminate allocations in HatchBrush.CreatePaint
Replace SKBitmap + 64 SetPixel P/Invoke calls with: - stackalloc uint[64] for the pixel buffer (256 bytes on stack) - Single SKImage.FromPixelCopy bulk transfer - No managed heap allocations for the tile Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent e4abfd4 commit 2baeb2e

2 files changed

Lines changed: 17 additions & 6 deletions

File tree

source/SkiaSharp.Extended.Drawing.Common/SkiaSharp.Extended.Drawing.Common.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
<RootNamespace>System.Drawing</RootNamespace>
77
<LangVersion>12.0</LangVersion>
88
<Nullable>enable</Nullable>
9+
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
910
<AssemblyVersion>10.0.0.0</AssemblyVersion>
1011
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
1112
<NoWarn>CS1591;CS0109;CS0219;CS0414;CS0436;CS0618;CS0649;CS0672;CS1690;CS3021;CS8602;CS8604;CS8618;SYSLIB0051</NoWarn>

source/SkiaSharp.Extended.Drawing.Common/System/Drawing/Drawing2D/HatchBrush.cs

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -192,8 +192,8 @@ internal override SKPaint CreatePaint()
192192
{
193193
ThrowIfDisposed();
194194
var paint = new SKPaint { Style = SKPaintStyle.Fill, IsAntialias = false };
195-
var fg = SkiaConversions.ToSKColor(_foreColor);
196-
var bg = SkiaConversions.ToSKColor(_backColor);
195+
uint fg = (uint)SkiaConversions.ToSKColor(_foreColor);
196+
uint bg = (uint)SkiaConversions.ToSKColor(_backColor);
197197

198198
int index = (int)_hatchStyle;
199199
if (index < 0 || index > 52)
@@ -202,17 +202,27 @@ internal override SKPaint CreatePaint()
202202
var data = HatchPatternData;
203203
int offset = index * 8;
204204
const int tileSize = 8;
205-
using var tileBitmap = new SKBitmap(tileSize, tileSize);
206205

206+
// Build 64-pixel tile in a stack-friendly buffer, then copy into SKImage
207+
Span<uint> pixels = stackalloc uint[tileSize * tileSize];
207208
for (int y = 0; y < tileSize; y++)
208209
{
209210
byte row = data[offset + y];
211+
int rowOffset = y * tileSize;
210212
for (int x = 0; x < tileSize; x++)
211-
tileBitmap.SetPixel(x, y, (row & (0x80 >> x)) != 0 ? fg : bg);
213+
pixels[rowOffset + x] = (row & (0x80 >> x)) != 0 ? fg : bg;
212214
}
213215

214-
using var image = SKImage.FromBitmap(tileBitmap);
215-
paint.Shader = SKShader.CreateImage(image, SKShaderTileMode.Repeat, SKShaderTileMode.Repeat);
216+
var info = new SKImageInfo(tileSize, tileSize, SKColorType.Bgra8888, SKAlphaType.Premul);
217+
unsafe
218+
{
219+
fixed (uint* ptr = pixels)
220+
{
221+
using var pixmap = new SKPixmap(info, (IntPtr)ptr, tileSize * sizeof(uint));
222+
using var image = SKImage.FromPixelCopy(pixmap);
223+
paint.Shader = SKShader.CreateImage(image, SKShaderTileMode.Repeat, SKShaderTileMode.Repeat);
224+
}
225+
}
216226
return paint;
217227
}
218228
}

0 commit comments

Comments
 (0)