Browse Source

Add single row RowAction value delegate

pull/1108/head
Sergio Pedri 6 years ago
parent
commit
b77dcfacf7
  1. 70
      src/ImageSharp/Advanced/IRowAction.cs
  2. 60
      src/ImageSharp/Advanced/ParallelRowIterator.cs

70
src/ImageSharp/Advanced/IRowAction.cs

@ -0,0 +1,70 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.Advanced
{
/// <summary>
/// Defines the contract for an action that operates on a row.
/// </summary>
public interface IRowAction
{
/// <summary>
/// Invokes the method passing the row y coordinate.
/// </summary>
/// <param name="y">The row y coordinate.</param>
void Invoke(int y);
}
/// <summary>
/// A <see langword="struct"/> that wraps a value delegate of a specified type, and info on the memory areas to process
/// </summary>
/// <typeparam name="T">The type of value delegate to invoke</typeparam>
internal readonly struct WrappingRowAction<T>
where T : struct, IRowAction
{
public readonly int MinY;
public readonly int MaxY;
public readonly int StepY;
public readonly int MaxX;
private readonly T action;
[MethodImpl(InliningOptions.ShortMethod)]
public WrappingRowAction(int minY, int maxY, int stepY, in T action)
: this(minY, maxY, stepY, 0, action)
{
}
[MethodImpl(InliningOptions.ShortMethod)]
public WrappingRowAction(int minY, int maxY, int stepY, int maxX, in T action)
{
this.MinY = minY;
this.MaxY = maxY;
this.StepY = stepY;
this.MaxX = maxX;
this.action = action;
}
[MethodImpl(InliningOptions.ShortMethod)]
public void Invoke(int i)
{
int yMin = this.MinY + (i * this.StepY);
if (yMin >= this.MaxY)
{
return;
}
int yMax = Math.Min(yMin + this.StepY, this.MaxY);
for (int y = yMin; y < yMax; y++)
{
// Skip the safety copy when invoking a potentially impure method on a readonly field
Unsafe.AsRef(this.action).Invoke(y);
}
}
}
}

60
src/ImageSharp/Advanced/ParallelRowIterator.cs

@ -76,6 +76,66 @@ namespace SixLabors.ImageSharp.Advanced
rowAction.Invoke);
}
/// <summary>
/// Iterate through the rows of a rectangle in optimized batches.
/// </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 row.</param>
[MethodImpl(InliningOptions.ShortMethod)]
public static void IterateRows2<T>(Rectangle rectangle, Configuration configuration, in T body)
where T : struct, IRowAction
{
var parallelSettings = ParallelExecutionSettings.FromConfiguration(configuration);
IterateRows2(rectangle, in parallelSettings, in body);
}
/// <summary>
/// Iterate through the rows of a rectangle in optimized batches.
/// </summary>
/// <typeparam name="T">The type of row action to perform.</typeparam>
/// <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 row.</param>
public static void IterateRows2<T>(
Rectangle rectangle,
in ParallelExecutionSettings parallelSettings,
in T body)
where T : struct, IRowAction
{
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(body).Invoke(y);
}
return;
}
int verticalStep = DivideCeil(rectangle.Height, numOfSteps);
var parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = numOfSteps };
var rowAction = new WrappingRowAction<T>(top, bottom, verticalStep, in body);
Parallel.For(
0,
numOfSteps,
parallelOptions,
rowAction.Invoke);
}
/// <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.

Loading…
Cancel
Save