Skip to content

Commit 4fdddc4

Browse files
committed
Added Blaze to some benchmarks
1 parent 2152cec commit 4fdddc4

File tree

5 files changed

+246
-5
lines changed

5 files changed

+246
-5
lines changed

ImageSharp.Drawing.sln

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{
337337
.github\workflows\build-and-test.yml = .github\workflows\build-and-test.yml
338338
EndProjectSection
339339
EndProject
340+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SharpBlaze", "..\SharpBlaze\SharpBlaze\SharpBlaze.csproj", "{FCEDD229-22BC-4B82-87DE-786BBFC52EDE}"
341+
EndProject
340342
Global
341343
GlobalSection(SolutionConfigurationPlatforms) = preSolution
342344
Debug|Any CPU = Debug|Any CPU
@@ -359,6 +361,10 @@ Global
359361
{5493F024-0A3F-420C-AC2D-05B77A36025B}.Debug|Any CPU.Build.0 = Debug|Any CPU
360362
{5493F024-0A3F-420C-AC2D-05B77A36025B}.Release|Any CPU.ActiveCfg = Release|Any CPU
361363
{5493F024-0A3F-420C-AC2D-05B77A36025B}.Release|Any CPU.Build.0 = Release|Any CPU
364+
{FCEDD229-22BC-4B82-87DE-786BBFC52EDE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
365+
{FCEDD229-22BC-4B82-87DE-786BBFC52EDE}.Debug|Any CPU.Build.0 = Debug|Any CPU
366+
{FCEDD229-22BC-4B82-87DE-786BBFC52EDE}.Release|Any CPU.ActiveCfg = Release|Any CPU
367+
{FCEDD229-22BC-4B82-87DE-786BBFC52EDE}.Release|Any CPU.Build.0 = Release|Any CPU
362368
EndGlobalSection
363369
GlobalSection(SolutionProperties) = preSolution
364370
HideSolutionNode = FALSE

tests/ImageSharp.Drawing.Benchmarks/Drawing/DrawPolygon.cs

Lines changed: 139 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,18 @@
44
using System.Drawing;
55
using System.Drawing.Drawing2D;
66
using System.Numerics;
7+
using System.Runtime.InteropServices;
78
using BenchmarkDotNet.Attributes;
89
using GeoJSON.Net.Feature;
910
using Newtonsoft.Json;
11+
using SharpBlaze;
1012
using SixLabors.ImageSharp.Drawing.Processing;
13+
using SixLabors.ImageSharp.Drawing.Shapes.PolygonClipper;
1114
using SixLabors.ImageSharp.Drawing.Tests;
1215
using SixLabors.ImageSharp.PixelFormats;
1316
using SixLabors.ImageSharp.Processing;
1417
using SkiaSharp;
18+
using BlazeMatrix = SharpBlaze.Matrix;
1519
using SDPointF = System.Drawing.PointF;
1620

1721
namespace SixLabors.ImageSharp.Drawing.Benchmarks.Drawing;
@@ -21,13 +25,20 @@ public abstract class DrawPolygon
2125
private PointF[][] points;
2226

2327
private Image<Rgba32> image;
28+
private bool isImageSharp;
2429

2530
private SDPointF[][] sdPoints;
2631
private Bitmap sdBitmap;
2732
private Graphics sdGraphics;
33+
private bool isSystem;
2834

2935
private SKPath skPath;
3036
private SKSurface skSurface;
37+
private bool isSkia;
38+
39+
private Executor executor;
40+
private DestinationImage<TileDescriptor_8x16> vecDst;
41+
private bool isBlaze;
3142

3243
protected abstract int Width { get; }
3344

@@ -49,9 +60,11 @@ public void Setup()
4960
this.sdPoints = this.points.Select(pts => pts.Select(p => new SDPointF(p.X, p.Y)).ToArray()).ToArray();
5061

5162
this.skPath = new SKPath();
63+
5264
foreach (PointF[] ptArr in this.points.Where(pts => pts.Length > 2))
5365
{
5466
this.skPath.MoveTo(ptArr[0].X, ptArr[1].Y);
67+
5568
for (int i = 1; i < ptArr.Length; i++)
5669
{
5770
this.skPath.LineTo(ptArr[i].X, ptArr[i].Y);
@@ -60,6 +73,11 @@ public void Setup()
6073
this.skPath.LineTo(ptArr[0].X, ptArr[1].Y);
6174
}
6275

76+
this.executor = new SerialExecutor();
77+
this.vecDst = new DestinationImage<TileDescriptor_8x16>();
78+
this.vecDst.UpdateSize(new IntSize(this.Width, this.Height));
79+
this.vecDst.ClearImage();
80+
6381
this.image = new Image<Rgba32>(this.Width, this.Height);
6482
this.sdBitmap = new Bitmap(this.Width, this.Height);
6583
this.sdGraphics = Graphics.FromImage(this.sdBitmap);
@@ -69,8 +87,44 @@ public void Setup()
6987
}
7088

7189
[GlobalCleanup]
72-
public void Cleanup()
90+
public unsafe void Cleanup()
7391
{
92+
string dir = "Images/DrawPolygon";
93+
Directory.CreateDirectory(dir);
94+
95+
if (this.isImageSharp)
96+
{
97+
this.image.SaveAsPng(System.IO.Path.Combine(dir, "ImageSharp.png"));
98+
this.isImageSharp = false;
99+
}
100+
101+
if (this.isBlaze)
102+
{
103+
using var blazeImage = Image.WrapMemory<Rgba32>(
104+
this.vecDst.GetImageData(),
105+
this.vecDst.GetBytesPerRow() * this.vecDst.GetImageHeight(),
106+
this.vecDst.GetImageWidth(),
107+
this.vecDst.GetImageHeight());
108+
109+
blazeImage.SaveAsPng(System.IO.Path.Combine(dir, "Blaze.png"));
110+
this.isBlaze = false;
111+
}
112+
113+
if (this.isSystem)
114+
{
115+
this.sdBitmap.Save(System.IO.Path.Combine(dir, "SystemDrawing.png"));
116+
this.isSystem = false;
117+
}
118+
119+
if (this.isSkia)
120+
{
121+
using var skSnapshot = this.skSurface.Snapshot();
122+
using var skEncoded = skSnapshot.Encode();
123+
using var skFile = new FileStream(System.IO.Path.Combine(dir, "SkiaSharp.png"), FileMode.Create);
124+
skEncoded.SaveTo(skFile);
125+
this.isSkia = false;
126+
}
127+
74128
this.image.Dispose();
75129
this.sdGraphics.Dispose();
76130
this.sdBitmap.Dispose();
@@ -87,18 +141,23 @@ public void SystemDrawing()
87141
{
88142
this.sdGraphics.DrawPolygon(pen, loop);
89143
}
144+
145+
this.isSystem = true;
90146
}
91147

92148
[Benchmark]
93149
public void ImageSharp()
94-
=> this.image.Mutate(
150+
{
151+
this.image.Mutate(
95152
c =>
96153
{
97154
foreach (PointF[] loop in this.points)
98155
{
99156
c.DrawPolygon(Color.White, this.Thickness, loop);
100157
}
101158
});
159+
this.isImageSharp = true;
160+
}
102161

103162
[Benchmark(Baseline = true)]
104163
public void SkiaSharp()
@@ -112,6 +171,84 @@ public void SkiaSharp()
112171
};
113172

114173
this.skSurface.Canvas.DrawPath(this.skPath, paint);
174+
this.isSkia = true;
175+
}
176+
177+
[Benchmark]
178+
public void Blaze()
179+
{
180+
VectorImageBuilder builder = new();
181+
182+
foreach (PointF[] loop in this.points)
183+
{
184+
var loopPolygon = new Polygon(loop);
185+
var brush = new Processing.SolidBrush(Color.White);
186+
var pen = new SolidPen(brush, this.Thickness);
187+
List<List<PointF>> outline = GenerateOutlineList(loopPolygon, pen.StrokeWidth, pen.JointStyle, pen.EndCapStyle);
188+
189+
foreach (List<PointF> line in outline)
190+
{
191+
Span<PointF> ptArr = CollectionsMarshal.AsSpan(line);
192+
193+
builder.MoveTo(new FloatPoint(ptArr[0].X, ptArr[1].Y));
194+
for (int i = 1; i < ptArr.Length; i++)
195+
{
196+
builder.LineTo(new FloatPoint(ptArr[i].X, ptArr[i].Y));
197+
}
198+
199+
builder.LineTo(new FloatPoint(ptArr[0].X, ptArr[1].Y));
200+
201+
builder.Close();
202+
}
203+
}
204+
205+
VectorImage image = builder.ToVectorImage(Color.White.ToPixel<Rgba32>().PackedValue);
206+
207+
this.vecDst.DrawImage(image, BlazeMatrix.Identity, this.executor);
208+
209+
this.isBlaze = true;
210+
}
211+
212+
private static List<List<PointF>> GenerateOutlineList(IPath path, float width, JointStyle jointStyle, EndCapStyle endCapStyle)
213+
{
214+
if (width <= 0)
215+
{
216+
return [];
217+
}
218+
219+
List<List<PointF>> stroked = [];
220+
221+
PolygonStroker stroker = new() { Width = width, LineJoin = GetLineJoin(jointStyle), LineCap = GetLineCap(endCapStyle) };
222+
foreach (ISimplePath simplePath in path.Flatten())
223+
{
224+
bool isClosed = simplePath.IsClosed || endCapStyle is EndCapStyle.Polygon or EndCapStyle.Joined;
225+
if (simplePath is Path concretePath)
226+
{
227+
if (concretePath.LineSegments.Count == 1 && concretePath.LineSegments[0] is LinearLineSegment lineSegment)
228+
{
229+
stroked.Add(stroker.ProcessPath(lineSegment.Flatten().Span, isClosed));
230+
continue;
231+
}
232+
}
233+
234+
stroked.Add(stroker.ProcessPath(simplePath.Points.Span, isClosed));
235+
}
236+
237+
return stroked;
238+
239+
static LineJoin GetLineJoin(JointStyle value) => value switch
240+
{
241+
JointStyle.Square => LineJoin.BevelJoin,
242+
JointStyle.Round => LineJoin.RoundJoin,
243+
_ => LineJoin.MiterJoin,
244+
};
245+
246+
static LineCap GetLineCap(EndCapStyle value) => value switch
247+
{
248+
EndCapStyle.Round => LineCap.Round,
249+
EndCapStyle.Square => LineCap.Square,
250+
_ => LineCap.Butt,
251+
};
115252
}
116253
}
117254

tests/ImageSharp.Drawing.Benchmarks/Drawing/FillPolygon.cs

Lines changed: 78 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,13 @@
77
using BenchmarkDotNet.Attributes;
88
using GeoJSON.Net.Feature;
99
using Newtonsoft.Json;
10+
using SharpBlaze;
1011
using SixLabors.ImageSharp.Drawing.Processing;
1112
using SixLabors.ImageSharp.Drawing.Tests;
1213
using SixLabors.ImageSharp.PixelFormats;
1314
using SixLabors.ImageSharp.Processing;
1415
using SkiaSharp;
16+
using BlazeMatrix = SharpBlaze.Matrix;
1517
using SDBitmap = System.Drawing.Bitmap;
1618
using SDPointF = System.Drawing.PointF;
1719

@@ -25,10 +27,20 @@ public abstract class FillPolygon
2527
private List<SKPath> skPaths;
2628

2729
private Image<Rgba32> image;
30+
private bool isImageSharp;
31+
2832
private SDBitmap sdBitmap;
2933
private Graphics sdGraphics;
34+
private bool isSystem;
35+
3036
private SKBitmap skBitmap;
3137
private SKCanvas skCanvas;
38+
private bool isSkia;
39+
40+
private VectorImage vecImage;
41+
private Executor executor;
42+
private DestinationImage<TileDescriptor_8x16> vecDst;
43+
private bool isBlaze;
3244

3345
protected abstract int Width { get; }
3446

@@ -52,19 +64,34 @@ public void Setup()
5264
this.sdPoints = this.points.Select(pts => pts.Select(p => new SDPointF(p.X, p.Y)).ToArray()).ToArray();
5365

5466
this.skPaths = new List<SKPath>();
67+
68+
VectorImageBuilder vecImageBuilder = new();
69+
5570
foreach (PointF[] ptArr in this.points.Where(pts => pts.Length > 2))
5671
{
5772
var skPath = new SKPath();
5873
skPath.MoveTo(ptArr[0].X, ptArr[1].Y);
74+
vecImageBuilder.MoveTo(new FloatPoint(ptArr[0].X, ptArr[1].Y));
75+
5976
for (int i = 1; i < ptArr.Length; i++)
6077
{
6178
skPath.LineTo(ptArr[i].X, ptArr[i].Y);
79+
vecImageBuilder.LineTo(new FloatPoint(ptArr[i].X, ptArr[i].Y));
6280
}
6381

6482
skPath.LineTo(ptArr[0].X, ptArr[1].Y);
6583
this.skPaths.Add(skPath);
84+
85+
vecImageBuilder.LineTo(new FloatPoint(ptArr[0].X, ptArr[1].Y));
86+
vecImageBuilder.Close();
6687
}
6788

89+
this.vecImage = vecImageBuilder.ToVectorImage(Color.White.ToPixel<Rgba32>().PackedValue);
90+
this.executor = new SerialExecutor();
91+
this.vecDst = new DestinationImage<TileDescriptor_8x16>();
92+
this.vecDst.UpdateSize(new IntSize(this.Width, this.Height));
93+
this.vecDst.ClearImage();
94+
6895
this.image = new Image<Rgba32>(this.Width, this.Height);
6996
this.sdBitmap = new SDBitmap(this.Width, this.Height);
7097
this.sdGraphics = Graphics.FromImage(this.sdBitmap);
@@ -75,8 +102,42 @@ public void Setup()
75102
}
76103

77104
[GlobalCleanup]
78-
public void Cleanup()
105+
public unsafe void Cleanup()
79106
{
107+
string dir = "Images/FillPolygon";
108+
Directory.CreateDirectory(dir);
109+
110+
if (this.isImageSharp)
111+
{
112+
this.image.SaveAsPng(System.IO.Path.Combine(dir, "ImageSharp.png"));
113+
this.isImageSharp = false;
114+
}
115+
116+
if (this.isBlaze)
117+
{
118+
using var blazeImage = Image.WrapMemory<Rgba32>(
119+
this.vecDst.GetImageData(),
120+
this.vecDst.GetBytesPerRow() * this.vecDst.GetImageHeight(),
121+
this.vecDst.GetImageWidth(),
122+
this.vecDst.GetImageHeight());
123+
124+
blazeImage.SaveAsPng(System.IO.Path.Combine(dir, "Blaze.png"));
125+
this.isBlaze = false;
126+
}
127+
128+
if (this.isSystem)
129+
{
130+
this.sdBitmap.Save(System.IO.Path.Combine(dir, "SystemDrawing.png"));
131+
this.isSystem = false;
132+
}
133+
134+
if (this.isSkia)
135+
{
136+
using var skFile = new FileStream(System.IO.Path.Combine(dir, "SkiaSharp.png"), FileMode.Create);
137+
this.skBitmap.Encode(skFile, SKEncodedImageFormat.Png, 100);
138+
this.isSkia = false;
139+
}
140+
80141
this.image.Dispose();
81142
this.sdGraphics.Dispose();
82143
this.sdBitmap.Dispose();
@@ -97,18 +158,24 @@ public void SystemDrawing()
97158
{
98159
this.sdGraphics.FillPolygon(brush, loop);
99160
}
161+
162+
this.isSystem = true;
100163
}
101164

102165
[Benchmark]
103166
public void ImageSharp()
104-
=> this.image.Mutate(c =>
167+
{
168+
this.image.Mutate(c =>
105169
{
106170
foreach (Polygon polygon in this.polygons)
107171
{
108172
c.Fill(Color.White, polygon);
109173
}
110174
});
111175

176+
this.isImageSharp = true;
177+
}
178+
112179
[Benchmark(Baseline = true)]
113180
public void SkiaSharp()
114181
{
@@ -123,6 +190,15 @@ public void SkiaSharp()
123190
};
124191
this.skCanvas.DrawPath(path, paint);
125192
}
193+
194+
this.isSkia = true;
195+
}
196+
197+
[Benchmark]
198+
public void Blaze()
199+
{
200+
this.vecDst.DrawImage(this.vecImage, BlazeMatrix.Identity, this.executor);
201+
this.isBlaze = true;
126202
}
127203
}
128204

0 commit comments

Comments
 (0)