Browse Source

Internalize, partially optimize and rename Action methods.

pull/1108/head
James Jackson-South 6 years ago
parent
commit
e40731d5da
  1. 29
      src/ImageSharp/Advanced/IRowIntervalAction.cs
  2. 40
      src/ImageSharp/Advanced/IRowIntervalAction{TBuffer}.cs
  3. 112
      src/ImageSharp/Advanced/ParallelRowIterator.cs
  4. 2
      src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor{TPixel}.cs
  5. 2
      src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor{TPixel}.cs
  6. 2
      src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor{TPixel}.cs
  7. 2
      src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor{TPixel}.cs
  8. 2
      src/ImageSharp/Processing/Processors/Effects/PixelRowDelegateProcessorBase{TPixel}.cs
  9. 2
      src/ImageSharp/Processing/Processors/Filters/FilterProcessor{TPixel}.cs
  10. 2
      src/ImageSharp/Processing/Processors/Overlays/GlowProcessor{TPixel}.cs
  11. 2
      src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor{TPixel}.cs
  12. 8
      tests/ImageSharp.Tests/Helpers/ParallelRowIteratorTests.cs
  13. 2
      tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs

29
src/ImageSharp/Advanced/IRowIntervalAction.cs

@ -40,6 +40,35 @@ namespace SixLabors.ImageSharp.Advanced
}
}
internal readonly struct WrappingRowIntervalAction
{
private readonly WrappingRowIntervalInfo info;
private readonly Action<RowInterval> action;
[MethodImpl(InliningOptions.ShortMethod)]
public WrappingRowIntervalAction(in WrappingRowIntervalInfo info, Action<RowInterval> action)
{
this.info = info;
this.action = action;
}
[MethodImpl(InliningOptions.ShortMethod)]
public void Invoke(int i)
{
int yMin = this.info.MinY + (i * this.info.StepY);
if (yMin >= this.info.MaxY)
{
return;
}
int yMax = Math.Min(yMin + this.info.StepY, this.info.MaxY);
var rows = new RowInterval(yMin, yMax);
this.action(rows);
}
}
internal readonly struct WrappingRowIntervalAction<T>
where T : struct, IRowIntervalAction
{

40
src/ImageSharp/Advanced/IRowIntervalAction{TBuffer}.cs

@ -23,7 +23,43 @@ namespace SixLabors.ImageSharp.Advanced
void Invoke(in RowInterval rows, Memory<TBuffer> memory);
}
internal readonly struct WrappingRowIntervalAction<T, TBuffer>
internal readonly struct WrappingRowIntervalBufferAction<TBuffer>
where TBuffer : unmanaged
{
private readonly WrappingRowIntervalInfo info;
private readonly MemoryAllocator allocator;
private readonly Action<RowInterval, Memory<TBuffer>> action;
[MethodImpl(InliningOptions.ShortMethod)]
public WrappingRowIntervalBufferAction(
in WrappingRowIntervalInfo info,
MemoryAllocator allocator,
Action<RowInterval, Memory<TBuffer>> action)
{
this.info = info;
this.allocator = allocator;
this.action = action;
}
[MethodImpl(InliningOptions.ShortMethod)]
public void Invoke(int i)
{
int yMin = this.info.MinY + (i * this.info.StepY);
if (yMin >= this.info.MaxY)
{
return;
}
int yMax = Math.Min(yMin + this.info.StepY, this.info.MaxY);
var rows = new RowInterval(yMin, yMax);
using IMemoryOwner<TBuffer> buffer = this.allocator.Allocate<TBuffer>(this.info.MaxX);
this.action(rows, buffer.Memory);
}
}
internal readonly struct WrappingRowIntervalBufferAction<T, TBuffer>
where T : struct, IRowIntervalAction<TBuffer>
where TBuffer : unmanaged
{
@ -32,7 +68,7 @@ namespace SixLabors.ImageSharp.Advanced
private readonly T action;
[MethodImpl(InliningOptions.ShortMethod)]
public WrappingRowIntervalAction(
public WrappingRowIntervalBufferAction(
in WrappingRowIntervalInfo info,
MemoryAllocator allocator,
in T action)

112
src/ImageSharp/Advanced/ParallelRowIterator.cs

@ -130,7 +130,7 @@ namespace SixLabors.ImageSharp.Advanced
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);
var rowAction = new WrappingRowIntervalBufferAction<T, TBuffer>(in rowInfo, allocator, in body);
Parallel.For(
0,
@ -145,11 +145,9 @@ namespace SixLabors.ImageSharp.Advanced
/// <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)
internal static void IterateRows(Rectangle rectangle, Configuration configuration, Action<RowInterval> body)
{
var parallelSettings = ParallelExecutionSettings.FromConfiguration(configuration);
IterateRows(rectangle, in parallelSettings, body);
}
@ -159,80 +157,81 @@ namespace SixLabors.ImageSharp.Advanced
/// <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(
internal static void IterateRows(
Rectangle rectangle,
in ParallelExecutionSettings parallelSettings,
Action<RowInterval> body)
{
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(rows);
return;
}
int verticalStep = DivideCeil(rectangle.Height, numOfSteps);
var parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = numOfSteps };
int top = rectangle.Top;
int bottom = rectangle.Bottom;
var rowInfo = new WrappingRowIntervalInfo(top, bottom, verticalStep);
var rowAction = new WrappingRowIntervalAction(in rowInfo, body);
Parallel.For(
0,
numOfSteps,
parallelOptions,
i =>
{
int yMin = top + (i * verticalStep);
if (yMin >= bottom)
{
return;
}
int yMax = Math.Min(yMin + verticalStep, bottom);
var rows = new RowInterval(yMin, yMax);
rowAction.Invoke);
}
body(rows);
});
/// <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<TBuffer>(
Rectangle rectangle,
Configuration configuration,
Action<RowInterval, Memory<TBuffer>> body)
where TBuffer : unmanaged
{
var parallelSettings = ParallelExecutionSettings.FromConfiguration(configuration);
IterateRows(rectangle, in parallelSettings, 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>
// [Obsolete("Use non-allocating generic versions instead.")]
internal static void IterateRowsWithTempBuffer<T>(
internal static void IterateRows<TBuffer>(
Rectangle rectangle,
in ParallelExecutionSettings parallelSettings,
Action<RowInterval, Memory<T>> body)
where T : unmanaged
Action<RowInterval, Memory<TBuffer>> body)
where TBuffer : unmanaged
{
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);
MemoryAllocator memoryAllocator = parallelSettings.MemoryAllocator;
MemoryAllocator allocator = parallelSettings.MemoryAllocator;
// Avoid TPL overhead in this trivial case:
if (numOfSteps == 1)
{
var rows = new RowInterval(rectangle.Top, rectangle.Bottom);
using (IMemoryOwner<T> buffer = memoryAllocator.Allocate<T>(rectangle.Width))
var rows = new RowInterval(top, bottom);
using (IMemoryOwner<TBuffer> buffer = allocator.Allocate<TBuffer>(width))
{
body(rows, buffer.Memory);
}
@ -241,48 +240,15 @@ namespace SixLabors.ImageSharp.Advanced
}
int verticalStep = DivideCeil(rectangle.Height, numOfSteps);
var parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = numOfSteps };
int top = rectangle.Top;
int bottom = rectangle.Bottom;
var rowInfo = new WrappingRowIntervalInfo(top, bottom, verticalStep, width);
var rowAction = new WrappingRowIntervalBufferAction<TBuffer>(in rowInfo, allocator, body);
Parallel.For(
0,
numOfSteps,
parallelOptions,
i =>
{
int yMin = top + (i * verticalStep);
if (yMin >= bottom)
{
return;
}
int yMax = Math.Min(yMin + verticalStep, rectangle.Bottom);
var rows = new RowInterval(yMin, yMax);
using (IMemoryOwner<T> buffer = memoryAllocator.Allocate<T>(rectangle.Width))
{
body(rows, buffer.Memory);
}
});
}
/// <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>
// [Obsolete("Use non-allocating generic versions instead.")]
internal static void IterateRowsWithTempBuffer<T>(
Rectangle rectangle,
Configuration configuration,
Action<RowInterval, Memory<T>> body)
where T : unmanaged
{
IterateRowsWithTempBuffer(rectangle, ParallelExecutionSettings.FromConfiguration(configuration), body);
rowAction.Invoke);
}
[MethodImpl(InliningOptions.ShortMethod)]

2
src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor{TPixel}.cs

@ -427,7 +427,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
int width = workingRectangle.Width;
float exp = this.gamma;
ParallelRowIterator.IterateRowsWithTempBuffer<Vector4>(
ParallelRowIterator.IterateRows<Vector4>(
workingRectangle,
configuration,
(rows, vectorBuffer) =>

2
src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor{TPixel}.cs

@ -78,7 +78,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
var workingRectangle = Rectangle.FromLTRB(startX, startY, endX, endY);
int width = workingRectangle.Width;
ParallelRowIterator.IterateRowsWithTempBuffer<Vector4>(
ParallelRowIterator.IterateRows<Vector4>(
workingRectangle,
this.Configuration,
(rows, vectorBuffer) =>

2
src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor{TPixel}.cs

@ -97,7 +97,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
var workingRectangle = Rectangle.FromLTRB(startX, startY, endX, endY);
int width = workingRectangle.Width;
ParallelRowIterator.IterateRowsWithTempBuffer<Vector4>(
ParallelRowIterator.IterateRows<Vector4>(
workingRectangle,
configuration,
(rows, vectorBuffer) =>

2
src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor{TPixel}.cs

@ -68,7 +68,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
var workingRectangle = Rectangle.FromLTRB(startX, startY, endX, endY);
int width = workingRectangle.Width;
ParallelRowIterator.IterateRowsWithTempBuffer<Vector4>(
ParallelRowIterator.IterateRows<Vector4>(
workingRectangle,
this.Configuration,
(rows, vectorBuffer) =>

2
src/ImageSharp/Processing/Processors/Effects/PixelRowDelegateProcessorBase{TPixel}.cs

@ -39,7 +39,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Effects
Configuration configuration = this.Configuration;
PixelConversionModifiers modifiers = this.modifiers;
ParallelRowIterator.IterateRowsWithTempBuffer<Vector4>(
ParallelRowIterator.IterateRows<Vector4>(
interest,
this.Configuration,
(rows, vectorBuffer) =>

2
src/ImageSharp/Processing/Processors/Filters/FilterProcessor{TPixel}.cs

@ -38,7 +38,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Filters
ColorMatrix matrix = this.definition.Matrix;
ParallelRowIterator.IterateRowsWithTempBuffer<Vector4>(
ParallelRowIterator.IterateRows<Vector4>(
interest,
this.Configuration,
(rows, vectorBuffer) =>

2
src/ImageSharp/Processing/Processors/Overlays/GlowProcessor{TPixel}.cs

@ -81,7 +81,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays
{
rowColors.GetSpan().Fill(glowColor);
ParallelRowIterator.IterateRowsWithTempBuffer<float>(
ParallelRowIterator.IterateRows<float>(
workingRect,
configuration,
(rows, amounts) =>

2
src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor{TPixel}.cs

@ -85,7 +85,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays
{
rowColors.GetSpan().Fill(vignetteColor);
ParallelRowIterator.IterateRowsWithTempBuffer<float>(
ParallelRowIterator.IterateRows<float>(
workingRect,
configuration,
(rows, amounts) =>

8
tests/ImageSharp.Tests/Helpers/ParallelRowIteratorTests.cs

@ -136,7 +136,7 @@ namespace SixLabors.ImageSharp.Tests.Helpers
var bufferHashes = new ConcurrentBag<int>();
int actualNumberOfSteps = 0;
ParallelRowIterator.IterateRowsWithTempBuffer(
ParallelRowIterator.IterateRows(
rectangle,
parallelSettings,
(RowInterval rows, Memory<Vector4> buffer) =>
@ -179,7 +179,7 @@ namespace SixLabors.ImageSharp.Tests.Helpers
int[] expectedData = Enumerable.Repeat(0, minY).Concat(Enumerable.Range(minY, maxY - minY)).ToArray();
var actualData = new int[maxY];
ParallelRowIterator.IterateRowsWithTempBuffer(
ParallelRowIterator.IterateRows(
rectangle,
parallelSettings,
(RowInterval rows, Memory<Vector4> buffer) =>
@ -262,7 +262,7 @@ namespace SixLabors.ImageSharp.Tests.Helpers
var rectangle = new Rectangle(0, 0, width, height);
int actualNumberOfSteps = 0;
ParallelRowIterator.IterateRowsWithTempBuffer(
ParallelRowIterator.IterateRows(
rectangle,
parallelSettings,
(RowInterval rows, Memory<Vector4> buffer) =>
@ -371,7 +371,7 @@ namespace SixLabors.ImageSharp.Tests.Helpers
var rect = new Rectangle(0, 0, width, height);
ArgumentOutOfRangeException ex = Assert.Throws<ArgumentOutOfRangeException>(
() => ParallelRowIterator.IterateRowsWithTempBuffer<Rgba32>(rect, parallelSettings, (rows, memory) => { }));
() => ParallelRowIterator.IterateRows<Rgba32>(rect, parallelSettings, (rows, memory) => { }));
Assert.Contains(width <= 0 ? "Width" : "Height", ex.Message);
}

2
tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs

@ -702,7 +702,7 @@ namespace SixLabors.ImageSharp.Tests
{
Rectangle sourceRectangle = this.SourceRectangle;
Configuration configuration = this.Configuration;
ParallelRowIterator.IterateRowsWithTempBuffer<Vector4>(
ParallelRowIterator.IterateRows<Vector4>(
sourceRectangle,
configuration,
(rows, temp) =>

Loading…
Cancel
Save