Browse Source

Specialize bokeh blur operations for 1D kernels

js/color-alpha-handling
Sergio Pedri 5 years ago
parent
commit
ca1a67a36c
  1. 34
      src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor.cs
  2. 46
      src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor{TPixel}.cs

34
src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor.cs

@ -127,39 +127,37 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
{ {
int boundsX = this.bounds.X; int boundsX = this.bounds.X;
int boundsWidth = this.bounds.Width; int boundsWidth = this.bounds.Width;
Span<Vector4> targetBuffer = this.targetValues.GetRowSpan(y); int kernelSize = this.kernel.Length;
var state = new ConvolutionState<Complex64>(this.kernel, this.kernel.Length, 1, this.map); Span<int> rowOffsets = this.map.GetRowOffsetSpan();
ref int sampleRowBase = ref state.GetSampleRow(y - this.bounds.Y); Span<int> columnOffsets = this.map.GetColumnOffsetSpan();
ref int sampleRowBase = ref Unsafe.Add(ref MemoryMarshal.GetReference(rowOffsets), (y - this.bounds.Y) * kernelSize);
ref int sampleColumnBase = ref MemoryMarshal.GetReference(columnOffsets);
// The target buffer is zeroed initially and then it accumulates the results // The target buffer is zeroed initially and then it accumulates the results
// of each partial convolution, so we don't have to clear it here as well. // of each partial convolution, so we don't have to clear it here as well
ref Vector4 targetBase = ref MemoryMarshal.GetReference(targetBuffer); Span<Vector4> targetBuffer = this.targetValues.GetRowSpan(y);
ReadOnlyKernel<Complex64> kernel = state.Kernel; ref Vector4 targetBase = ref MemoryMarshal.GetReference(targetBuffer);
ref Complex64 kernelBase = ref this.kernel[0];
for (int kY = 0; kY < kernel.Rows; kY++) for (int kY = 0; kY < kernelSize; kY++)
{ {
// Get the precalculated source sample row for this kernel row and copy to our buffer. // Get the precalculated source sample row for this kernel row and copy to our buffer
int sampleY = Unsafe.Add(ref sampleRowBase, kY); int sampleY = Unsafe.Add(ref sampleRowBase, kY);
Span<ComplexVector4> sourceRow = this.sourceValues.GetRowSpan(sampleY).Slice(boundsX, boundsWidth); Span<ComplexVector4> sourceRow = this.sourceValues.GetRowSpan(sampleY).Slice(boundsX, boundsWidth);
ref ComplexVector4 sourceBase = ref MemoryMarshal.GetReference(sourceRow); ref ComplexVector4 sourceBase = ref MemoryMarshal.GetReference(sourceRow);
Complex64 factor = Unsafe.Add(ref kernelBase, kY);
for (int x = 0; x < boundsWidth; x++) for (int x = 0; x < boundsWidth; x++)
{ {
ref int sampleColumnBase = ref state.GetSampleColumn(x); int sampleX = Unsafe.Add(ref sampleColumnBase, x) - boundsX;
ref Vector4 target = ref Unsafe.Add(ref targetBase, x); ref Vector4 target = ref Unsafe.Add(ref targetBase, x);
ComplexVector4 pixel4 = default;
for (int kX = 0; kX < kernel.Columns; kX++)
{
int sampleX = Unsafe.Add(ref sampleColumnBase, kX) - boundsX;
ComplexVector4 sample = Unsafe.Add(ref sourceBase, sampleX);
pixel4.Sum(kernel[kY, kX] * sample); ComplexVector4 sample = Unsafe.Add(ref sourceBase, sampleX);
} ComplexVector4 partial = factor * sample;
target += pixel4.WeightedSum(this.z, this.w); target += partial.WeightedSum(this.z, this.w);
} }
} }
} }

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

@ -207,39 +207,41 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
{ {
int boundsX = this.bounds.X; int boundsX = this.bounds.X;
int boundsWidth = this.bounds.Width; int boundsWidth = this.bounds.Width;
int kernelSize = this.kernel.Length;
var state = new ConvolutionState<Complex64>(this.kernel, 1, this.kernel.Length, this.map); Span<int> rowOffsets = this.map.GetRowOffsetSpan();
ref int sampleRowBase = ref state.GetSampleRow(y - this.bounds.Y); Span<int> columnOffsets = this.map.GetColumnOffsetSpan();
int sampleY = Unsafe.Add(ref MemoryMarshal.GetReference(rowOffsets), y - this.bounds.Y);
ref int sampleColumnBase = ref MemoryMarshal.GetReference(columnOffsets);
// Clear the target buffer for each row run
Span<ComplexVector4> targetBuffer = this.targetValues.GetRowSpan(y); Span<ComplexVector4> targetBuffer = this.targetValues.GetRowSpan(y);
// Clear the target buffer
targetBuffer.Clear(); targetBuffer.Clear();
ref ComplexVector4 targetBase = ref MemoryMarshal.GetReference(targetBuffer); ref ComplexVector4 targetBase = ref MemoryMarshal.GetReference(targetBuffer);
ReadOnlyKernel<Complex64> kernel = state.Kernel; // Execute the bulk pixel format conversion for the current row
Span<TPixel> sourceRow = this.sourcePixels.GetRowSpan(sampleY).Slice(boundsX, boundsWidth);
PixelOperations<TPixel>.Instance.ToVector4(this.configuration, sourceRow, span);
for (int kY = 0; kY < kernel.Rows; kY++) ref Vector4 sourceBase = ref MemoryMarshal.GetReference(span);
{ ref Complex64 kernelBase = ref this.kernel[0];
// Get the precalculated source sample row for this kernel row and copy to our buffer.
int sampleY = Unsafe.Add(ref sampleRowBase, kY);
Span<TPixel> sourceRow = this.sourcePixels.GetRowSpan(sampleY).Slice(boundsX, boundsWidth);
PixelOperations<TPixel>.Instance.ToVector4(this.configuration, sourceRow, span);
ref Vector4 sourceBase = ref MemoryMarshal.GetReference(span); for (int x = 0; x < span.Length; x++)
{
ref ComplexVector4 target = ref Unsafe.Add(ref targetBase, x);
for (int x = 0; x < span.Length; x++) for (int kX = 0; kX < kernelSize; kX++)
{ {
ref int sampleColumnBase = ref state.GetSampleColumn(x); int sampleX = Unsafe.Add(ref sampleColumnBase, kX) - boundsX;
ref ComplexVector4 target = ref Unsafe.Add(ref targetBase, x); Vector4 sample = Unsafe.Add(ref sourceBase, sampleX);
Complex64 factor = Unsafe.Add(ref kernelBase, kX);
for (int kX = 0; kX < kernel.Columns; kX++)
{ target.Sum(factor * sample);
int sampleX = Unsafe.Add(ref sampleColumnBase, kX) - boundsX;
Vector4 sample = Unsafe.Add(ref sourceBase, sampleX);
target.Sum(kernel[kY, kX] * sample);
}
} }
// Shift the base column sampling reference by one row at the end of each outer
// iteration so that the inner tight loop indexing can skip the multiplication
sampleColumnBase = ref Unsafe.Add(ref sampleColumnBase, kernelSize);
} }
} }
} }

Loading…
Cancel
Save