|
|
|
@ -21,14 +21,16 @@ namespace SixLabors.ImageSharp.Advanced.ParallelUtils |
|
|
|
/// <summary>
|
|
|
|
/// Iterate through the rows of a rectangle in optimized batches defined by <see cref="RowInterval"/>-s.
|
|
|
|
/// </summary>
|
|
|
|
/// <typeparam name="T">The type of row action to perform.</typeparam>
|
|
|
|
/// <param name="rectangle">The <see cref="Rectangle"/>.</param>
|
|
|
|
/// <param name="configuration">The <see cref="Configuration"/> to get the parallel settings from.</param>
|
|
|
|
/// <param name="body">The method body defining the iteration logic on a single <see cref="RowInterval"/>.</param>
|
|
|
|
public static void IterateRows(Rectangle rectangle, Configuration configuration, Action<RowInterval> body) |
|
|
|
[MethodImpl(InliningOptions.ShortMethod)] |
|
|
|
public static void IterateRows<T>(Rectangle rectangle, Configuration configuration, in T body) |
|
|
|
where T : struct, IRowIntervalAction |
|
|
|
{ |
|
|
|
var parallelSettings = ParallelExecutionSettings.FromConfiguration(configuration); |
|
|
|
|
|
|
|
IterateRows(rectangle, in parallelSettings, body); |
|
|
|
IterateRows(rectangle, in parallelSettings, in body); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
@ -36,52 +38,120 @@ namespace SixLabors.ImageSharp.Advanced.ParallelUtils |
|
|
|
/// </summary>
|
|
|
|
/// <typeparam name="T">The type of row action to perform.</typeparam>
|
|
|
|
/// <param name="rectangle">The <see cref="Rectangle"/>.</param>
|
|
|
|
/// <param name="configuration">The <see cref="Configuration"/> to get the parallel settings from.</param>
|
|
|
|
/// <param name="parallelSettings">The <see cref="ParallelExecutionSettings"/>.</param>
|
|
|
|
/// <param name="body">The method body defining the iteration logic on a single <see cref="RowInterval"/>.</param>
|
|
|
|
public static void IterateRowsFast<T>(Rectangle rectangle, Configuration configuration, ref T body) |
|
|
|
where T : struct, IRowIntervalAction |
|
|
|
{ |
|
|
|
var parallelSettings = ParallelExecutionSettings.FromConfiguration(configuration); |
|
|
|
|
|
|
|
IterateRowsFast(rectangle, in parallelSettings, ref body); |
|
|
|
} |
|
|
|
|
|
|
|
internal static void IterateRowsFast<T>( |
|
|
|
public static void IterateRows<T>( |
|
|
|
Rectangle rectangle, |
|
|
|
in ParallelExecutionSettings parallelSettings, |
|
|
|
ref T body) |
|
|
|
in T body) |
|
|
|
where T : struct, IRowIntervalAction |
|
|
|
{ |
|
|
|
ValidateRectangle(rectangle); |
|
|
|
|
|
|
|
int maxSteps = DivideCeil( |
|
|
|
rectangle.Width * rectangle.Height, |
|
|
|
parallelSettings.MinimumPixelsProcessedPerTask); |
|
|
|
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) |
|
|
|
{ |
|
|
|
var rows = new RowInterval(rectangle.Top, rectangle.Bottom); |
|
|
|
var rows = new RowInterval(top, bottom); |
|
|
|
body.Invoke(in rows); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
int verticalStep = DivideCeil(rectangle.Height, numOfSteps); |
|
|
|
|
|
|
|
var parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = numOfSteps }; |
|
|
|
var rowInfo = new WrappingRowIntervalInfo(top, bottom, verticalStep); |
|
|
|
var rowAction = new WrappingRowIntervalAction<T>(in rowInfo, in body); |
|
|
|
|
|
|
|
Parallel.For( |
|
|
|
0, |
|
|
|
numOfSteps, |
|
|
|
parallelOptions, |
|
|
|
i => rowAction.Invoke(i)); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Iterate through the rows of a rectangle in optimized batches defined by <see cref="RowInterval"/>-s
|
|
|
|
/// instantiating a temporary buffer for each <paramref name="body"/> invocation.
|
|
|
|
/// </summary>
|
|
|
|
/// <typeparam name="T">The type of row action to perform.</typeparam>
|
|
|
|
/// <typeparam name="TBuffer">The type of buffer elements.</typeparam>
|
|
|
|
/// <param name="rectangle">The <see cref="Rectangle"/>.</param>
|
|
|
|
/// <param name="configuration">The <see cref="Configuration"/> to get the parallel settings from.</param>
|
|
|
|
/// <param name="body">The method body defining the iteration logic on a single <see cref="RowInterval"/>.</param>
|
|
|
|
public static void IterateRows<T, TBuffer>(Rectangle rectangle, Configuration configuration, in T body) |
|
|
|
where T : struct, IRowIntervalAction<TBuffer> |
|
|
|
where TBuffer : unmanaged |
|
|
|
{ |
|
|
|
var parallelSettings = ParallelExecutionSettings.FromConfiguration(configuration); |
|
|
|
IterateRows<T, TBuffer>(rectangle, in parallelSettings, in body); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Iterate through the rows of a rectangle in optimized batches defined by <see cref="RowInterval"/>-s
|
|
|
|
/// instantiating a temporary buffer for each <paramref name="body"/> invocation.
|
|
|
|
/// </summary>
|
|
|
|
internal static void IterateRows<T, TBuffer>( |
|
|
|
Rectangle rectangle, |
|
|
|
in ParallelExecutionSettings parallelSettings, |
|
|
|
in T body) |
|
|
|
where T : struct, IRowIntervalAction<TBuffer> |
|
|
|
where TBuffer : unmanaged |
|
|
|
{ |
|
|
|
ValidateRectangle(rectangle); |
|
|
|
|
|
|
|
int top = rectangle.Top; |
|
|
|
int bottom = rectangle.Bottom; |
|
|
|
var rowInfo = new WrappingRowIntervalInfo(top, bottom, verticalStep); |
|
|
|
var rowAction = new WrappingRowIntervalAction<T>(in rowInfo, ref body); |
|
|
|
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) |
|
|
|
{ |
|
|
|
var rows = new RowInterval(top, bottom); |
|
|
|
using (IMemoryOwner<TBuffer> buffer = allocator.Allocate<TBuffer>(width)) |
|
|
|
{ |
|
|
|
body.Invoke(rows, buffer.Memory); |
|
|
|
} |
|
|
|
|
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
int verticalStep = DivideCeil(height, numOfSteps); |
|
|
|
var parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = numOfSteps }; |
|
|
|
var rowInfo = new WrappingRowIntervalInfo(top, bottom, verticalStep, width); |
|
|
|
var rowAction = new WrappingRowIntervalAction<T, TBuffer>(in rowInfo, allocator, in body); |
|
|
|
|
|
|
|
Parallel.For( |
|
|
|
0, |
|
|
|
numOfSteps, |
|
|
|
parallelOptions, |
|
|
|
i => rowAction.Invoke(i)); |
|
|
|
i => |
|
|
|
rowAction.Invoke(i)); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Iterate through the rows of a rectangle in optimized batches defined by <see cref="RowInterval"/>-s.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="rectangle">The <see cref="Rectangle"/>.</param>
|
|
|
|
/// <param name="configuration">The <see cref="Configuration"/> to get the parallel settings from.</param>
|
|
|
|
/// <param name="body">The method body defining the iteration logic on a single <see cref="RowInterval"/>.</param>
|
|
|
|
// [Obsolete("Use non-allocating generic versions instead.")]
|
|
|
|
public static void IterateRows(Rectangle rectangle, Configuration configuration, Action<RowInterval> body) |
|
|
|
{ |
|
|
|
var parallelSettings = ParallelExecutionSettings.FromConfiguration(configuration); |
|
|
|
|
|
|
|
IterateRows(rectangle, in parallelSettings, body); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
@ -90,10 +160,11 @@ namespace SixLabors.ImageSharp.Advanced.ParallelUtils |
|
|
|
/// <param name="rectangle">The <see cref="Rectangle"/>.</param>
|
|
|
|
/// <param name="parallelSettings">The <see cref="ParallelExecutionSettings"/>.</param>
|
|
|
|
/// <param name="body">The method body defining the iteration logic on a single <see cref="RowInterval"/>.</param>
|
|
|
|
// [Obsolete("Use non-allocating generic versions instead.")]
|
|
|
|
public static void IterateRows( |
|
|
|
Rectangle rectangle, |
|
|
|
in ParallelExecutionSettings parallelSettings, |
|
|
|
Action<RowInterval> body) |
|
|
|
Rectangle rectangle, |
|
|
|
in ParallelExecutionSettings parallelSettings, |
|
|
|
Action<RowInterval> body) |
|
|
|
{ |
|
|
|
ValidateRectangle(rectangle); |
|
|
|
|
|
|
|
@ -143,6 +214,7 @@ namespace SixLabors.ImageSharp.Advanced.ParallelUtils |
|
|
|
/// Iterate through the rows of a rectangle in optimized batches defined by <see cref="RowInterval"/>-s
|
|
|
|
/// instantiating a temporary buffer for each <paramref name="body"/> invocation.
|
|
|
|
/// </summary>
|
|
|
|
// [Obsolete("Use non-allocating generic versions instead.")]
|
|
|
|
internal static void IterateRowsWithTempBuffer<T>( |
|
|
|
Rectangle rectangle, |
|
|
|
in ParallelExecutionSettings parallelSettings, |
|
|
|
@ -204,6 +276,7 @@ namespace SixLabors.ImageSharp.Advanced.ParallelUtils |
|
|
|
/// Iterate through the rows of a rectangle in optimized batches defined by <see cref="RowInterval"/>-s
|
|
|
|
/// instantiating a temporary buffer for each <paramref name="body"/> invocation.
|
|
|
|
/// </summary>
|
|
|
|
// [Obsolete("Use non-allocating generic versions instead.")]
|
|
|
|
internal static void IterateRowsWithTempBuffer<T>( |
|
|
|
Rectangle rectangle, |
|
|
|
Configuration configuration, |
|
|
|
@ -213,7 +286,7 @@ namespace SixLabors.ImageSharp.Advanced.ParallelUtils |
|
|
|
IterateRowsWithTempBuffer(rectangle, ParallelExecutionSettings.FromConfiguration(configuration), body); |
|
|
|
} |
|
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|
|
|
[MethodImpl(InliningOptions.ShortMethod)] |
|
|
|
private static int DivideCeil(int dividend, int divisor) => 1 + ((dividend - 1) / divisor); |
|
|
|
|
|
|
|
private static void ValidateRectangle(Rectangle rectangle) |
|
|
|
|