Browse Source

Refactor processors to single row with buffer APIs

af/octree-no-pixelmap
Sergio Pedri 6 years ago
parent
commit
5708137dbd
  1. 38
      src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor{TPixel}.cs
  2. 84
      src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor{TPixel}.cs
  3. 84
      src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor{TPixel}.cs
  4. 80
      src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor{TPixel}.cs
  5. 27
      src/ImageSharp/Processing/Processors/Effects/PixelRowDelegateProcessor{TPixel,TDelegate}.cs
  6. 25
      src/ImageSharp/Processing/Processors/Filters/FilterProcessor{TPixel}.cs
  7. 36
      src/ImageSharp/Processing/Processors/Overlays/GlowProcessor{TPixel}.cs
  8. 38
      src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor{TPixel}.cs
  9. 58
      src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor{TPixel}.cs
  10. 69
      src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor{TPixel}.cs

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

@ -268,10 +268,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
protected override void OnFrameApply(ImageFrame<TPixel> source) protected override void OnFrameApply(ImageFrame<TPixel> source)
{ {
// Preliminary gamma highlight pass // Preliminary gamma highlight pass
ParallelRowIterator.IterateRows<ApplyGammaExposureRowIntervalAction, Vector4>( ParallelRowIterator.IterateRows2<ApplyGammaExposureRowAction, Vector4>(
this.SourceRectangle, this.SourceRectangle,
this.Configuration, this.Configuration,
new ApplyGammaExposureRowIntervalAction(this.SourceRectangle, source.PixelBuffer, this.Configuration, this.gamma)); new ApplyGammaExposureRowAction(this.SourceRectangle, source.PixelBuffer, this.Configuration, this.gamma));
// Create a 0-filled buffer to use to store the result of the component convolutions // Create a 0-filled buffer to use to store the result of the component convolutions
using Buffer2D<Vector4> processingBuffer = this.Configuration.MemoryAllocator.Allocate2D<Vector4>(source.Size(), AllocationOptions.Clean); using Buffer2D<Vector4> processingBuffer = this.Configuration.MemoryAllocator.Allocate2D<Vector4>(source.Size(), AllocationOptions.Clean);
@ -416,7 +416,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// <summary> /// <summary>
/// A <see langword="struct"/> implementing the gamma exposure logic for <see cref="BokehBlurProcessor{T}"/>. /// A <see langword="struct"/> implementing the gamma exposure logic for <see cref="BokehBlurProcessor{T}"/>.
/// </summary> /// </summary>
private readonly struct ApplyGammaExposureRowIntervalAction : IRowIntervalAction<Vector4> private readonly struct ApplyGammaExposureRowAction : IRowAction<Vector4>
{ {
private readonly Rectangle bounds; private readonly Rectangle bounds;
private readonly Buffer2D<TPixel> targetPixels; private readonly Buffer2D<TPixel> targetPixels;
@ -424,7 +424,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
private readonly float gamma; private readonly float gamma;
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public ApplyGammaExposureRowIntervalAction( public ApplyGammaExposureRowAction(
Rectangle bounds, Rectangle bounds,
Buffer2D<TPixel> targetPixels, Buffer2D<TPixel> targetPixels,
Configuration configuration, Configuration configuration,
@ -438,27 +438,23 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public void Invoke(in RowInterval rows, Memory<Vector4> memory) public void Invoke(int y, Span<Vector4> span)
{ {
Span<Vector4> vectorSpan = memory.Span; int length = span.Length;
int length = vectorSpan.Length;
for (int y = rows.Min; y < rows.Max; y++) Span<TPixel> targetRowSpan = this.targetPixels.GetRowSpan(y).Slice(this.bounds.X);
{ PixelOperations<TPixel>.Instance.ToVector4(this.configuration, targetRowSpan.Slice(0, length), span, PixelConversionModifiers.Premultiply);
Span<TPixel> targetRowSpan = this.targetPixels.GetRowSpan(y).Slice(this.bounds.X); ref Vector4 baseRef = ref MemoryMarshal.GetReference(span);
PixelOperations<TPixel>.Instance.ToVector4(this.configuration, targetRowSpan.Slice(0, length), vectorSpan, PixelConversionModifiers.Premultiply);
ref Vector4 baseRef = ref MemoryMarshal.GetReference(vectorSpan);
for (int x = 0; x < this.bounds.Width; x++)
{
ref Vector4 v = ref Unsafe.Add(ref baseRef, x);
v.X = MathF.Pow(v.X, this.gamma);
v.Y = MathF.Pow(v.Y, this.gamma);
v.Z = MathF.Pow(v.Z, this.gamma);
}
PixelOperations<TPixel>.Instance.FromVector4Destructive(this.configuration, vectorSpan.Slice(0, length), targetRowSpan); for (int x = 0; x < this.bounds.Width; x++)
{
ref Vector4 v = ref Unsafe.Add(ref baseRef, x);
v.X = MathF.Pow(v.X, this.gamma);
v.Y = MathF.Pow(v.Y, this.gamma);
v.Z = MathF.Pow(v.Z, this.gamma);
} }
PixelOperations<TPixel>.Instance.FromVector4Destructive(this.configuration, span.Slice(0, length), targetRowSpan);
} }
} }

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

@ -66,10 +66,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds()); var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds());
ParallelRowIterator.IterateRows<RowIntervalAction, Vector4>( ParallelRowIterator.IterateRows2<RowAction, Vector4>(
interest, interest,
this.Configuration, this.Configuration,
new RowIntervalAction(interest, targetPixels, source.PixelBuffer, this.KernelY, this.KernelX, this.Configuration, this.PreserveAlpha)); new RowAction(interest, targetPixels, source.PixelBuffer, this.KernelY, this.KernelX, this.Configuration, this.PreserveAlpha));
Buffer2D<TPixel>.SwapOrCopyContent(source.PixelBuffer, targetPixels); Buffer2D<TPixel>.SwapOrCopyContent(source.PixelBuffer, targetPixels);
} }
@ -77,7 +77,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// <summary> /// <summary>
/// A <see langword="struct"/> implementing the convolution logic for <see cref="Convolution2DProcessor{T}"/>. /// A <see langword="struct"/> implementing the convolution logic for <see cref="Convolution2DProcessor{T}"/>.
/// </summary> /// </summary>
private readonly struct RowIntervalAction : IRowIntervalAction<Vector4> private readonly struct RowAction : IRowAction<Vector4>
{ {
private readonly Rectangle bounds; private readonly Rectangle bounds;
private readonly int maxY; private readonly int maxY;
@ -90,7 +90,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
private readonly bool preserveAlpha; private readonly bool preserveAlpha;
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public RowIntervalAction( public RowAction(
Rectangle bounds, Rectangle bounds,
Buffer2D<TPixel> targetPixels, Buffer2D<TPixel> targetPixels,
Buffer2D<TPixel> sourcePixels, Buffer2D<TPixel> sourcePixels,
@ -112,54 +112,50 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public void Invoke(in RowInterval rows, Memory<Vector4> memory) public void Invoke(int y, Span<Vector4> span)
{ {
Span<Vector4> vectorSpan = memory.Span; int length = span.Length;
int length = vectorSpan.Length; ref Vector4 vectorSpanRef = ref MemoryMarshal.GetReference(span);
ref Vector4 vectorSpanRef = ref MemoryMarshal.GetReference(vectorSpan);
for (int y = rows.Min; y < rows.Max; y++) Span<TPixel> targetRowSpan = this.targetPixels.GetRowSpan(y).Slice(this.bounds.X);
{ PixelOperations<TPixel>.Instance.ToVector4(this.configuration, targetRowSpan.Slice(0, length), span);
Span<TPixel> targetRowSpan = this.targetPixels.GetRowSpan(y).Slice(this.bounds.X);
PixelOperations<TPixel>.Instance.ToVector4(this.configuration, targetRowSpan.Slice(0, length), vectorSpan);
if (this.preserveAlpha) if (this.preserveAlpha)
{
for (int x = 0; x < this.bounds.Width; x++)
{ {
for (int x = 0; x < this.bounds.Width; x++) DenseMatrixUtils.Convolve2D3(
{ in this.kernelY,
DenseMatrixUtils.Convolve2D3( in this.kernelX,
in this.kernelY, this.sourcePixels,
in this.kernelX, ref vectorSpanRef,
this.sourcePixels, y,
ref vectorSpanRef, x,
y, this.bounds.Y,
x, this.maxY,
this.bounds.Y, this.bounds.X,
this.maxY, this.maxX);
this.bounds.X,
this.maxX);
}
} }
else }
else
{
for (int x = 0; x < this.bounds.Width; x++)
{ {
for (int x = 0; x < this.bounds.Width; x++) DenseMatrixUtils.Convolve2D4(
{ in this.kernelY,
DenseMatrixUtils.Convolve2D4( in this.kernelX,
in this.kernelY, this.sourcePixels,
in this.kernelX, ref vectorSpanRef,
this.sourcePixels, y,
ref vectorSpanRef, x,
y, this.bounds.Y,
x, this.maxY,
this.bounds.Y, this.bounds.X,
this.maxY, this.maxX);
this.bounds.X,
this.maxX);
}
} }
PixelOperations<TPixel>.Instance.FromVector4Destructive(this.configuration, vectorSpan, targetRowSpan);
} }
PixelOperations<TPixel>.Instance.FromVector4Destructive(this.configuration, span, targetRowSpan);
} }
} }
} }

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

@ -64,22 +64,22 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds()); var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds());
// Horizontal convolution // Horizontal convolution
ParallelRowIterator.IterateRows<RowIntervalAction, Vector4>( ParallelRowIterator.IterateRows2<RowAction, Vector4>(
interest, interest,
this.Configuration, this.Configuration,
new RowIntervalAction(interest, firstPassPixels, source.PixelBuffer, this.KernelX, this.Configuration, this.PreserveAlpha)); new RowAction(interest, firstPassPixels, source.PixelBuffer, this.KernelX, this.Configuration, this.PreserveAlpha));
// Vertical convolution // Vertical convolution
ParallelRowIterator.IterateRows<RowIntervalAction, Vector4>( ParallelRowIterator.IterateRows2<RowAction, Vector4>(
interest, interest,
this.Configuration, this.Configuration,
new RowIntervalAction(interest, source.PixelBuffer, firstPassPixels, this.KernelY, this.Configuration, this.PreserveAlpha)); new RowAction(interest, source.PixelBuffer, firstPassPixels, this.KernelY, this.Configuration, this.PreserveAlpha));
} }
/// <summary> /// <summary>
/// A <see langword="struct"/> implementing the convolution logic for <see cref="Convolution2PassProcessor{T}"/>. /// A <see langword="struct"/> implementing the convolution logic for <see cref="Convolution2PassProcessor{T}"/>.
/// </summary> /// </summary>
private readonly struct RowIntervalAction : IRowIntervalAction<Vector4> private readonly struct RowAction : IRowAction<Vector4>
{ {
private readonly Rectangle bounds; private readonly Rectangle bounds;
private readonly Buffer2D<TPixel> targetPixels; private readonly Buffer2D<TPixel> targetPixels;
@ -89,7 +89,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
private readonly bool preserveAlpha; private readonly bool preserveAlpha;
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public RowIntervalAction( public RowAction(
Rectangle bounds, Rectangle bounds,
Buffer2D<TPixel> targetPixels, Buffer2D<TPixel> targetPixels,
Buffer2D<TPixel> sourcePixels, Buffer2D<TPixel> sourcePixels,
@ -107,55 +107,51 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public void Invoke(in RowInterval rows, Memory<Vector4> memory) public void Invoke(int y, Span<Vector4> span)
{ {
Span<Vector4> vectorSpan = memory.Span; int length = span.Length;
int length = vectorSpan.Length; ref Vector4 vectorSpanRef = ref MemoryMarshal.GetReference(span);
ref Vector4 vectorSpanRef = ref MemoryMarshal.GetReference(vectorSpan);
int maxY = this.bounds.Bottom - 1; int maxY = this.bounds.Bottom - 1;
int maxX = this.bounds.Right - 1; int maxX = this.bounds.Right - 1;
for (int y = rows.Min; y < rows.Max; y++) Span<TPixel> targetRowSpan = this.targetPixels.GetRowSpan(y).Slice(this.bounds.X);
{ PixelOperations<TPixel>.Instance.ToVector4(this.configuration, targetRowSpan.Slice(0, length), span);
Span<TPixel> targetRowSpan = this.targetPixels.GetRowSpan(y).Slice(this.bounds.X);
PixelOperations<TPixel>.Instance.ToVector4(this.configuration, targetRowSpan.Slice(0, length), vectorSpan);
if (this.preserveAlpha) if (this.preserveAlpha)
{
for (int x = 0; x < this.bounds.Width; x++)
{ {
for (int x = 0; x < this.bounds.Width; x++) DenseMatrixUtils.Convolve3(
{ in this.kernel,
DenseMatrixUtils.Convolve3( this.sourcePixels,
in this.kernel, ref vectorSpanRef,
this.sourcePixels, y,
ref vectorSpanRef, x,
y, this.bounds.Y,
x, maxY,
this.bounds.Y, this.bounds.X,
maxY, maxX);
this.bounds.X,
maxX);
}
} }
else }
else
{
for (int x = 0; x < this.bounds.Width; x++)
{ {
for (int x = 0; x < this.bounds.Width; x++) DenseMatrixUtils.Convolve4(
{ in this.kernel,
DenseMatrixUtils.Convolve4( this.sourcePixels,
in this.kernel, ref vectorSpanRef,
this.sourcePixels, y,
ref vectorSpanRef, x,
y, this.bounds.Y,
x, maxY,
this.bounds.Y, this.bounds.X,
maxY, maxX);
this.bounds.X,
maxX);
}
} }
PixelOperations<TPixel>.Instance.FromVector4Destructive(this.configuration, vectorSpan, targetRowSpan);
} }
PixelOperations<TPixel>.Instance.FromVector4Destructive(this.configuration, span, targetRowSpan);
} }
} }
} }

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

@ -57,10 +57,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds()); var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds());
ParallelRowIterator.IterateRows<RowIntervalAction, Vector4>( ParallelRowIterator.IterateRows2<RowAction, Vector4>(
interest, interest,
this.Configuration, this.Configuration,
new RowIntervalAction(interest, targetPixels, source.PixelBuffer, this.KernelXY, this.Configuration, this.PreserveAlpha)); new RowAction(interest, targetPixels, source.PixelBuffer, this.KernelXY, this.Configuration, this.PreserveAlpha));
Buffer2D<TPixel>.SwapOrCopyContent(source.PixelBuffer, targetPixels); Buffer2D<TPixel>.SwapOrCopyContent(source.PixelBuffer, targetPixels);
} }
@ -68,7 +68,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// <summary> /// <summary>
/// A <see langword="struct"/> implementing the convolution logic for <see cref="ConvolutionProcessor{T}"/>. /// A <see langword="struct"/> implementing the convolution logic for <see cref="ConvolutionProcessor{T}"/>.
/// </summary> /// </summary>
private readonly struct RowIntervalAction : IRowIntervalAction<Vector4> private readonly struct RowAction : IRowAction<Vector4>
{ {
private readonly Rectangle bounds; private readonly Rectangle bounds;
private readonly int maxY; private readonly int maxY;
@ -80,7 +80,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
private readonly bool preserveAlpha; private readonly bool preserveAlpha;
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public RowIntervalAction( public RowAction(
Rectangle bounds, Rectangle bounds,
Buffer2D<TPixel> targetPixels, Buffer2D<TPixel> targetPixels,
Buffer2D<TPixel> sourcePixels, Buffer2D<TPixel> sourcePixels,
@ -100,52 +100,48 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public void Invoke(in RowInterval rows, Memory<Vector4> memory) public void Invoke(int y, Span<Vector4> span)
{ {
Span<Vector4> vectorSpan = memory.Span; int length = span.Length;
int length = vectorSpan.Length; ref Vector4 vectorSpanRef = ref MemoryMarshal.GetReference(span);
ref Vector4 vectorSpanRef = ref MemoryMarshal.GetReference(vectorSpan);
for (int y = rows.Min; y < rows.Max; y++) Span<TPixel> targetRowSpan = this.targetPixels.GetRowSpan(y).Slice(this.bounds.X);
{ PixelOperations<TPixel>.Instance.ToVector4(this.configuration, targetRowSpan.Slice(0, length), span);
Span<TPixel> targetRowSpan = this.targetPixels.GetRowSpan(y).Slice(this.bounds.X);
PixelOperations<TPixel>.Instance.ToVector4(this.configuration, targetRowSpan.Slice(0, length), vectorSpan);
if (this.preserveAlpha) if (this.preserveAlpha)
{
for (int x = 0; x < this.bounds.Width; x++)
{ {
for (int x = 0; x < this.bounds.Width; x++) DenseMatrixUtils.Convolve3(
{ in this.kernel,
DenseMatrixUtils.Convolve3( this.sourcePixels,
in this.kernel, ref vectorSpanRef,
this.sourcePixels, y,
ref vectorSpanRef, x,
y, this.bounds.Y,
x, this.maxY,
this.bounds.Y, this.bounds.X,
this.maxY, this.maxX);
this.bounds.X,
this.maxX);
}
} }
else }
else
{
for (int x = 0; x < this.bounds.Width; x++)
{ {
for (int x = 0; x < this.bounds.Width; x++) DenseMatrixUtils.Convolve4(
{ in this.kernel,
DenseMatrixUtils.Convolve4( this.sourcePixels,
in this.kernel, ref vectorSpanRef,
this.sourcePixels, y,
ref vectorSpanRef, x,
y, this.bounds.Y,
x, this.maxY,
this.bounds.Y, this.bounds.X,
this.maxY, this.maxX);
this.bounds.X,
this.maxX);
}
} }
PixelOperations<TPixel>.Instance.FromVector4Destructive(this.configuration, vectorSpan, targetRowSpan);
} }
PixelOperations<TPixel>.Instance.FromVector4Destructive(this.configuration, span, targetRowSpan);
} }
} }
} }

27
src/ImageSharp/Processing/Processors/Effects/PixelRowDelegateProcessor{TPixel,TDelegate}.cs

@ -5,7 +5,6 @@ using System;
using System.Numerics; using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Processing.Processors.Effects namespace SixLabors.ImageSharp.Processing.Processors.Effects
@ -51,16 +50,16 @@ namespace SixLabors.ImageSharp.Processing.Processors.Effects
{ {
var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds()); var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds());
ParallelRowIterator.IterateRows<RowIntervalAction, Vector4>( ParallelRowIterator.IterateRows2<RowAction, Vector4>(
interest, interest,
this.Configuration, this.Configuration,
new RowIntervalAction(interest.X, source, this.Configuration, this.modifiers, this.rowDelegate)); new RowAction(interest.X, source, this.Configuration, this.modifiers, this.rowDelegate));
} }
/// <summary> /// <summary>
/// A <see langword="struct"/> implementing the convolution logic for <see cref="PixelRowDelegateProcessor{TPixel,TDelegate}"/>. /// A <see langword="struct"/> implementing the convolution logic for <see cref="PixelRowDelegateProcessor{TPixel,TDelegate}"/>.
/// </summary> /// </summary>
private readonly struct RowIntervalAction : IRowIntervalAction<Vector4> private readonly struct RowAction : IRowAction<Vector4>
{ {
private readonly int startX; private readonly int startX;
private readonly ImageFrame<TPixel> source; private readonly ImageFrame<TPixel> source;
@ -69,7 +68,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Effects
private readonly TDelegate rowProcessor; private readonly TDelegate rowProcessor;
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public RowIntervalAction( public RowAction(
int startX, int startX,
ImageFrame<TPixel> source, ImageFrame<TPixel> source,
Configuration configuration, Configuration configuration,
@ -85,20 +84,16 @@ namespace SixLabors.ImageSharp.Processing.Processors.Effects
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public void Invoke(in RowInterval rows, Memory<Vector4> memory) public void Invoke(int y, Span<Vector4> span)
{ {
for (int y = rows.Min; y < rows.Max; y++) int length = span.Length;
{ Span<TPixel> rowSpan = this.source.GetPixelRowSpan(y).Slice(this.startX, length);
Span<Vector4> vectorSpan = memory.Span; PixelOperations<TPixel>.Instance.ToVector4(this.configuration, rowSpan, span, this.modifiers);
int length = vectorSpan.Length;
Span<TPixel> rowSpan = this.source.GetPixelRowSpan(y).Slice(this.startX, length);
PixelOperations<TPixel>.Instance.ToVector4(this.configuration, rowSpan, vectorSpan, this.modifiers);
// Run the user defined pixel shader to the current row of pixels // Run the user defined pixel shader to the current row of pixels
Unsafe.AsRef(this.rowProcessor).Invoke(vectorSpan, new Point(this.startX, y)); Unsafe.AsRef(this.rowProcessor).Invoke(span, new Point(this.startX, y));
PixelOperations<TPixel>.Instance.FromVector4Destructive(this.configuration, vectorSpan, rowSpan, this.modifiers); PixelOperations<TPixel>.Instance.FromVector4Destructive(this.configuration, span, rowSpan, this.modifiers);
}
} }
} }
} }

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

@ -5,7 +5,6 @@ using System;
using System.Numerics; using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Processing.Processors.Filters namespace SixLabors.ImageSharp.Processing.Processors.Filters
@ -37,16 +36,16 @@ namespace SixLabors.ImageSharp.Processing.Processors.Filters
{ {
var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds()); var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds());
ParallelRowIterator.IterateRows<RowIntervalAction, Vector4>( ParallelRowIterator.IterateRows2<RowAction, Vector4>(
interest, interest,
this.Configuration, this.Configuration,
new RowIntervalAction(interest.X, source, this.definition.Matrix, this.Configuration)); new RowAction(interest.X, source, this.definition.Matrix, this.Configuration));
} }
/// <summary> /// <summary>
/// A <see langword="struct"/> implementing the convolution logic for <see cref="FilterProcessor{TPixel}"/>. /// A <see langword="struct"/> implementing the convolution logic for <see cref="FilterProcessor{TPixel}"/>.
/// </summary> /// </summary>
private readonly struct RowIntervalAction : IRowIntervalAction<Vector4> private readonly struct RowAction : IRowAction<Vector4>
{ {
private readonly int startX; private readonly int startX;
private readonly ImageFrame<TPixel> source; private readonly ImageFrame<TPixel> source;
@ -54,7 +53,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Filters
private readonly Configuration configuration; private readonly Configuration configuration;
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public RowIntervalAction( public RowAction(
int startX, int startX,
ImageFrame<TPixel> source, ImageFrame<TPixel> source,
ColorMatrix matrix, ColorMatrix matrix,
@ -68,19 +67,15 @@ namespace SixLabors.ImageSharp.Processing.Processors.Filters
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public void Invoke(in RowInterval rows, Memory<Vector4> memory) public void Invoke(int y, Span<Vector4> span)
{ {
for (int y = rows.Min; y < rows.Max; y++) int length = span.Length;
{ Span<TPixel> rowSpan = this.source.GetPixelRowSpan(y).Slice(this.startX, length);
Span<Vector4> vectorSpan = memory.Span; PixelOperations<TPixel>.Instance.ToVector4(this.configuration, rowSpan, span);
int length = vectorSpan.Length;
Span<TPixel> rowSpan = this.source.GetPixelRowSpan(y).Slice(this.startX, length);
PixelOperations<TPixel>.Instance.ToVector4(this.configuration, rowSpan, vectorSpan);
Vector4Utils.Transform(vectorSpan, ref Unsafe.AsRef(this.matrix)); Vector4Utils.Transform(span, ref Unsafe.AsRef(this.matrix));
PixelOperations<TPixel>.Instance.FromVector4Destructive(this.configuration, vectorSpan, rowSpan); PixelOperations<TPixel>.Instance.FromVector4Destructive(this.configuration, span, rowSpan);
}
} }
} }
} }

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

@ -55,13 +55,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays
using IMemoryOwner<TPixel> rowColors = allocator.Allocate<TPixel>(interest.Width); using IMemoryOwner<TPixel> rowColors = allocator.Allocate<TPixel>(interest.Width);
rowColors.GetSpan().Fill(glowColor); rowColors.GetSpan().Fill(glowColor);
ParallelRowIterator.IterateRows<RowIntervalAction, float>( ParallelRowIterator.IterateRows2<RowAction, float>(
interest, interest,
configuration, configuration,
new RowIntervalAction(configuration, interest, rowColors, this.blender, center, maxDistance, blendPercent, source)); new RowAction(configuration, interest, rowColors, this.blender, center, maxDistance, blendPercent, source));
} }
private readonly struct RowIntervalAction : IRowIntervalAction<float> private readonly struct RowAction : IRowAction<float>
{ {
private readonly Configuration configuration; private readonly Configuration configuration;
private readonly Rectangle bounds; private readonly Rectangle bounds;
@ -73,7 +73,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays
private readonly ImageFrame<TPixel> source; private readonly ImageFrame<TPixel> source;
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public RowIntervalAction( public RowAction(
Configuration configuration, Configuration configuration,
Rectangle bounds, Rectangle bounds,
IMemoryOwner<TPixel> colors, IMemoryOwner<TPixel> colors,
@ -94,28 +94,24 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays
} }
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public void Invoke(in RowInterval rows, Memory<float> memory) public void Invoke(int y, Span<float> span)
{ {
Span<float> amountsSpan = memory.Span;
Span<TPixel> colorSpan = this.colors.GetSpan(); Span<TPixel> colorSpan = this.colors.GetSpan();
for (int y = rows.Min; y < rows.Max; y++) for (int i = 0; i < this.bounds.Width; i++)
{ {
for (int i = 0; i < this.bounds.Width; i++) float distance = Vector2.Distance(this.center, new Vector2(i + this.bounds.X, y));
{ span[i] = (this.blendPercent * (1 - (.95F * (distance / this.maxDistance)))).Clamp(0, 1);
float distance = Vector2.Distance(this.center, new Vector2(i + this.bounds.X, y)); }
amountsSpan[i] = (this.blendPercent * (1 - (.95F * (distance / this.maxDistance)))).Clamp(0, 1);
}
Span<TPixel> destination = this.source.GetPixelRowSpan(y).Slice(this.bounds.X, this.bounds.Width); Span<TPixel> destination = this.source.GetPixelRowSpan(y).Slice(this.bounds.X, this.bounds.Width);
this.blender.Blend( this.blender.Blend(
this.configuration, this.configuration,
destination, destination,
destination, destination,
colorSpan, colorSpan,
amountsSpan); span);
}
} }
} }
} }

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

@ -63,13 +63,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays
using IMemoryOwner<TPixel> rowColors = allocator.Allocate<TPixel>(interest.Width); using IMemoryOwner<TPixel> rowColors = allocator.Allocate<TPixel>(interest.Width);
rowColors.GetSpan().Fill(vignetteColor); rowColors.GetSpan().Fill(vignetteColor);
ParallelRowIterator.IterateRows<RowIntervalAction, float>( ParallelRowIterator.IterateRows2<RowAction, float>(
interest, interest,
configuration, configuration,
new RowIntervalAction(configuration, interest, rowColors, this.blender, center, maxDistance, blendPercent, source)); new RowAction(configuration, interest, rowColors, this.blender, center, maxDistance, blendPercent, source));
} }
private readonly struct RowIntervalAction : IRowIntervalAction<float> private readonly struct RowAction : IRowAction<float>
{ {
private readonly Configuration configuration; private readonly Configuration configuration;
private readonly Rectangle bounds; private readonly Rectangle bounds;
@ -81,7 +81,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays
private readonly ImageFrame<TPixel> source; private readonly ImageFrame<TPixel> source;
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public RowIntervalAction( public RowAction(
Configuration configuration, Configuration configuration,
Rectangle bounds, Rectangle bounds,
IMemoryOwner<TPixel> colors, IMemoryOwner<TPixel> colors,
@ -102,28 +102,24 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays
} }
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public void Invoke(in RowInterval rows, Memory<float> memory) public void Invoke(int y, Span<float> span)
{ {
Span<float> amountsSpan = memory.Span;
Span<TPixel> colorSpan = this.colors.GetSpan(); Span<TPixel> colorSpan = this.colors.GetSpan();
for (int y = rows.Min; y < rows.Max; y++) for (int i = 0; i < this.bounds.Width; i++)
{ {
for (int i = 0; i < this.bounds.Width; i++) float distance = Vector2.Distance(this.center, new Vector2(i + this.bounds.X, y));
{ span[i] = (this.blendPercent * (.9F * (distance / this.maxDistance))).Clamp(0, 1);
float distance = Vector2.Distance(this.center, new Vector2(i + this.bounds.X, y));
amountsSpan[i] = (this.blendPercent * (.9F * (distance / this.maxDistance))).Clamp(0, 1);
}
Span<TPixel> destination = this.source.GetPixelRowSpan(y).Slice(this.bounds.X, this.bounds.Width);
this.blender.Blend(
this.configuration,
destination,
destination,
colorSpan,
amountsSpan);
} }
Span<TPixel> destination = this.source.GetPixelRowSpan(y).Slice(this.bounds.X, this.bounds.Width);
this.blender.Blend(
this.configuration,
destination,
destination,
colorSpan,
span);
} }
} }
} }

58
src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor{TPixel}.cs

@ -5,7 +5,6 @@ using System;
using System.Numerics; using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Processing.Processors.Transforms namespace SixLabors.ImageSharp.Processing.Processors.Transforms
@ -68,10 +67,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
using var kernelMap = new TransformKernelMap(configuration, source.Size(), destination.Size(), this.resampler); using var kernelMap = new TransformKernelMap(configuration, source.Size(), destination.Size(), this.resampler);
ParallelRowIterator.IterateRows<RowIntervalAction, Vector4>( ParallelRowIterator.IterateRows2<RowAction, Vector4>(
targetBounds, targetBounds,
configuration, configuration,
new RowIntervalAction(configuration, kernelMap, ref matrix, width, source, destination)); new RowAction(configuration, kernelMap, ref matrix, width, source, destination));
} }
/// <summary> /// <summary>
@ -101,7 +100,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
} }
/// <inheritdoc/> /// <inheritdoc/>
/// <param name="rows"></param>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public void Invoke(int y) public void Invoke(int y)
{ {
@ -121,7 +119,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
/// <summary> /// <summary>
/// A <see langword="struct"/> implementing the transformation logic for <see cref="AffineTransformProcessor{T}"/>. /// A <see langword="struct"/> implementing the transformation logic for <see cref="AffineTransformProcessor{T}"/>.
/// </summary> /// </summary>
private readonly struct RowIntervalAction : IRowIntervalAction<Vector4> private readonly struct RowAction : IRowAction<Vector4>
{ {
private readonly Configuration configuration; private readonly Configuration configuration;
private readonly TransformKernelMap kernelMap; private readonly TransformKernelMap kernelMap;
@ -131,7 +129,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
private readonly ImageFrame<TPixel> destination; private readonly ImageFrame<TPixel> destination;
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public RowIntervalAction( public RowAction(
Configuration configuration, Configuration configuration,
TransformKernelMap kernelMap, TransformKernelMap kernelMap,
ref Matrix3x2 matrix, ref Matrix3x2 matrix,
@ -149,35 +147,31 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public void Invoke(in RowInterval rows, Memory<Vector4> memory) public void Invoke(int y, Span<Vector4> span)
{ {
Span<Vector4> vectorSpan = memory.Span; Span<TPixel> targetRowSpan = this.destination.GetPixelRowSpan(y);
for (int y = rows.Min; y < rows.Max; y++) PixelOperations<TPixel>.Instance.ToVector4(this.configuration, targetRowSpan, span);
{ ref float ySpanRef = ref this.kernelMap.GetYStartReference(y);
Span<TPixel> targetRowSpan = this.destination.GetPixelRowSpan(y); ref float xSpanRef = ref this.kernelMap.GetXStartReference(y);
PixelOperations<TPixel>.Instance.ToVector4(this.configuration, targetRowSpan, vectorSpan);
ref float ySpanRef = ref this.kernelMap.GetYStartReference(y);
ref float xSpanRef = ref this.kernelMap.GetXStartReference(y);
for (int x = 0; x < this.maxX; x++)
{
// Use the single precision position to calculate correct bounding pixels
// otherwise we get rogue pixels outside of the bounds.
var point = Vector2.Transform(new Vector2(x, y), this.matrix);
this.kernelMap.Convolve(
point,
x,
ref ySpanRef,
ref xSpanRef,
this.source.PixelBuffer,
vectorSpan);
}
PixelOperations<TPixel>.Instance.FromVector4Destructive( for (int x = 0; x < this.maxX; x++)
this.configuration, {
vectorSpan, // Use the single precision position to calculate correct bounding pixels
targetRowSpan); // otherwise we get rogue pixels outside of the bounds.
var point = Vector2.Transform(new Vector2(x, y), this.matrix);
this.kernelMap.Convolve(
point,
x,
ref ySpanRef,
ref xSpanRef,
this.source.PixelBuffer,
span);
} }
PixelOperations<TPixel>.Instance.FromVector4Destructive(
this.configuration,
span,
targetRowSpan);
} }
} }
} }

69
src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor{TPixel}.cs

@ -5,7 +5,6 @@ using System;
using System.Numerics; using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Processing.Processors.Transforms namespace SixLabors.ImageSharp.Processing.Processors.Transforms
@ -17,9 +16,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
internal class ProjectiveTransformProcessor<TPixel> : TransformProcessor<TPixel> internal class ProjectiveTransformProcessor<TPixel> : TransformProcessor<TPixel>
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
private Size targetSize; private readonly Size targetSize;
private readonly IResampler resampler; private readonly IResampler resampler;
private Matrix4x4 transformMatrix; private readonly Matrix4x4 transformMatrix;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="ProjectiveTransformProcessor{TPixel}"/> class. /// Initializes a new instance of the <see cref="ProjectiveTransformProcessor{TPixel}"/> class.
@ -70,12 +69,15 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
using var kernelMap = new TransformKernelMap(configuration, source.Size(), destination.Size(), this.resampler); using var kernelMap = new TransformKernelMap(configuration, source.Size(), destination.Size(), this.resampler);
ParallelRowIterator.IterateRows<RowIntervalAction, Vector4>( ParallelRowIterator.IterateRows2<RowAction, Vector4>(
targetBounds, targetBounds,
configuration, configuration,
new RowIntervalAction(configuration, kernelMap, ref matrix, width, source, destination)); new RowAction(configuration, kernelMap, ref matrix, width, source, destination));
} }
/// <summary>
/// A <see langword="struct"/> implementing the nearest neighbor interpolation logic for <see cref="ProjectiveTransformProcessor{T}"/>.
/// </summary>
private readonly struct NearestNeighborRowAction : IRowAction private readonly struct NearestNeighborRowAction : IRowAction
{ {
private readonly Rectangle bounds; private readonly Rectangle bounds;
@ -99,6 +101,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
this.destination = destination; this.destination = destination;
} }
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public void Invoke(int y) public void Invoke(int y)
{ {
@ -118,7 +121,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
} }
} }
private readonly struct RowIntervalAction : IRowIntervalAction<Vector4> /// <summary>
/// A <see langword="struct"/> implementing the convolution logic for <see cref="ProjectiveTransformProcessor{T}"/>.
/// </summary>
private readonly struct RowAction : IRowAction<Vector4>
{ {
private readonly Configuration configuration; private readonly Configuration configuration;
private readonly TransformKernelMap kernelMap; private readonly TransformKernelMap kernelMap;
@ -128,7 +134,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
private readonly ImageFrame<TPixel> destination; private readonly ImageFrame<TPixel> destination;
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public RowIntervalAction( public RowAction(
Configuration configuration, Configuration configuration,
TransformKernelMap kernelMap, TransformKernelMap kernelMap,
ref Matrix4x4 matrix, ref Matrix4x4 matrix,
@ -144,36 +150,33 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
this.destination = destination; this.destination = destination;
} }
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public void Invoke(in RowInterval rows, Memory<Vector4> memory) public void Invoke(int y, Span<Vector4> span)
{ {
Span<Vector4> vectorSpan = memory.Span; Span<TPixel> targetRowSpan = this.destination.GetPixelRowSpan(y);
for (int y = rows.Min; y < rows.Max; y++) PixelOperations<TPixel>.Instance.ToVector4(this.configuration, targetRowSpan, span);
{ ref float ySpanRef = ref this.kernelMap.GetYStartReference(y);
Span<TPixel> targetRowSpan = this.destination.GetPixelRowSpan(y); ref float xSpanRef = ref this.kernelMap.GetXStartReference(y);
PixelOperations<TPixel>.Instance.ToVector4(this.configuration, targetRowSpan, vectorSpan);
ref float ySpanRef = ref this.kernelMap.GetYStartReference(y);
ref float xSpanRef = ref this.kernelMap.GetXStartReference(y);
for (int x = 0; x < this.maxX; x++)
{
// Use the single precision position to calculate correct bounding pixels
// otherwise we get rogue pixels outside of the bounds.
Vector2 point = TransformUtils.ProjectiveTransform2D(x, y, this.matrix);
this.kernelMap.Convolve(
point,
x,
ref ySpanRef,
ref xSpanRef,
this.source.PixelBuffer,
vectorSpan);
}
PixelOperations<TPixel>.Instance.FromVector4Destructive( for (int x = 0; x < this.maxX; x++)
this.configuration, {
vectorSpan, // Use the single precision position to calculate correct bounding pixels
targetRowSpan); // otherwise we get rogue pixels outside of the bounds.
Vector2 point = TransformUtils.ProjectiveTransform2D(x, y, this.matrix);
this.kernelMap.Convolve(
point,
x,
ref ySpanRef,
ref xSpanRef,
this.source.PixelBuffer,
span);
} }
PixelOperations<TPixel>.Instance.FromVector4Destructive(
this.configuration,
span,
targetRowSpan);
} }
} }
} }

Loading…
Cancel
Save