Browse Source

Bulk convert source rows to Vector4

pull/2219/head
Ynse Hoornenborg 4 years ago
parent
commit
bc1162e05b
  1. 11
      src/ImageSharp/Processing/Processors/Convolution/MedianBlurProcessor{TPixel}.cs
  2. 32
      src/ImageSharp/Processing/Processors/Convolution/MedianRowOperation{TPixel}.cs

11
src/ImageSharp/Processing/Processors/Convolution/MedianBlurProcessor{TPixel}.cs

@ -17,10 +17,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
private readonly MedianBlurProcessor definition; private readonly MedianBlurProcessor definition;
public MedianBlurProcessor(Configuration configuration, MedianBlurProcessor definition, Image<TPixel> source, Rectangle sourceRectangle) public MedianBlurProcessor(Configuration configuration, MedianBlurProcessor definition, Image<TPixel> source, Rectangle sourceRectangle)
: base(configuration, source, sourceRectangle) : base(configuration, source, sourceRectangle) => this.definition = definition;
{
this.definition = definition;
}
protected override void OnFrameApply(ImageFrame<TPixel> source) protected override void OnFrameApply(ImageFrame<TPixel> source)
{ {
@ -31,13 +28,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
source.CopyTo(targetPixels); source.CopyTo(targetPixels);
Rectangle interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds()); var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds());
// We use a rectangle with width set to 2 * kernelSize^2 + width, to allocate a buffer big enough // We use a rectangle with width set to 2 * kernelSize^2 + width, to allocate a buffer big enough
// for kernel source and target bulk pixel conversion. // for kernel source and target bulk pixel conversion.
Rectangle operationBounds = new Rectangle(interest.X, interest.Y, (2 * (kernelSize * kernelSize)) + interest.Width, interest.Height); var operationBounds = new Rectangle(interest.X, interest.Y, (2 * kernelSize * kernelSize) + interest.Width + (kernelSize * interest.Width), interest.Height);
using KernelSamplingMap map = new KernelSamplingMap(this.Configuration.MemoryAllocator); using var map = new KernelSamplingMap(this.Configuration.MemoryAllocator);
map.BuildSamplingOffsetMap(kernelSize, kernelSize, interest, this.definition.BorderWrapModeX, this.definition.BorderWrapModeY); map.BuildSamplingOffsetMap(kernelSize, kernelSize, interest, this.definition.BorderWrapModeX, this.definition.BorderWrapModeY);
var operation = new MedianRowOperation<TPixel>( var operation = new MedianRowOperation<TPixel>(

32
src/ImageSharp/Processing/Processors/Convolution/MedianRowOperation{TPixel}.cs

@ -51,7 +51,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
int kernelCount = this.kernelSize * this.kernelSize; int kernelCount = this.kernelSize * this.kernelSize;
Span<Vector4> kernelBuffer = span.Slice(0, kernelCount); Span<Vector4> kernelBuffer = span.Slice(0, kernelCount);
Span<Vector4> channelVectorBuffer = span.Slice(kernelCount, kernelCount); Span<Vector4> channelVectorBuffer = span.Slice(kernelCount, kernelCount);
Span<Vector4> targetBuffer = span.Slice(kernelCount << 1, boundsWidth); Span<Vector4> sourceVectorBuffer = span.Slice(kernelCount << 1, this.kernelSize * boundsWidth);
Span<Vector4> targetBuffer = span.Slice((kernelCount << 1) + sourceVectorBuffer.Length, boundsWidth);
// Stack 4 channels of floats in the space of Vector4's. // Stack 4 channels of floats in the space of Vector4's.
Span<float> channelBuffer = MemoryMarshal.Cast<Vector4, float>(channelVectorBuffer); Span<float> channelBuffer = MemoryMarshal.Cast<Vector4, float>(channelVectorBuffer);
@ -59,13 +60,22 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
Span<float> yChannel = channelBuffer.Slice(this.yChannelStart, kernelCount); Span<float> yChannel = channelBuffer.Slice(this.yChannelStart, kernelCount);
Span<float> zChannel = channelBuffer.Slice(this.zChannelStart, kernelCount); Span<float> zChannel = channelBuffer.Slice(this.zChannelStart, kernelCount);
DenseMatrix<Vector4> kernel = new DenseMatrix<Vector4>(this.kernelSize, this.kernelSize, kernelBuffer); var kernel = new DenseMatrix<Vector4>(this.kernelSize, this.kernelSize, kernelBuffer);
int row = y - this.bounds.Y; int row = y - this.bounds.Y;
MedianConvolutionState state = new MedianConvolutionState(in kernel, this.map); var state = new MedianConvolutionState(in kernel, this.map);
ref int sampleRowBase = ref state.GetSampleRow(row); ref int sampleRowBase = ref state.GetSampleRow(row);
ref Vector4 targetBase = ref MemoryMarshal.GetReference(targetBuffer); ref Vector4 targetBase = ref MemoryMarshal.GetReference(targetBuffer);
// First convert the required source rows to Vector4.
for (int i = 0; i < this.kernelSize; i++)
{
int currentYIndex = Unsafe.Add(ref sampleRowBase, i);
Span<TPixel> sourceRow = this.sourcePixels.DangerousGetRowSpan(currentYIndex).Slice(boundsX, boundsWidth);
Span<Vector4> sourceVectorRow = sourceVectorBuffer.Slice(i * boundsWidth, boundsWidth);
PixelOperations<TPixel>.Instance.ToVector4(this.configuration, sourceRow, sourceVectorRow);
}
if (this.preserveAlpha) if (this.preserveAlpha)
{ {
for (int x = 0; x < boundsWidth; x++) for (int x = 0; x < boundsWidth; x++)
@ -76,13 +86,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
for (int kY = 0; kY < state.Kernel.Rows; kY++) for (int kY = 0; kY < state.Kernel.Rows; kY++)
{ {
int currentYIndex = Unsafe.Add(ref sampleRowBase, kY); int currentYIndex = Unsafe.Add(ref sampleRowBase, kY);
Span<TPixel> sourceRow = this.sourcePixels.DangerousGetRowSpan(currentYIndex).Slice(boundsX, boundsWidth); Span<Vector4> sourceRow = sourceVectorBuffer.Slice(kY * boundsWidth);
ref TPixel sourceRowBase = ref MemoryMarshal.GetReference(sourceRow); ref Vector4 sourceRowBase = ref MemoryMarshal.GetReference(sourceRow);
for (int kX = 0; kX < state.Kernel.Columns; kX++) for (int kX = 0; kX < state.Kernel.Columns; kX++)
{ {
int currentXIndex = Unsafe.Add(ref sampleColumnBase, kX) - boundsX; int currentXIndex = Unsafe.Add(ref sampleColumnBase, kX) - boundsX;
TPixel pixel = Unsafe.Add(ref sourceRowBase, currentXIndex); Vector4 pixel = Unsafe.Add(ref sourceRowBase, currentXIndex);
state.Kernel.SetValue(index, pixel.ToVector4()); state.Kernel.SetValue(index, pixel);
index++; index++;
} }
} }
@ -102,13 +112,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
for (int kY = 0; kY < state.Kernel.Rows; kY++) for (int kY = 0; kY < state.Kernel.Rows; kY++)
{ {
int currentYIndex = Unsafe.Add(ref sampleRowBase, kY); int currentYIndex = Unsafe.Add(ref sampleRowBase, kY);
Span<TPixel> sourceRow = this.sourcePixels.DangerousGetRowSpan(currentYIndex).Slice(boundsX, boundsWidth); Span<Vector4> sourceRow = sourceVectorBuffer.Slice(kY * boundsWidth);
ref TPixel sourceRowBase = ref MemoryMarshal.GetReference(sourceRow); ref Vector4 sourceRowBase = ref MemoryMarshal.GetReference(sourceRow);
for (int kX = 0; kX < state.Kernel.Columns; kX++) for (int kX = 0; kX < state.Kernel.Columns; kX++)
{ {
int currentXIndex = Unsafe.Add(ref sampleColumnBase, kX) - boundsX; int currentXIndex = Unsafe.Add(ref sampleColumnBase, kX) - boundsX;
TPixel pixel = Unsafe.Add(ref sourceRowBase, currentXIndex); Vector4 pixel = Unsafe.Add(ref sourceRowBase, currentXIndex);
state.Kernel.SetValue(index, pixel.ToVector4()); state.Kernel.SetValue(index, pixel);
index++; index++;
} }
} }

Loading…
Cancel
Save