Browse Source

optimized sliding works!

pull/888/head
Anton Firszov 7 years ago
parent
commit
f6c778442d
  1. 28
      src/ImageSharp/Memory/Buffer2DExtensions.cs
  2. 17
      src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeWorker.cs
  3. 23
      tests/ImageSharp.Tests/Memory/Buffer2DTests.cs

28
src/ImageSharp/Memory/Buffer2DExtensions.cs

@ -3,7 +3,9 @@
using System; using System;
using System.Buffers; using System.Buffers;
using System.Diagnostics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.Primitives; using SixLabors.Primitives;
@ -27,8 +29,8 @@ namespace SixLabors.ImageSharp.Memory
{ {
DebugGuard.NotNull(buffer, nameof(buffer)); DebugGuard.NotNull(buffer, nameof(buffer));
DebugGuard.MustBeGreaterThanOrEqualTo(sourceIndex, 0, nameof(sourceIndex)); DebugGuard.MustBeGreaterThanOrEqualTo(sourceIndex, 0, nameof(sourceIndex));
DebugGuard.MustBeGreaterThanOrEqualTo(destIndex, sourceIndex + columnCount, nameof(destIndex)); DebugGuard.MustBeGreaterThanOrEqualTo(destIndex, 0, nameof(sourceIndex));
DebugGuard.MustBeLessThanOrEqualTo(destIndex, buffer.Width - columnCount, nameof(destIndex)); CheckColumnRegionsDoNotOverlap(buffer, sourceIndex, destIndex, columnCount);
int elementSize = Unsafe.SizeOf<T>(); int elementSize = Unsafe.SizeOf<T>();
int width = buffer.Width * elementSize; int width = buffer.Width * elementSize;
@ -36,9 +38,11 @@ namespace SixLabors.ImageSharp.Memory
int dOffset = destIndex * elementSize; int dOffset = destIndex * elementSize;
long count = columnCount * elementSize; long count = columnCount * elementSize;
using (MemoryHandle handle = buffer.Memory.Pin()) Span<byte> span = MemoryMarshal.AsBytes(buffer.Memory.Span);
fixed (byte* ptr = span)
{ {
byte* basePtr = (byte*)handle.Pointer; byte* basePtr = (byte*)ptr;
for (int y = 0; y < buffer.Height; y++) for (int y = 0; y < buffer.Height; y++)
{ {
byte* sPtr = basePtr + sOffset; byte* sPtr = basePtr + sOffset;
@ -164,5 +168,21 @@ namespace SixLabors.ImageSharp.Memory
{ {
return buffer.MemorySource.GetSpan(); return buffer.MemorySource.GetSpan();
} }
[Conditional("DEBUG")]
private static void CheckColumnRegionsDoNotOverlap<T>(
Buffer2D<T> buffer,
int sourceIndex,
int destIndex,
int columnCount)
where T : struct
{
int minIndex = Math.Min(sourceIndex, destIndex);
int maxIndex = Math.Max(sourceIndex, destIndex);
if (maxIndex < minIndex + columnCount || maxIndex > buffer.Width - columnCount)
{
throw new InvalidOperationException("Column regions should not overlap!");
}
}
} }
} }

17
src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeWorker.cs

@ -148,14 +148,23 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
int minY = this.currentWindow.Max - this.windowBandHeight; int minY = this.currentWindow.Max - this.windowBandHeight;
int maxY = Math.Min(minY + this.workerHeight, this.sourceRectangle.Height); int maxY = Math.Min(minY + this.workerHeight, this.sourceRectangle.Height);
// Copy previous bottom band to the new top:
// (rows <--> columns, because the buffer is transposed)
this.transposedFirstPassBuffer.CopyColumns(
this.workerHeight - this.windowBandHeight,
0,
this.windowBandHeight);
this.currentWindow = new RowInterval(minY, maxY); this.currentWindow = new RowInterval(minY, maxY);
this.CalculateFirstPassValues(this.currentWindow);
// Calculate the remainder:
this.CalculateFirstPassValues(this.currentWindow.Slice(this.windowBandHeight));
} }
private void CalculateFirstPassValues(RowInterval window) private void CalculateFirstPassValues(RowInterval calculationInterval)
{ {
Span<Vector4> tempRowSpan = this.tempRowBuffer.GetSpan(); Span<Vector4> tempRowSpan = this.tempRowBuffer.GetSpan();
for (int y = window.Min; y < window.Max; y++) for (int y = calculationInterval.Min; y < calculationInterval.Max; y++)
{ {
Span<TPixel> sourceRow = this.source.GetRowSpan(y); Span<TPixel> sourceRow = this.source.GetRowSpan(y);
@ -166,7 +175,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
this.conversionModifiers); this.conversionModifiers);
// ref Vector4 firstPassBaseRef = ref this.buffer.Span[y - top]; // ref Vector4 firstPassBaseRef = ref this.buffer.Span[y - top];
Span<Vector4> firstPassSpan = this.transposedFirstPassBuffer.Span.Slice(y - window.Min); Span<Vector4> firstPassSpan = this.transposedFirstPassBuffer.Span.Slice(y - this.currentWindow.Min);
for (int x = this.targetWorkingRect.Left; x < this.targetWorkingRect.Right; x++) for (int x = this.targetWorkingRect.Left; x < this.targetWorkingRect.Right; x++)
{ {

23
tests/ImageSharp.Tests/Memory/Buffer2DTests.cs

@ -155,5 +155,28 @@ namespace SixLabors.ImageSharp.Tests.Memory
} }
} }
} }
[Fact]
public void CopyColumns_InvokeMultipleTimes()
{
Random rnd = new Random(123);
using (Buffer2D<float> b = this.MemoryAllocator.Allocate2D<float>(100, 100))
{
rnd.RandomFill(b.Span, 0, 1);
b.CopyColumns(0, 50, 22);
b.CopyColumns(0, 50, 22);
for (int y = 0; y < b.Height; y++)
{
Span<float> row = b.GetRowSpan(y);
Span<float> s = row.Slice(0, 22);
Span<float> d = row.Slice(50, 22);
Xunit.Assert.True(s.SequenceEqual(d));
}
}
}
} }
} }
Loading…
Cancel
Save