|
|
|
@ -282,10 +282,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution |
|
|
|
float inverseGamma = 1 / this.gamma; |
|
|
|
|
|
|
|
// Apply the inverse gamma exposure pass, and write the final pixel data
|
|
|
|
ParallelRowIterator.IterateRows( |
|
|
|
ParallelRowIterator.IterateRows2( |
|
|
|
this.SourceRectangle, |
|
|
|
this.Configuration, |
|
|
|
new ApplyInverseGammaExposureRowIntervalAction(this.SourceRectangle, source.PixelBuffer, processingBuffer, this.Configuration, inverseGamma)); |
|
|
|
new ApplyInverseGammaExposureRowAction(this.SourceRectangle, source.PixelBuffer, processingBuffer, this.Configuration, inverseGamma)); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
@ -314,23 +314,23 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution |
|
|
|
Vector4 parameters = Unsafe.Add(ref paramsRef, i); |
|
|
|
|
|
|
|
// Compute the vertical 1D convolution
|
|
|
|
ParallelRowIterator.IterateRows( |
|
|
|
ParallelRowIterator.IterateRows2( |
|
|
|
sourceRectangle, |
|
|
|
configuration, |
|
|
|
new ApplyVerticalConvolutionRowIntervalAction(ref sourceRectangle, firstPassBuffer, source.PixelBuffer, kernel)); |
|
|
|
new ApplyVerticalConvolutionRowAction(ref sourceRectangle, firstPassBuffer, source.PixelBuffer, kernel)); |
|
|
|
|
|
|
|
// Compute the horizontal 1D convolutions and accumulate the partial results on the target buffer
|
|
|
|
ParallelRowIterator.IterateRows( |
|
|
|
ParallelRowIterator.IterateRows2( |
|
|
|
sourceRectangle, |
|
|
|
configuration, |
|
|
|
new ApplyHorizontalConvolutionRowIntervalAction(ref sourceRectangle, processingBuffer, firstPassBuffer, kernel, parameters.Z, parameters.W)); |
|
|
|
new ApplyHorizontalConvolutionRowAction(ref sourceRectangle, processingBuffer, firstPassBuffer, kernel, parameters.Z, parameters.W)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// A <see langword="struct"/> implementing the vertical convolution logic for <see cref="BokehBlurProcessor{T}"/>.
|
|
|
|
/// </summary>
|
|
|
|
private readonly struct ApplyVerticalConvolutionRowIntervalAction : IRowIntervalAction |
|
|
|
private readonly struct ApplyVerticalConvolutionRowAction : IRowAction |
|
|
|
{ |
|
|
|
private readonly Rectangle bounds; |
|
|
|
private readonly Buffer2D<ComplexVector4> targetValues; |
|
|
|
@ -340,7 +340,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution |
|
|
|
private readonly int maxX; |
|
|
|
|
|
|
|
[MethodImpl(InliningOptions.ShortMethod)] |
|
|
|
public ApplyVerticalConvolutionRowIntervalAction( |
|
|
|
public ApplyVerticalConvolutionRowAction( |
|
|
|
ref Rectangle bounds, |
|
|
|
Buffer2D<ComplexVector4> targetValues, |
|
|
|
Buffer2D<TPixel> sourcePixels, |
|
|
|
@ -356,16 +356,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution |
|
|
|
|
|
|
|
/// <inheritdoc/>
|
|
|
|
[MethodImpl(InliningOptions.ShortMethod)] |
|
|
|
public void Invoke(in RowInterval rows) |
|
|
|
public void Invoke(int y) |
|
|
|
{ |
|
|
|
for (int y = rows.Min; y < rows.Max; y++) |
|
|
|
{ |
|
|
|
Span<ComplexVector4> targetRowSpan = this.targetValues.GetRowSpan(y).Slice(this.bounds.X); |
|
|
|
Span<ComplexVector4> targetRowSpan = this.targetValues.GetRowSpan(y).Slice(this.bounds.X); |
|
|
|
|
|
|
|
for (int x = 0; x < this.bounds.Width; x++) |
|
|
|
{ |
|
|
|
Buffer2DUtils.Convolve4(this.kernel, this.sourcePixels, targetRowSpan, y, x, this.bounds.Y, this.maxY, this.bounds.X, this.maxX); |
|
|
|
} |
|
|
|
for (int x = 0; x < this.bounds.Width; x++) |
|
|
|
{ |
|
|
|
Buffer2DUtils.Convolve4(this.kernel, this.sourcePixels, targetRowSpan, y, x, this.bounds.Y, this.maxY, this.bounds.X, this.maxX); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
@ -373,7 +370,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution |
|
|
|
/// <summary>
|
|
|
|
/// A <see langword="struct"/> implementing the horizontal convolution logic for <see cref="BokehBlurProcessor{T}"/>.
|
|
|
|
/// </summary>
|
|
|
|
private readonly struct ApplyHorizontalConvolutionRowIntervalAction : IRowIntervalAction |
|
|
|
private readonly struct ApplyHorizontalConvolutionRowAction : IRowAction |
|
|
|
{ |
|
|
|
private readonly Rectangle bounds; |
|
|
|
private readonly Buffer2D<Vector4> targetValues; |
|
|
|
@ -385,7 +382,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution |
|
|
|
private readonly int maxX; |
|
|
|
|
|
|
|
[MethodImpl(InliningOptions.ShortMethod)] |
|
|
|
public ApplyHorizontalConvolutionRowIntervalAction( |
|
|
|
public ApplyHorizontalConvolutionRowAction( |
|
|
|
ref Rectangle bounds, |
|
|
|
Buffer2D<Vector4> targetValues, |
|
|
|
Buffer2D<ComplexVector4> sourceValues, |
|
|
|
@ -405,16 +402,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution |
|
|
|
|
|
|
|
/// <inheritdoc/>
|
|
|
|
[MethodImpl(InliningOptions.ShortMethod)] |
|
|
|
public void Invoke(in RowInterval rows) |
|
|
|
public void Invoke(int y) |
|
|
|
{ |
|
|
|
for (int y = rows.Min; y < rows.Max; y++) |
|
|
|
{ |
|
|
|
Span<Vector4> targetRowSpan = this.targetValues.GetRowSpan(y).Slice(this.bounds.X); |
|
|
|
Span<Vector4> targetRowSpan = this.targetValues.GetRowSpan(y).Slice(this.bounds.X); |
|
|
|
|
|
|
|
for (int x = 0; x < this.bounds.Width; x++) |
|
|
|
{ |
|
|
|
Buffer2DUtils.Convolve4AndAccumulatePartials(this.kernel, this.sourceValues, targetRowSpan, y, x, this.bounds.Y, this.maxY, this.bounds.X, this.maxX, this.z, this.w); |
|
|
|
} |
|
|
|
for (int x = 0; x < this.bounds.Width; x++) |
|
|
|
{ |
|
|
|
Buffer2DUtils.Convolve4AndAccumulatePartials(this.kernel, this.sourceValues, targetRowSpan, y, x, this.bounds.Y, this.maxY, this.bounds.X, this.maxX, this.z, this.w); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
@ -471,7 +465,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution |
|
|
|
/// <summary>
|
|
|
|
/// A <see langword="struct"/> implementing the inverse gamma exposure logic for <see cref="BokehBlurProcessor{T}"/>.
|
|
|
|
/// </summary>
|
|
|
|
private readonly struct ApplyInverseGammaExposureRowIntervalAction : IRowIntervalAction |
|
|
|
private readonly struct ApplyInverseGammaExposureRowAction : IRowAction |
|
|
|
{ |
|
|
|
private readonly Rectangle bounds; |
|
|
|
private readonly Buffer2D<TPixel> targetPixels; |
|
|
|
@ -480,7 +474,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution |
|
|
|
private readonly float inverseGamma; |
|
|
|
|
|
|
|
[MethodImpl(InliningOptions.ShortMethod)] |
|
|
|
public ApplyInverseGammaExposureRowIntervalAction( |
|
|
|
public ApplyInverseGammaExposureRowAction( |
|
|
|
Rectangle bounds, |
|
|
|
Buffer2D<TPixel> targetPixels, |
|
|
|
Buffer2D<Vector4> sourceValues, |
|
|
|
@ -496,28 +490,25 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution |
|
|
|
|
|
|
|
/// <inheritdoc/>
|
|
|
|
[MethodImpl(InliningOptions.ShortMethod)] |
|
|
|
public void Invoke(in RowInterval rows) |
|
|
|
public void Invoke(int y) |
|
|
|
{ |
|
|
|
Vector4 low = Vector4.Zero; |
|
|
|
var high = new Vector4(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity); |
|
|
|
|
|
|
|
for (int y = rows.Min; y < rows.Max; y++) |
|
|
|
{ |
|
|
|
Span<TPixel> targetPixelSpan = this.targetPixels.GetRowSpan(y).Slice(this.bounds.X); |
|
|
|
Span<Vector4> sourceRowSpan = this.sourceValues.GetRowSpan(y).Slice(this.bounds.X); |
|
|
|
ref Vector4 sourceRef = ref MemoryMarshal.GetReference(sourceRowSpan); |
|
|
|
|
|
|
|
for (int x = 0; x < this.bounds.Width; x++) |
|
|
|
{ |
|
|
|
ref Vector4 v = ref Unsafe.Add(ref sourceRef, x); |
|
|
|
var clamp = Vector4.Clamp(v, low, high); |
|
|
|
v.X = MathF.Pow(clamp.X, this.inverseGamma); |
|
|
|
v.Y = MathF.Pow(clamp.Y, this.inverseGamma); |
|
|
|
v.Z = MathF.Pow(clamp.Z, this.inverseGamma); |
|
|
|
} |
|
|
|
Span<TPixel> targetPixelSpan = this.targetPixels.GetRowSpan(y).Slice(this.bounds.X); |
|
|
|
Span<Vector4> sourceRowSpan = this.sourceValues.GetRowSpan(y).Slice(this.bounds.X); |
|
|
|
ref Vector4 sourceRef = ref MemoryMarshal.GetReference(sourceRowSpan); |
|
|
|
|
|
|
|
PixelOperations<TPixel>.Instance.FromVector4Destructive(this.configuration, sourceRowSpan.Slice(0, this.bounds.Width), targetPixelSpan, PixelConversionModifiers.Premultiply); |
|
|
|
for (int x = 0; x < this.bounds.Width; x++) |
|
|
|
{ |
|
|
|
ref Vector4 v = ref Unsafe.Add(ref sourceRef, x); |
|
|
|
var clamp = Vector4.Clamp(v, low, high); |
|
|
|
v.X = MathF.Pow(clamp.X, this.inverseGamma); |
|
|
|
v.Y = MathF.Pow(clamp.Y, this.inverseGamma); |
|
|
|
v.Z = MathF.Pow(clamp.Z, this.inverseGamma); |
|
|
|
} |
|
|
|
|
|
|
|
PixelOperations<TPixel>.Instance.FromVector4Destructive(this.configuration, sourceRowSpan.Slice(0, this.bounds.Width), targetPixelSpan, PixelConversionModifiers.Premultiply); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|