Skip to content

Commit ed7c042

Browse files
Remove old scanner/rasterizer
1 parent 815b1e6 commit ed7c042

31 files changed

+1801
-3502
lines changed
Lines changed: 6 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
// Copyright (c) Six Labors.
22
// Licensed under the Six Labors Split License.
33

4-
using System;
54
using SixLabors.ImageSharp.Drawing.Shapes.Rasterization;
65
using SixLabors.ImageSharp.Memory;
76

@@ -10,22 +9,14 @@ namespace SixLabors.ImageSharp.Drawing.Processing.Backends;
109
/// <summary>
1110
/// Default CPU drawing backend.
1211
/// </summary>
13-
/// <remarks>
14-
/// This backend currently dispatches to the existing scanline rasterizer pipeline.
15-
/// A tiled rasterizer path is wired behind an AppContext switch for incremental rollout.
16-
/// </remarks>
1712
internal sealed class CpuDrawingBackend : IDrawingBackend
1813
{
19-
private const string ExperimentalTiledRasterizerSwitch = "SixLabors.ImageSharp.Drawing.ExperimentalTiledRasterizer";
14+
private readonly IRasterizer primaryRasterizer;
2015

21-
private readonly IRasterizer defaultRasterizer;
22-
private readonly TiledRasterizer tiledRasterizer;
23-
24-
private CpuDrawingBackend(IRasterizer defaultRasterizer)
16+
private CpuDrawingBackend(IRasterizer primaryRasterizer)
2517
{
26-
Guard.NotNull(defaultRasterizer, nameof(defaultRasterizer));
27-
this.defaultRasterizer = defaultRasterizer;
28-
this.tiledRasterizer = TiledRasterizer.Instance;
18+
Guard.NotNull(primaryRasterizer, nameof(primaryRasterizer));
19+
this.primaryRasterizer = primaryRasterizer;
2920
}
3021

3122
/// <summary>
@@ -36,7 +27,7 @@ private CpuDrawingBackend(IRasterizer defaultRasterizer)
3627
/// <summary>
3728
/// Gets the primary rasterizer used by this backend.
3829
/// </summary>
39-
public IRasterizer PrimaryRasterizer => this.defaultRasterizer;
30+
public IRasterizer PrimaryRasterizer => this.primaryRasterizer;
4031

4132
/// <summary>
4233
/// Creates a backend that uses the given rasterizer as the primary implementation.
@@ -57,16 +48,5 @@ public void RasterizePath<TState>(
5748
ref TState state,
5849
RasterizerScanlineHandler<TState> scanlineHandler)
5950
where TState : struct
60-
{
61-
if (UseExperimentalTiledRasterizer())
62-
{
63-
this.tiledRasterizer.Rasterize(path, options, allocator, ref state, scanlineHandler);
64-
return;
65-
}
66-
67-
this.defaultRasterizer.Rasterize(path, options, allocator, ref state, scanlineHandler);
68-
}
69-
70-
private static bool UseExperimentalTiledRasterizer()
71-
=> AppContext.TryGetSwitch(ExperimentalTiledRasterizerSwitch, out bool enabled) && enabled;
51+
=> this.primaryRasterizer.Rasterize(path, options, allocator, ref state, scanlineHandler);
7252
}

src/ImageSharp.Drawing/Processing/Processors/Drawing/FillPathProcessor.cs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,6 @@ namespace SixLabors.ImageSharp.Drawing.Processing.Processors.Drawing;
1111
/// </summary>
1212
public class FillPathProcessor : IImageProcessor
1313
{
14-
/// <summary>
15-
/// Fixed subpixel sampling density used by the CPU rasterizer for both antialiased and
16-
/// quantized-aliased rendering.
17-
/// </summary>
18-
internal const int FixedRasterizerSubpixelCount = 16;
19-
2014
/// <summary>
2115
/// Initializes a new instance of the <see cref="FillPathProcessor" /> class.
2216
/// </summary>

src/ImageSharp.Drawing/Processing/Processors/Drawing/FillPathProcessor{TPixel}.cs

Lines changed: 2 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -64,23 +64,20 @@ protected override void OnFrameApply(ImageFrame<TPixel> source)
6464

6565
int minX = interest.Left;
6666

67-
// The rasterizer always computes continuous coverage, then aliased mode quantizes coverage
68-
// in ProcessRasterizedScanline().
69-
int subpixelCount = FillPathProcessor.FixedRasterizerSubpixelCount;
7067
using BrushApplicator<TPixel> applicator = brush.CreateApplicator(configuration, graphicsOptions, source, this.bounds);
7168
MemoryAllocator allocator = this.Configuration.MemoryAllocator;
7269
IDrawingBackend drawingBackend = configuration.GetDrawingBackend();
70+
RasterizationMode rasterizationMode = graphicsOptions.Antialias ? RasterizationMode.Antialiased : RasterizationMode.Aliased;
7371
RasterizerOptions rasterizerOptions = new(
7472
interest,
75-
subpixelCount,
7673
shapeOptions.IntersectionRule,
74+
rasterizationMode,
7775
RasterizerSamplingOrigin.PixelBoundary);
7876

7977
RasterizationState state = new(
8078
source,
8179
applicator,
8280
minX,
83-
graphicsOptions.Antialias,
8481
isSolidBrushWithoutBlending,
8582
solidBrushColor);
8683

@@ -106,41 +103,6 @@ private static bool IsSolidBrushWithoutBlending(GraphicsOptions options, Brush i
106103

107104
private static void ProcessRasterizedScanline(int y, Span<float> scanline, ref RasterizationState state)
108105
{
109-
if (!state.Antialias)
110-
{
111-
bool hasOnes = false;
112-
bool hasZeros = false;
113-
for (int x = 0; x < scanline.Length; x++)
114-
{
115-
if (scanline[x] >= 0.5F)
116-
{
117-
scanline[x] = 1F;
118-
hasOnes = true;
119-
}
120-
else
121-
{
122-
scanline[x] = 0F;
123-
hasZeros = true;
124-
}
125-
}
126-
127-
if (state.IsSolidBrushWithoutBlending && hasOnes != hasZeros)
128-
{
129-
if (hasOnes)
130-
{
131-
state.Source.PixelBuffer.DangerousGetRowSpan(y).Slice(state.MinX, scanline.Length).Fill(state.SolidBrushColor);
132-
}
133-
134-
return;
135-
}
136-
137-
if (state.IsSolidBrushWithoutBlending && hasOnes)
138-
{
139-
FillOpaqueRuns(state.Source, y, state.MinX, scanline, state.SolidBrushColor);
140-
return;
141-
}
142-
}
143-
144106
if (state.IsSolidBrushWithoutBlending)
145107
{
146108
ApplyCoverageRunsForOpaqueSolidBrush(state.Source, state.Applicator, scanline, state.MinX, y, state.SolidBrushColor);
@@ -236,46 +198,18 @@ private static void ApplyCoverageRunsForOpaqueSolidBrush(
236198
}
237199
}
238200

239-
private static void FillOpaqueRuns(ImageFrame<TPixel> source, int y, int minX, Span<float> scanline, TPixel solidBrushColor)
240-
{
241-
Span<TPixel> destinationRow = source.PixelBuffer.DangerousGetRowSpan(y).Slice(minX, scanline.Length);
242-
int i = 0;
243-
244-
while (i < scanline.Length)
245-
{
246-
while (i < scanline.Length && scanline[i] <= 0F)
247-
{
248-
i++;
249-
}
250-
251-
int runStart = i;
252-
while (i < scanline.Length && scanline[i] > 0F)
253-
{
254-
i++;
255-
}
256-
257-
int runLength = i - runStart;
258-
if (runLength > 0)
259-
{
260-
destinationRow.Slice(runStart, runLength).Fill(solidBrushColor);
261-
}
262-
}
263-
}
264-
265201
private readonly struct RasterizationState
266202
{
267203
public RasterizationState(
268204
ImageFrame<TPixel> source,
269205
BrushApplicator<TPixel> applicator,
270206
int minX,
271-
bool antialias,
272207
bool isSolidBrushWithoutBlending,
273208
TPixel solidBrushColor)
274209
{
275210
this.Source = source;
276211
this.Applicator = applicator;
277212
this.MinX = minX;
278-
this.Antialias = antialias;
279213
this.IsSolidBrushWithoutBlending = isSolidBrushWithoutBlending;
280214
this.SolidBrushColor = solidBrushColor;
281215
}
@@ -286,8 +220,6 @@ public RasterizationState(
286220

287221
public int MinX { get; }
288222

289-
public bool Antialias { get; }
290-
291223
public bool IsSolidBrushWithoutBlending { get; }
292224

293225
public TPixel SolidBrushColor { get; }

src/ImageSharp.Drawing/Processing/Processors/Text/RichTextGlyphRenderer.cs

Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -541,19 +541,17 @@ private Buffer2D<float> Render(IPath path)
541541
// Pad to prevent edge clipping.
542542
size += new Size(2, 2);
543543

544-
// Use one coverage rasterization path for both AA and aliased text.
545-
// Aliased mode quantizes coverage in ProcessTextScanline().
546-
int subpixelCount = FillPathProcessor.FixedRasterizerSubpixelCount;
547544
RasterizerSamplingOrigin samplingOrigin = RasterizerSamplingOrigin.PixelBoundary;
548545
GraphicsOptions graphicsOptions = this.drawingOptions.GraphicsOptions;
546+
RasterizationMode rasterizationMode = graphicsOptions.Antialias ? RasterizationMode.Antialiased : RasterizationMode.Aliased;
549547

550548
// Take the path inside the path builder, scan thing and generate a Buffer2D representing the glyph.
551549
Buffer2D<float> buffer = this.memoryAllocator.Allocate2D<float>(size.Width, size.Height, AllocationOptions.Clean);
552-
TextRasterizationState state = new(buffer, graphicsOptions.Antialias);
550+
TextRasterizationState state = new(buffer);
553551
RasterizerOptions rasterizerOptions = new(
554552
new Rectangle(0, 0, size.Width, size.Height),
555-
subpixelCount,
556553
TextUtilities.MapFillRule(this.currentFillRule),
554+
rasterizationMode,
557555
samplingOrigin);
558556

559557
this.drawingBackend.RasterizePath(
@@ -570,14 +568,6 @@ private static void ProcessTextScanline(int y, Span<float> scanline, ref TextRas
570568
{
571569
Span<float> destination = state.Buffer.DangerousGetRowSpan(y);
572570
scanline.CopyTo(destination);
573-
574-
if (!state.Antialias)
575-
{
576-
for (int x = 0; x < destination.Length; x++)
577-
{
578-
destination[x] = destination[x] >= 0.5F ? 1F : 0F;
579-
}
580-
}
581571
}
582572

583573
private void Dispose(bool disposing)
@@ -625,15 +615,9 @@ public readonly void Dispose()
625615

626616
private readonly struct TextRasterizationState
627617
{
628-
public TextRasterizationState(Buffer2D<float> buffer, bool antialias)
629-
{
630-
this.Buffer = buffer;
631-
this.Antialias = antialias;
632-
}
618+
public TextRasterizationState(Buffer2D<float> buffer) => this.Buffer = buffer;
633619

634620
public Buffer2D<float> Buffer { get; }
635-
636-
public bool Antialias { get; }
637621
}
638622

639623
private readonly struct CacheKey : IEquatable<CacheKey>

src/ImageSharp.Drawing/Shapes/ComplexPolygon.cs

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -117,10 +117,7 @@ public IPath AsClosedPath()
117117
/// <inheritdoc/>
118118
SegmentInfo IPathInternals.PointAlongPath(float distance)
119119
{
120-
if (this.internalPaths == null)
121-
{
122-
this.InitInternalPaths();
123-
}
120+
this.EnsureInternalPaths();
124121

125122
distance %= this.length;
126123
foreach (InternalPath p in this.internalPaths)
@@ -141,17 +138,29 @@ SegmentInfo IPathInternals.PointAlongPath(float distance)
141138
/// <inheritdoc/>
142139
IReadOnlyList<InternalPath> IInternalPathOwner.GetRingsAsInternalPath()
143140
{
144-
this.InitInternalPaths();
141+
this.EnsureInternalPaths();
145142
return this.internalPaths;
146143
}
147144

145+
[MemberNotNull(nameof(internalPaths))]
146+
private void EnsureInternalPaths()
147+
{
148+
if (this.internalPaths is not null)
149+
{
150+
return;
151+
}
152+
153+
this.InitInternalPaths();
154+
}
155+
148156
/// <summary>
149157
/// Initializes <see cref="internalPaths"/> and <see cref="length"/>.
150158
/// </summary>
151159
[MemberNotNull(nameof(internalPaths))]
152160
private void InitInternalPaths()
153161
{
154162
this.internalPaths = new List<InternalPath>(this.paths.Length);
163+
this.length = 0;
155164

156165
foreach (IPath p in this.paths)
157166
{

src/ImageSharp.Drawing/Shapes/IInternalPathOwner.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,5 @@ internal interface IInternalPathOwner
1313
/// Returns the rings as a readonly collection of <see cref="InternalPath"/> elements.
1414
/// </summary>
1515
/// <returns>The <see cref="IReadOnlyList{T}"/>.</returns>
16-
IReadOnlyList<InternalPath> GetRingsAsInternalPath();
16+
public IReadOnlyList<InternalPath> GetRingsAsInternalPath();
1717
}

src/ImageSharp.Drawing/Shapes/Path.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ public class Path : IPath, ISimplePath, IPathInternals, IInternalPathOwner
1515
{
1616
private readonly ILineSegment[] lineSegments;
1717
private InternalPath? innerPath;
18+
private IReadOnlyList<InternalPath>? internalPathRings;
1819

1920
/// <summary>
2021
/// Initializes a new instance of the <see cref="Path"/> class.
@@ -131,7 +132,8 @@ SegmentInfo IPathInternals.PointAlongPath(float distance)
131132
=> this.InnerPath.PointAlongPath(distance);
132133

133134
/// <inheritdoc/>
134-
IReadOnlyList<InternalPath> IInternalPathOwner.GetRingsAsInternalPath() => [this.InnerPath];
135+
IReadOnlyList<InternalPath> IInternalPathOwner.GetRingsAsInternalPath()
136+
=> this.internalPathRings ??= [this.InnerPath];
135137

136138
/// <summary>
137139
/// Converts an SVG path string into an <see cref="IPath"/>.

0 commit comments

Comments
 (0)