Browse Source

refactor

- ResizeWindow -> ResizeWorker
- Most logic moved to ResizeWorker
af/merge-core
Anton Firszov 7 years ago
parent
commit
ec1971435b
  1. 42
      src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor.cs
  2. 72
      src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeWorker.cs

42
src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor.cs

@ -237,11 +237,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
BufferArea<TPixel> sourceArea = source.PixelBuffer.GetArea(sourceRectangle);
// Interpolate the image using the calculated weights.
// A 2-pass 1D algorithm appears to be faster than splitting a 1-pass 2D algorithm
// First process the columns. Since we are not using multiple threads startY and endY
// are the upper and lower bounds of the source rectangle.
using (var resizeWindow = new ResizeWindow<TPixel>(
// If we want to reintroduce processing:
// it's possible to launch multiple workers for different regions of the image
using (var worker = new ResizeWorker<TPixel>(
configuration,
sourceArea,
conversionModifiers,
@ -250,39 +248,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
width,
destWorkingRect,
startX))
using (IMemoryOwner<Vector4> tempBuffer = source.MemoryAllocator.Allocate<Vector4>(width))
{
resizeWindow.Initialize();
// Now process the rows.
Span<Vector4> tempColSpan = tempBuffer.GetSpan();
for (int y = destWorkingRect.Top; y < destWorkingRect.Bottom; y++)
{
// Ensure offsets are normalized for cropping and padding.
ResizeKernel kernel = this.verticalKernelMap.GetKernel(y - startY);
while (kernel.StartIndex + kernel.Length > resizeWindow.Bottom)
{
resizeWindow.Slide();
}
ref Vector4 tempRowBase = ref MemoryMarshal.GetReference(tempColSpan);
int top = kernel.StartIndex - resizeWindow.Top;
for (int x = 0; x < width; x++)
{
Span<Vector4> firstPassColumn = resizeWindow.GetColumnSpan(x).Slice(top);
// Destination color components
Unsafe.Add(ref tempRowBase, x) = kernel.ConvolveCore(firstPassColumn);
}
Span<TPixel> targetRowSpan = destination.GetPixelRowSpan(y);
PixelOperations<TPixel>.Instance.FromVector4Destructive(configuration, tempColSpan, targetRowSpan, conversionModifiers);
}
worker.Initialize();
worker.FillDestinationPixels(destWorkingRect.Top, destWorkingRect.Bottom, startY, destination.PixelBuffer);
}
}

72
src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeWindow.cs → src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeWorker.cs

@ -5,6 +5,7 @@ using System;
using System.Buffers;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@ -13,7 +14,7 @@ using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.Transforms
{
internal class ResizeWindow<TPixel> : IDisposable
internal class ResizeWorker<TPixel> : IDisposable
where TPixel : struct, IPixel<TPixel>
{
private readonly Buffer2D<Vector4> buffer;
@ -32,15 +33,19 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
private readonly IMemoryOwner<Vector4> tempRowBuffer;
private readonly IMemoryOwner<Vector4> tempColumnBuffer;
private readonly ResizeKernelMap verticalKernelMap;
private readonly int destWidth;
private readonly Rectangle destWorkingRect;
private readonly int diameter;
private readonly int windowHeight;
public ResizeWindow(
public ResizeWorker(
Configuration configuration,
BufferArea<TPixel> source,
PixelConversionModifiers conversionModifiers,
@ -56,6 +61,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
this.conversionModifiers = conversionModifiers;
this.horizontalKernelMap = horizontalKernelMap;
this.verticalKernelMap = verticalKernelMap;
this.destWidth = destWidth;
this.destWorkingRect = destWorkingRect;
this.startX = startX;
@ -67,22 +73,29 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
this.windowHeight,
destWidth,
AllocationOptions.Clean);
this.tempRowBuffer = configuration.MemoryAllocator.Allocate<Vector4>(this.sourceRectangle.Width);
this.tempColumnBuffer = configuration.MemoryAllocator.Allocate<Vector4>(destWidth);
this.CurrentMinY = 0;
this.CurrentMaxY = this.windowHeight;
}
public int Bottom { get; private set; }
public int CurrentMaxY { get; private set; }
public int Top { get; private set; }
public int CurrentMinY { get; private set; }
public void Dispose()
{
this.buffer.Dispose();
this.tempRowBuffer.Dispose();
this.tempColumnBuffer.Dispose();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Span<Vector4> GetColumnSpan(int x, int startY)
{
return this.buffer.GetRowSpan(x).Slice(startY - this.Top);
return this.buffer.GetRowSpan(x).Slice(startY - this.CurrentMinY);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@ -93,23 +106,52 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
public void Initialize()
{
this.Initialize(0, this.windowHeight);
this.CalculateFirstPassValues(0, this.windowHeight);
}
public void Slide()
public void FillDestinationPixels(int minY, int maxY, int startY, Buffer2D<TPixel> destination)
{
int top = this.Top + this.diameter;
int bottom = Math.Min(this.Bottom + this.diameter, this.sourceRectangle.Height);
this.Initialize(top, bottom);
Span<Vector4> tempColSpan = this.tempColumnBuffer.GetSpan();
for (int y = minY; y < maxY; y++)
{
// Ensure offsets are normalized for cropping and padding.
ResizeKernel kernel = this.verticalKernelMap.GetKernel(y - startY);
while (kernel.StartIndex + kernel.Length > this.CurrentMaxY)
{
this.Slide();
}
ref Vector4 tempRowBase = ref MemoryMarshal.GetReference(tempColSpan);
int top = kernel.StartIndex - this.CurrentMinY;
for (int x = 0; x < this.destWidth; x++)
{
Span<Vector4> firstPassColumn = this.GetColumnSpan(x).Slice(top);
// Destination color components
Unsafe.Add(ref tempRowBase, x) = kernel.ConvolveCore(firstPassColumn);
}
Span<TPixel> targetRowSpan = destination.GetRowSpan(y);
PixelOperations<TPixel>.Instance.FromVector4Destructive(configuration, tempColSpan, targetRowSpan, conversionModifiers);
}
}
private void Initialize(int top, int bottom)
public void Slide()
{
this.Top = top;
this.Bottom = bottom;
this.CurrentMinY = this.CurrentMinY + this.diameter;
this.CurrentMaxY = Math.Min(this.CurrentMaxY + this.diameter, this.sourceRectangle.Height);
this.CalculateFirstPassValues(this.CurrentMinY, this.CurrentMaxY);
}
private void CalculateFirstPassValues(int minY, int maxY)
{
Span<Vector4> tempRowSpan = this.tempRowBuffer.GetSpan();
for (int y = top; y < bottom; y++)
for (int y = minY; y < maxY; y++)
{
Span<TPixel> sourceRow = this.source.GetRowSpan(y);
@ -120,7 +162,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
this.conversionModifiers);
//ref Vector4 firstPassBaseRef = ref this.buffer.Span[y - top];
Span<Vector4> firstPassSpan = this.buffer.Span.Slice(y - top);
Span<Vector4> firstPassSpan = this.buffer.Span.Slice(y - minY);
for (int x = this.destWorkingRect.Left; x < this.destWorkingRect.Right; x++)
{
Loading…
Cancel
Save