Browse Source

Use ParallelRowIterator for BokehBlur

pull/3113/head
James Jackson-South 1 month ago
parent
commit
0220108d86
  1. 70
      src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor{TPixel}.cs

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

@ -1,7 +1,6 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Six Labors Split License. // Licensed under the Six Labors Split License.
using System.Buffers;
using System.Numerics; using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
@ -79,36 +78,22 @@ internal class BokehBlurProcessor<TPixel> : ImageProcessor<TPixel>
{ {
Rectangle sourceRectangle = Rectangle.Intersect(this.SourceRectangle, source.Bounds); Rectangle sourceRectangle = Rectangle.Intersect(this.SourceRectangle, source.Bounds);
MemoryAllocator allocator = this.Configuration.MemoryAllocator;
// Convolution is memory-bandwidth-bound with low arithmetic intensity.
// Parallelization degrades performance due to cache line contention from
// overlapping source row reads. See #3111.
// Preliminary gamma highlight pass // Preliminary gamma highlight pass
if (this.gamma == 3F) if (this.gamma == 3F)
{ {
ApplyGamma3ExposureRowOperation gammaOperation = new(sourceRectangle, source.PixelBuffer, this.Configuration); ApplyGamma3ExposureRowOperation gammaOperation = new(sourceRectangle, source.PixelBuffer, this.Configuration);
ParallelRowIterator.IterateRows<ApplyGamma3ExposureRowOperation, Vector4>(
using IMemoryOwner<Vector4> gammaBuffer = allocator.Allocate<Vector4>(gammaOperation.GetRequiredBufferLength(sourceRectangle)); this.Configuration,
Span<Vector4> gammaSpan = gammaBuffer.Memory.Span; sourceRectangle,
in gammaOperation);
for (int y = sourceRectangle.Top; y < sourceRectangle.Bottom; y++)
{
gammaOperation.Invoke(y, gammaSpan);
}
} }
else else
{ {
ApplyGammaExposureRowOperation gammaOperation = new(sourceRectangle, source.PixelBuffer, this.Configuration, this.gamma); ApplyGammaExposureRowOperation gammaOperation = new(sourceRectangle, source.PixelBuffer, this.Configuration, this.gamma);
ParallelRowIterator.IterateRows<ApplyGammaExposureRowOperation, Vector4>(
using IMemoryOwner<Vector4> gammaBuffer = allocator.Allocate<Vector4>(gammaOperation.GetRequiredBufferLength(sourceRectangle)); this.Configuration,
Span<Vector4> gammaSpan = gammaBuffer.Memory.Span; sourceRectangle,
in gammaOperation);
for (int y = sourceRectangle.Top; y < sourceRectangle.Bottom; y++)
{
gammaOperation.Invoke(y, gammaSpan);
}
} }
// 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
@ -121,20 +106,18 @@ internal class BokehBlurProcessor<TPixel> : ImageProcessor<TPixel>
if (this.gamma == 3F) if (this.gamma == 3F)
{ {
ApplyInverseGamma3ExposureRowOperation operation = new(sourceRectangle, source.PixelBuffer, processingBuffer, this.Configuration); ApplyInverseGamma3ExposureRowOperation operation = new(sourceRectangle, source.PixelBuffer, processingBuffer, this.Configuration);
ParallelRowIterator.IterateRows(
for (int y = sourceRectangle.Top; y < sourceRectangle.Bottom; y++) this.Configuration,
{ sourceRectangle,
operation.Invoke(y); in operation);
}
} }
else else
{ {
ApplyInverseGammaExposureRowOperation operation = new(sourceRectangle, source.PixelBuffer, processingBuffer, this.Configuration, this.gamma); ApplyInverseGammaExposureRowOperation operation = new(sourceRectangle, source.PixelBuffer, processingBuffer, this.Configuration, this.gamma);
ParallelRowIterator.IterateRows(
for (int y = sourceRectangle.Top; y < sourceRectangle.Bottom; y++) this.Configuration,
{ sourceRectangle,
operation.Invoke(y); in operation);
}
} }
} }
@ -187,15 +170,10 @@ internal class BokehBlurProcessor<TPixel> : ImageProcessor<TPixel>
kernel, kernel,
configuration); configuration);
using (IMemoryOwner<Vector4> hBuffer = configuration.MemoryAllocator.Allocate<Vector4>(horizontalOperation.GetRequiredBufferLength(sourceRectangle))) ParallelRowIterator.IterateRows<FirstPassConvolutionRowOperation, Vector4>(
{ configuration,
Span<Vector4> hSpan = hBuffer.Memory.Span; sourceRectangle,
in horizontalOperation);
for (int y = sourceRectangle.Top; y < sourceRectangle.Bottom; y++)
{
horizontalOperation.Invoke(y, hSpan);
}
}
// Vertical 1D convolutions to accumulate the partial results on the target buffer // Vertical 1D convolutions to accumulate the partial results on the target buffer
BokehBlurProcessor.SecondPassConvolutionRowOperation verticalOperation = new( BokehBlurProcessor.SecondPassConvolutionRowOperation verticalOperation = new(
@ -207,10 +185,10 @@ internal class BokehBlurProcessor<TPixel> : ImageProcessor<TPixel>
parameters.Z, parameters.Z,
parameters.W); parameters.W);
for (int y = sourceRectangle.Top; y < sourceRectangle.Bottom; y++) ParallelRowIterator.IterateRows(
{ configuration,
verticalOperation.Invoke(y); sourceRectangle,
} in verticalOperation);
} }
} }

Loading…
Cancel
Save