diff --git a/src/ImageSharp/Advanced/ParallelRowIterator.cs b/src/ImageSharp/Advanced/ParallelRowIterator.cs
index 70b48aee9..86442ede7 100644
--- a/src/ImageSharp/Advanced/ParallelRowIterator.cs
+++ b/src/ImageSharp/Advanced/ParallelRowIterator.cs
@@ -17,6 +17,137 @@ namespace SixLabors.ImageSharp.Advanced
///
public static partial class ParallelRowIterator
{
+ ///
+ /// Iterate through the rows of a rectangle in optimized batches.
+ ///
+ /// The type of row operation to perform.
+ /// The to get the parallel settings from.
+ /// The .
+ /// The operation defining the iteration logic on a single row.
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public static void IterateRows(Configuration configuration, Rectangle rectangle, in T operation)
+ where T : struct, IRowOperation
+ {
+ var parallelSettings = ParallelExecutionSettings.FromConfiguration(configuration);
+ IterateRows(rectangle, in parallelSettings, in operation);
+ }
+
+ ///
+ /// Iterate through the rows of a rectangle in optimized batches.
+ ///
+ /// The type of row operation to perform.
+ /// The .
+ /// The .
+ /// The operation defining the iteration logic on a single row.
+ public static void IterateRows(
+ Rectangle rectangle,
+ in ParallelExecutionSettings parallelSettings,
+ in T operation)
+ where T : struct, IRowOperation
+ {
+ ValidateRectangle(rectangle);
+
+ int top = rectangle.Top;
+ int bottom = rectangle.Bottom;
+ int width = rectangle.Width;
+ int height = rectangle.Height;
+
+ int maxSteps = DivideCeil(width * height, parallelSettings.MinimumPixelsProcessedPerTask);
+ int numOfSteps = Math.Min(parallelSettings.MaxDegreeOfParallelism, maxSteps);
+
+ // Avoid TPL overhead in this trivial case:
+ if (numOfSteps == 1)
+ {
+ for (int y = top; y < bottom; y++)
+ {
+ Unsafe.AsRef(operation).Invoke(y);
+ }
+
+ return;
+ }
+
+ int verticalStep = DivideCeil(rectangle.Height, numOfSteps);
+ var parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = numOfSteps };
+ var info = new IterationParameters(top, bottom, verticalStep);
+ var wrappingOperation = new RowOperationWrapper(in info, in operation);
+
+ Parallel.For(
+ 0,
+ numOfSteps,
+ parallelOptions,
+ wrappingOperation.Invoke);
+ }
+
+ ///
+ /// Iterate through the rows of a rectangle in optimized batches.
+ /// instantiating a temporary buffer for each invocation.
+ ///
+ /// The type of row operation to perform.
+ /// The type of buffer elements.
+ /// The to get the parallel settings from.
+ /// The .
+ /// The operation defining the iteration logic on a single row.
+ public static void IterateRows(Configuration configuration, Rectangle rectangle, in T operation)
+ where T : struct, IRowOperation
+ where TBuffer : unmanaged
+ {
+ var parallelSettings = ParallelExecutionSettings.FromConfiguration(configuration);
+ IterateRows(rectangle, in parallelSettings, in operation);
+ }
+
+ ///
+ /// Iterate through the rows of a rectangle in optimized batches.
+ /// instantiating a temporary buffer for each invocation.
+ ///
+ /// The type of row operation to perform.
+ /// The type of buffer elements.
+ /// The .
+ /// The .
+ /// The operation defining the iteration logic on a single row.
+ public static void IterateRows(
+ Rectangle rectangle,
+ in ParallelExecutionSettings parallelSettings,
+ in T operation)
+ where T : struct, IRowOperation
+ where TBuffer : unmanaged
+ {
+ ValidateRectangle(rectangle);
+
+ int top = rectangle.Top;
+ int bottom = rectangle.Bottom;
+ int width = rectangle.Width;
+ int height = rectangle.Height;
+
+ int maxSteps = DivideCeil(width * height, parallelSettings.MinimumPixelsProcessedPerTask);
+ int numOfSteps = Math.Min(parallelSettings.MaxDegreeOfParallelism, maxSteps);
+ MemoryAllocator allocator = parallelSettings.MemoryAllocator;
+
+ // Avoid TPL overhead in this trivial case:
+ if (numOfSteps == 1)
+ {
+ using IMemoryOwner buffer = allocator.Allocate(width);
+ Span span = buffer.Memory.Span;
+
+ for (int y = top; y < bottom; y++)
+ {
+ Unsafe.AsRef(operation).Invoke(y, span);
+ }
+
+ return;
+ }
+
+ int verticalStep = DivideCeil(height, numOfSteps);
+ var parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = numOfSteps };
+ var info = new IterationParameters(top, bottom, verticalStep, width);
+ var wrappingOperation = new RowOperationWrapper(in info, allocator, in operation);
+
+ Parallel.For(
+ 0,
+ numOfSteps,
+ parallelOptions,
+ wrappingOperation.Invoke);
+ }
+
///
/// Iterate through the rows of a rectangle in optimized batches defined by -s.
///
@@ -123,10 +254,9 @@ namespace SixLabors.ImageSharp.Advanced
if (numOfSteps == 1)
{
var rows = new RowInterval(top, bottom);
- using (IMemoryOwner buffer = allocator.Allocate(width))
- {
- Unsafe.AsRef(operation).Invoke(in rows, buffer.Memory.Span);
- }
+ using IMemoryOwner buffer = allocator.Allocate(width);
+
+ Unsafe.AsRef(operation).Invoke(in rows, buffer.Memory.Span);
return;
}