Skip to content

Commit 0da47ef

Browse files
committed
ThreadLocalBlenderBuffers<TPixel>
1 parent 4e9eb8f commit 0da47ef

8 files changed

Lines changed: 365 additions & 192 deletions

File tree

src/ImageSharp.Drawing/Processing/GradientBrush.cs

Lines changed: 6 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System.Buffers;
66
using System.Numerics;
77
using System.Threading;
8+
using SixLabors.ImageSharp.Drawing.Utilities;
89
using SixLabors.ImageSharp.Memory;
910
using SixLabors.ImageSharp.PixelFormats;
1011

@@ -59,7 +60,7 @@ internal abstract class GradientBrushApplicator<TPixel> : BrushApplicator<TPixel
5960

6061
private readonly int scalineWidth;
6162

62-
private readonly ThreadLocal<ThreadContextData> threadContextData;
63+
private readonly ThreadLocalBlenderBuffers<TPixel> blenderBuffers;
6364

6465
private bool isDisposed;
6566

@@ -85,9 +86,7 @@ protected GradientBrushApplicator(
8586
this.repetitionMode = repetitionMode;
8687
this.scalineWidth = target.Width;
8788
this.allocator = configuration.MemoryAllocator;
88-
this.threadContextData = new ThreadLocal<ThreadContextData>(
89-
() => new ThreadContextData(this.allocator, this.scalineWidth),
90-
true);
89+
this.blenderBuffers = new ThreadLocalBlenderBuffers<TPixel>(this.allocator, this.scalineWidth);
9190
}
9291

9392
internal TPixel this[int x, int y]
@@ -140,9 +139,8 @@ protected GradientBrushApplicator(
140139
/// <inheritdoc />
141140
public override void Apply(Span<float> scanline, int x, int y)
142141
{
143-
ThreadContextData contextData = this.threadContextData.Value;
144-
Span<float> amounts = contextData.AmountSpan.Slice(0, scanline.Length);
145-
Span<TPixel> overlays = contextData.OverlaySpan.Slice(0, scanline.Length);
142+
Span<float> amounts = this.blenderBuffers.AmountSpan.Slice(0, scanline.Length);
143+
Span<TPixel> overlays = this.blenderBuffers.OverlaySpan.Slice(0, scanline.Length);
146144
float blendPercentage = this.Options.BlendPercentage;
147145

148146
// TODO: Remove bounds checks.
@@ -193,12 +191,7 @@ protected override void Dispose(bool disposing)
193191

194192
if (disposing)
195193
{
196-
foreach (ThreadContextData data in this.threadContextData.Values)
197-
{
198-
data.Dispose();
199-
}
200-
201-
this.threadContextData.Dispose();
194+
this.blenderBuffers.Dispose();
202195
}
203196

204197
this.isDisposed = true;
@@ -225,33 +218,6 @@ protected override void Dispose(bool disposing)
225218

226219
return (localGradientFrom, localGradientTo);
227220
}
228-
229-
private sealed class ThreadContextData : IDisposable
230-
{
231-
private bool isDisposed;
232-
private readonly IMemoryOwner<float> amountBuffer;
233-
private readonly IMemoryOwner<TPixel> overlayBuffer;
234-
235-
public ThreadContextData(MemoryAllocator allocator, int scanlineLength)
236-
{
237-
this.amountBuffer = allocator.Allocate<float>(scanlineLength);
238-
this.overlayBuffer = allocator.Allocate<TPixel>(scanlineLength);
239-
}
240-
241-
public Span<float> AmountSpan => this.amountBuffer.Memory.Span;
242-
243-
public Span<TPixel> OverlaySpan => this.overlayBuffer.Memory.Span;
244-
245-
public void Dispose()
246-
{
247-
if (!this.isDisposed)
248-
{
249-
this.isDisposed = true;
250-
this.amountBuffer.Dispose();
251-
this.overlayBuffer.Dispose();
252-
}
253-
}
254-
}
255221
}
256222
}
257223
}

src/ImageSharp.Drawing/Processing/PathGradientBrush.cs

Lines changed: 5 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ private sealed class PathGradientBrushApplicator<TPixel> : BrushApplicator<TPixe
189189

190190
private readonly TPixel transparentPixel;
191191

192-
private readonly ThreadLocal<ThreadContextData> threadContextData;
192+
private ThreadLocalBlenderBuffers<TPixel> blenderBuffers;
193193

194194
private bool isDisposed;
195195

@@ -220,9 +220,7 @@ public PathGradientBrushApplicator(
220220
this.centerPixel = centerColor.ToPixel<TPixel>();
221221
this.maxDistance = points.Select(p => (Vector2)(p - this.center)).Max(d => d.Length());
222222
this.transparentPixel = Color.Transparent.ToPixel<TPixel>();
223-
this.threadContextData = new ThreadLocal<ThreadContextData>(
224-
() => new ThreadContextData(configuration.MemoryAllocator, source.Width),
225-
true);
223+
this.blenderBuffers = new ThreadLocalBlenderBuffers<TPixel>(configuration.MemoryAllocator, source.Width);
226224
}
227225

228226
internal TPixel this[int x, int y]
@@ -285,9 +283,8 @@ public PathGradientBrushApplicator(
285283
/// <inheritdoc />
286284
public override void Apply(Span<float> scanline, int x, int y)
287285
{
288-
ThreadContextData contextData = this.threadContextData.Value;
289-
Span<float> amounts = contextData.AmountSpan.Slice(0, scanline.Length);
290-
Span<TPixel> overlays = contextData.OverlaySpan.Slice(0, scanline.Length);
286+
Span<float> amounts = this.blenderBuffers.AmountSpan.Slice(0, scanline.Length);
287+
Span<TPixel> overlays = this.blenderBuffers.OverlaySpan.Slice(0, scanline.Length);
291288
float blendPercentage = this.Options.BlendPercentage;
292289

293290
// TODO: Remove bounds checks.
@@ -324,12 +321,7 @@ protected override void Dispose(bool disposing)
324321

325322
if (disposing)
326323
{
327-
foreach (ThreadContextData data in this.threadContextData.Values)
328-
{
329-
data.Dispose();
330-
}
331-
332-
this.threadContextData.Dispose();
324+
this.blenderBuffers.Dispose();
333325
}
334326

335327
this.isDisposed = true;
@@ -394,33 +386,6 @@ private static bool FindPointOnTriangle(Vector2 v1, Vector2 v2, Vector2 v3, Vect
394386
v = ((d00 * d21) - (d01 * d20)) / denominator;
395387
return true;
396388
}
397-
398-
private sealed class ThreadContextData : IDisposable
399-
{
400-
private bool isDisposed;
401-
private readonly IMemoryOwner<float> amountBuffer;
402-
private readonly IMemoryOwner<TPixel> overlayBuffer;
403-
404-
public ThreadContextData(MemoryAllocator allocator, int scanlineLength)
405-
{
406-
this.amountBuffer = allocator.Allocate<float>(scanlineLength);
407-
this.overlayBuffer = allocator.Allocate<TPixel>(scanlineLength);
408-
}
409-
410-
public Span<float> AmountSpan => this.amountBuffer.Memory.Span;
411-
412-
public Span<TPixel> OverlaySpan => this.overlayBuffer.Memory.Span;
413-
414-
public void Dispose()
415-
{
416-
if (!this.isDisposed)
417-
{
418-
this.isDisposed = true;
419-
this.amountBuffer.Dispose();
420-
this.overlayBuffer.Dispose();
421-
}
422-
}
423-
}
424389
}
425390
}
426391
}

src/ImageSharp.Drawing/Processing/PatternBrush.cs

Lines changed: 5 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ private sealed class PatternBrushApplicator<TPixel> : BrushApplicator<TPixel>
111111
private readonly DenseMatrix<TPixel> pattern;
112112
private readonly MemoryAllocator allocator;
113113
private readonly int scalineWidth;
114-
private readonly ThreadLocal<ThreadContextData> threadContextData;
114+
private readonly ThreadLocalBlenderBuffers<TPixel> blenderBuffers;
115115
private bool isDisposed;
116116

117117
/// <summary>
@@ -131,9 +131,7 @@ public PatternBrushApplicator(
131131
this.pattern = pattern;
132132
this.scalineWidth = source.Width;
133133
this.allocator = configuration.MemoryAllocator;
134-
this.threadContextData = new ThreadLocal<ThreadContextData>(
135-
() => new ThreadContextData(this.allocator, this.scalineWidth),
136-
true);
134+
this.blenderBuffers = new ThreadLocalBlenderBuffers<TPixel>(configuration.MemoryAllocator, source.Width);
137135
}
138136

139137
internal TPixel this[int x, int y]
@@ -152,9 +150,8 @@ public PatternBrushApplicator(
152150
public override void Apply(Span<float> scanline, int x, int y)
153151
{
154152
int patternY = y % this.pattern.Rows;
155-
ThreadContextData contextData = this.threadContextData.Value;
156-
Span<float> amounts = contextData.AmountSpan.Slice(0, scanline.Length);
157-
Span<TPixel> overlays = contextData.OverlaySpan.Slice(0, scanline.Length);
153+
Span<float> amounts = this.blenderBuffers.AmountSpan.Slice(0, scanline.Length);
154+
Span<TPixel> overlays = this.blenderBuffers.OverlaySpan.Slice(0, scanline.Length);
158155

159156
for (int i = 0; i < scanline.Length; i++)
160157
{
@@ -185,43 +182,11 @@ protected override void Dispose(bool disposing)
185182

186183
if (disposing)
187184
{
188-
foreach (ThreadContextData data in this.threadContextData.Values)
189-
{
190-
data.Dispose();
191-
}
192-
193-
this.threadContextData.Dispose();
185+
this.blenderBuffers.Dispose();
194186
}
195187

196188
this.isDisposed = true;
197189
}
198-
199-
private sealed class ThreadContextData : IDisposable
200-
{
201-
private bool isDisposed;
202-
private readonly IMemoryOwner<float> amountBuffer;
203-
private readonly IMemoryOwner<TPixel> overlayBuffer;
204-
205-
public ThreadContextData(MemoryAllocator allocator, int scanlineLength)
206-
{
207-
this.amountBuffer = allocator.Allocate<float>(scanlineLength);
208-
this.overlayBuffer = allocator.Allocate<TPixel>(scanlineLength);
209-
}
210-
211-
public Span<float> AmountSpan => this.amountBuffer.Memory.Span;
212-
213-
public Span<TPixel> OverlaySpan => this.overlayBuffer.Memory.Span;
214-
215-
public void Dispose()
216-
{
217-
if (!this.isDisposed)
218-
{
219-
this.isDisposed = true;
220-
this.amountBuffer.Dispose();
221-
this.overlayBuffer.Dispose();
222-
}
223-
}
224-
}
225190
}
226191
}
227192
}

src/ImageSharp.Drawing/Processing/RecolorBrush.cs

Lines changed: 6 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System.Buffers;
66
using System.Numerics;
77
using System.Threading;
8+
using SixLabors.ImageSharp.Drawing.Utilities;
89
using SixLabors.ImageSharp.Memory;
910
using SixLabors.ImageSharp.PixelFormats;
1011

@@ -70,7 +71,7 @@ private class RecolorBrushApplicator<TPixel> : BrushApplicator<TPixel>
7071
private readonly TPixel targetColorPixel;
7172
private readonly MemoryAllocator allocator;
7273
private readonly int scalineWidth;
73-
private readonly ThreadLocal<ThreadContextData> threadContextData;
74+
private readonly ThreadLocalBlenderBuffers<TPixel> blenderBuffers;
7475
private bool isDisposed;
7576

7677
/// <summary>
@@ -103,9 +104,7 @@ public RecolorBrushApplicator(
103104

104105
this.scalineWidth = source.Width;
105106
this.allocator = configuration.MemoryAllocator;
106-
this.threadContextData = new ThreadLocal<ThreadContextData>(
107-
() => new ThreadContextData(this.allocator, this.scalineWidth),
108-
true);
107+
this.blenderBuffers = new ThreadLocalBlenderBuffers<TPixel>(configuration.MemoryAllocator, source.Width);
109108
}
110109

111110
internal TPixel this[int x, int y]
@@ -132,9 +131,8 @@ public RecolorBrushApplicator(
132131
/// <inheritdoc />
133132
public override void Apply(Span<float> scanline, int x, int y)
134133
{
135-
ThreadContextData contextData = this.threadContextData.Value;
136-
Span<float> amounts = contextData.AmountSpan.Slice(0, scanline.Length);
137-
Span<TPixel> overlays = contextData.OverlaySpan.Slice(0, scanline.Length);
134+
Span<float> amounts = this.blenderBuffers.AmountSpan.Slice(0, scanline.Length);
135+
Span<TPixel> overlays = this.blenderBuffers.OverlaySpan.Slice(0, scanline.Length);
138136

139137
for (int i = 0; i < scanline.Length; i++)
140138
{
@@ -168,43 +166,11 @@ protected override void Dispose(bool disposing)
168166

169167
if (disposing)
170168
{
171-
foreach (ThreadContextData data in this.threadContextData.Values)
172-
{
173-
data.Dispose();
174-
}
175-
176-
this.threadContextData.Dispose();
169+
this.blenderBuffers.Dispose();
177170
}
178171

179172
this.isDisposed = true;
180173
}
181-
182-
private sealed class ThreadContextData : IDisposable
183-
{
184-
private bool isDisposed;
185-
private readonly IMemoryOwner<float> amountBuffer;
186-
private readonly IMemoryOwner<TPixel> overlayBuffer;
187-
188-
public ThreadContextData(MemoryAllocator allocator, int scanlineLength)
189-
{
190-
this.amountBuffer = allocator.Allocate<float>(scanlineLength);
191-
this.overlayBuffer = allocator.Allocate<TPixel>(scanlineLength);
192-
}
193-
194-
public Span<float> AmountSpan => this.amountBuffer.Memory.Span;
195-
196-
public Span<TPixel> OverlaySpan => this.overlayBuffer.Memory.Span;
197-
198-
public void Dispose()
199-
{
200-
if (!this.isDisposed)
201-
{
202-
this.isDisposed = true;
203-
this.amountBuffer.Dispose();
204-
this.overlayBuffer.Dispose();
205-
}
206-
}
207-
}
208174
}
209175
}
210176
}

0 commit comments

Comments
 (0)