Skip to content

Commit f64e141

Browse files
Merge pull request #1035 from SixLabors/af/expose-buffer-internals
Expose Buffer2D and ParallelHelper internals
2 parents 826205d + fe09e10 commit f64e141

36 files changed

+273
-176
lines changed

src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
using System;
55

66
using SixLabors.ImageSharp.Advanced;
7-
using SixLabors.ImageSharp.ParallelUtils;
7+
using SixLabors.ImageSharp.Advanced.ParallelUtils;
88
using SixLabors.ImageSharp.PixelFormats;
99
using SixLabors.Primitives;
1010

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

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
using System.Buffers;
66

77
using SixLabors.ImageSharp.Advanced;
8+
using SixLabors.ImageSharp.Advanced.ParallelUtils;
89
using SixLabors.ImageSharp.Memory;
9-
using SixLabors.ImageSharp.ParallelUtils;
1010
using SixLabors.ImageSharp.PixelFormats;
1111
using SixLabors.Primitives;
1212

@@ -45,17 +45,18 @@ protected override void OnFrameApply(ImageFrame<TPixel> source)
4545

4646
int width = maxX - minX;
4747

48-
var workingRect = Rectangle.FromLTRB(minX, minY, maxX, maxY);
48+
Rectangle workingRect = Rectangle.FromLTRB(minX, minY, maxX, maxY);
4949

5050
IBrush brush = this.definition.Brush;
5151
GraphicsOptions options = this.definition.Options;
5252

5353
// If there's no reason for blending, then avoid it.
5454
if (this.IsSolidBrushWithoutBlending(out SolidBrush solidBrush))
5555
{
56-
ParallelExecutionSettings parallelSettings = configuration.GetParallelSettings().MultiplyMinimumPixelsPerTask(4);
56+
ParallelExecutionSettings parallelSettings = ParallelExecutionSettings.FromConfiguration(configuration)
57+
.MultiplyMinimumPixelsPerTask(4);
5758

58-
TPixel colorPixel = solidBrush.Color.ToPixel<TPixel>();
59+
var colorPixel = solidBrush.Color.ToPixel<TPixel>();
5960

6061
ParallelHelper.IterateRows(
6162
workingRect,

src/ImageSharp/Common/ParallelUtils/ParallelExecutionSettings.cs renamed to src/ImageSharp/Advanced/ParallelUtils/ParallelExecutionSettings.cs

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
// Copyright (c) Six Labors and contributors.
22
// Licensed under the Apache License, Version 2.0.
33

4+
using System;
45
using System.Threading.Tasks;
56

67
using SixLabors.Memory;
78

8-
namespace SixLabors.ImageSharp.ParallelUtils
9+
namespace SixLabors.ImageSharp.Advanced.ParallelUtils
910
{
1011
/// <summary>
1112
/// Defines execution settings for methods in <see cref="ParallelHelper"/>.
1213
/// </summary>
13-
internal readonly struct ParallelExecutionSettings
14+
public readonly struct ParallelExecutionSettings
1415
{
1516
/// <summary>
1617
/// Default value for <see cref="MinimumPixelsProcessedPerTask"/>.
@@ -20,11 +21,24 @@ internal readonly struct ParallelExecutionSettings
2021
/// <summary>
2122
/// Initializes a new instance of the <see cref="ParallelExecutionSettings"/> struct.
2223
/// </summary>
24+
/// <param name="maxDegreeOfParallelism">The value used for initializing <see cref="ParallelOptions.MaxDegreeOfParallelism"/> when using TPL.</param>
25+
/// <param name="minimumPixelsProcessedPerTask">The value for <see cref="MinimumPixelsProcessedPerTask"/>.</param>
26+
/// <param name="memoryAllocator">The <see cref="MemoryAllocator"/>.</param>
2327
public ParallelExecutionSettings(
2428
int maxDegreeOfParallelism,
2529
int minimumPixelsProcessedPerTask,
2630
MemoryAllocator memoryAllocator)
2731
{
32+
// Shall be compatible with ParallelOptions.MaxDegreeOfParallelism:
33+
// https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.paralleloptions.maxdegreeofparallelism
34+
if (maxDegreeOfParallelism == 0 || maxDegreeOfParallelism < -1)
35+
{
36+
throw new ArgumentOutOfRangeException(nameof(maxDegreeOfParallelism));
37+
}
38+
39+
Guard.MustBeGreaterThan(minimumPixelsProcessedPerTask, 0, nameof(minimumPixelsProcessedPerTask));
40+
Guard.NotNull(memoryAllocator, nameof(memoryAllocator));
41+
2842
this.MaxDegreeOfParallelism = maxDegreeOfParallelism;
2943
this.MinimumPixelsProcessedPerTask = minimumPixelsProcessedPerTask;
3044
this.MemoryAllocator = memoryAllocator;
@@ -33,13 +47,15 @@ public ParallelExecutionSettings(
3347
/// <summary>
3448
/// Initializes a new instance of the <see cref="ParallelExecutionSettings"/> struct.
3549
/// </summary>
50+
/// <param name="maxDegreeOfParallelism">The value used for initializing <see cref="ParallelOptions.MaxDegreeOfParallelism"/> when using TPL.</param>
51+
/// <param name="memoryAllocator">The <see cref="MemoryAllocator"/>.</param>
3652
public ParallelExecutionSettings(int maxDegreeOfParallelism, MemoryAllocator memoryAllocator)
3753
: this(maxDegreeOfParallelism, DefaultMinimumPixelsProcessedPerTask, memoryAllocator)
3854
{
3955
}
4056

4157
/// <summary>
42-
/// Gets the MemoryAllocator
58+
/// Gets the <see cref="MemoryAllocator"/>.
4359
/// </summary>
4460
public MemoryAllocator MemoryAllocator { get; }
4561

@@ -60,12 +76,26 @@ public ParallelExecutionSettings(int maxDegreeOfParallelism, MemoryAllocator mem
6076
/// Creates a new instance of <see cref="ParallelExecutionSettings"/>
6177
/// having <see cref="MinimumPixelsProcessedPerTask"/> multiplied by <paramref name="multiplier"/>
6278
/// </summary>
79+
/// <param name="multiplier">The value to multiply <see cref="MinimumPixelsProcessedPerTask"/> with.</param>
80+
/// <returns>The modified <see cref="ParallelExecutionSettings"/>.</returns>
6381
public ParallelExecutionSettings MultiplyMinimumPixelsPerTask(int multiplier)
6482
{
83+
Guard.MustBeGreaterThan(multiplier, 0, nameof(multiplier));
84+
6585
return new ParallelExecutionSettings(
6686
this.MaxDegreeOfParallelism,
6787
this.MinimumPixelsProcessedPerTask * multiplier,
6888
this.MemoryAllocator);
6989
}
90+
91+
/// <summary>
92+
/// Get the default <see cref="SixLabors.ImageSharp.Advanced.ParallelUtils.ParallelExecutionSettings"/> for a <see cref="SixLabors.ImageSharp.Configuration"/>
93+
/// </summary>
94+
/// <param name="configuration">The <see cref="Configuration"/>.</param>
95+
/// <returns>The <see cref="ParallelExecutionSettings"/>.</returns>
96+
public static ParallelExecutionSettings FromConfiguration(Configuration configuration)
97+
{
98+
return new ParallelExecutionSettings(configuration.MaxDegreeOfParallelism, configuration.MemoryAllocator);
99+
}
70100
}
71-
}
101+
}

src/ImageSharp/Common/ParallelUtils/ParallelHelper.cs renamed to src/ImageSharp/Advanced/ParallelUtils/ParallelHelper.cs

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,44 +10,45 @@
1010
using SixLabors.Memory;
1111
using SixLabors.Primitives;
1212

13-
namespace SixLabors.ImageSharp.ParallelUtils
13+
namespace SixLabors.ImageSharp.Advanced.ParallelUtils
1414
{
1515
/// <summary>
1616
/// Utility methods for batched processing of pixel row intervals.
17-
/// Parallel execution is optimized for image processing.
18-
/// Use this instead of direct <see cref="Parallel"/> calls!
17+
/// Parallel execution is optimized for image processing based on values defined
18+
/// <see cref="ParallelExecutionSettings"/> or <see cref="Configuration"/>.
19+
/// Using this class is preferred over direct usage of <see cref="Parallel"/> utility methods.
1920
/// </summary>
20-
internal static class ParallelHelper
21+
public static class ParallelHelper
2122
{
22-
/// <summary>
23-
/// Get the default <see cref="ParallelExecutionSettings"/> for a <see cref="Configuration"/>
24-
/// </summary>
25-
public static ParallelExecutionSettings GetParallelSettings(this Configuration configuration)
26-
{
27-
return new ParallelExecutionSettings(configuration.MaxDegreeOfParallelism, configuration.MemoryAllocator);
28-
}
29-
3023
/// <summary>
3124
/// Iterate through the rows of a rectangle in optimized batches defined by <see cref="RowInterval"/>-s.
3225
/// </summary>
26+
/// <param name="rectangle">The <see cref="Rectangle"/>.</param>
27+
/// <param name="configuration">The <see cref="Configuration"/> to get the parallel settings from.</param>
28+
/// <param name="body">The method body defining the iteration logic on a single <see cref="RowInterval"/>.</param>
3329
public static void IterateRows(Rectangle rectangle, Configuration configuration, Action<RowInterval> body)
3430
{
35-
ParallelExecutionSettings parallelSettings = configuration.GetParallelSettings();
31+
ParallelExecutionSettings parallelSettings = ParallelExecutionSettings.FromConfiguration(configuration);
3632

3733
IterateRows(rectangle, parallelSettings, body);
3834
}
3935

4036
/// <summary>
4137
/// Iterate through the rows of a rectangle in optimized batches defined by <see cref="RowInterval"/>-s.
4238
/// </summary>
39+
/// <param name="rectangle">The <see cref="Rectangle"/>.</param>
40+
/// <param name="parallelSettings">The <see cref="ParallelExecutionSettings"/>.</param>
41+
/// <param name="body">The method body defining the iteration logic on a single <see cref="RowInterval"/>.</param>
4342
public static void IterateRows(
4443
Rectangle rectangle,
4544
in ParallelExecutionSettings parallelSettings,
4645
Action<RowInterval> body)
4746
{
4847
ValidateRectangle(rectangle);
4948

50-
int maxSteps = DivideCeil(rectangle.Width * rectangle.Height, parallelSettings.MinimumPixelsProcessedPerTask);
49+
int maxSteps = DivideCeil(
50+
rectangle.Width * rectangle.Height,
51+
parallelSettings.MinimumPixelsProcessedPerTask);
5152

5253
int numOfSteps = Math.Min(parallelSettings.MaxDegreeOfParallelism, maxSteps);
5354

@@ -81,7 +82,7 @@ public static void IterateRows(
8182
/// Iterate through the rows of a rectangle in optimized batches defined by <see cref="RowInterval"/>-s
8283
/// instantiating a temporary buffer for each <paramref name="body"/> invocation.
8384
/// </summary>
84-
public static void IterateRowsWithTempBuffer<T>(
85+
internal static void IterateRowsWithTempBuffer<T>(
8586
Rectangle rectangle,
8687
in ParallelExecutionSettings parallelSettings,
8788
Action<RowInterval, Memory<T>> body)
@@ -133,13 +134,13 @@ public static void IterateRowsWithTempBuffer<T>(
133134
/// Iterate through the rows of a rectangle in optimized batches defined by <see cref="RowInterval"/>-s
134135
/// instantiating a temporary buffer for each <paramref name="body"/> invocation.
135136
/// </summary>
136-
public static void IterateRowsWithTempBuffer<T>(
137+
internal static void IterateRowsWithTempBuffer<T>(
137138
Rectangle rectangle,
138139
Configuration configuration,
139140
Action<RowInterval, Memory<T>> body)
140141
where T : unmanaged
141142
{
142-
IterateRowsWithTempBuffer(rectangle, configuration.GetParallelSettings(), body);
143+
IterateRowsWithTempBuffer(rectangle, ParallelExecutionSettings.FromConfiguration(configuration), body);
143144
}
144145

145146
[MethodImpl(MethodImplOptions.AggressiveInlining)]

src/ImageSharp/Configuration.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ public int MaxDegreeOfParallelism
6363
get => this.maxDegreeOfParallelism;
6464
set
6565
{
66-
if (value <= 0)
66+
if (value == 0 || value < -1)
6767
{
6868
throw new ArgumentOutOfRangeException(nameof(this.MaxDegreeOfParallelism));
6969
}
@@ -161,4 +161,4 @@ internal static Configuration CreateDefaultInstance()
161161
new BmpConfigurationModule());
162162
}
163163
}
164-
}
164+
}

src/ImageSharp/ImageFrameCollection{TPixel}.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,7 @@ private ImageFrame<TPixel> CopyNonCompatibleFrame(ImageFrame source)
351351
this.parent.GetConfiguration(),
352352
source.Size(),
353353
source.Metadata.DeepClone());
354-
source.CopyPixelsTo(result.PixelBuffer.Span);
354+
source.CopyPixelsTo(result.PixelBuffer.GetSpan());
355355
return result;
356356
}
357357
}

src/ImageSharp/ImageFrame{TPixel}.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66
using System.Runtime.InteropServices;
77

88
using SixLabors.ImageSharp.Advanced;
9+
using SixLabors.ImageSharp.Advanced.ParallelUtils;
910
using SixLabors.ImageSharp.Memory;
1011
using SixLabors.ImageSharp.Metadata;
11-
using SixLabors.ImageSharp.ParallelUtils;
1212
using SixLabors.ImageSharp.PixelFormats;
1313
using SixLabors.Memory;
1414
using SixLabors.Primitives;
@@ -218,10 +218,10 @@ internal override void CopyPixelsTo<TDestinationPixel>(Span<TDestinationPixel> d
218218
if (typeof(TPixel) == typeof(TDestinationPixel))
219219
{
220220
Span<TPixel> dest1 = MemoryMarshal.Cast<TDestinationPixel, TPixel>(destination);
221-
this.PixelBuffer.Span.CopyTo(dest1);
221+
this.PixelBuffer.GetSpan().CopyTo(dest1);
222222
}
223223

224-
PixelOperations<TPixel>.Instance.To(this.Configuration, this.PixelBuffer.Span, destination);
224+
PixelOperations<TPixel>.Instance.To(this.Configuration, this.PixelBuffer.GetSpan(), destination);
225225
}
226226

227227
/// <inheritdoc/>

0 commit comments

Comments
 (0)