Browse Source

moar RowInterval stuff

af/merge-core
Anton Firszov 7 years ago
parent
commit
398736a09b
  1. 37
      src/ImageSharp/Memory/RowInterval.cs
  2. 43
      src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeWorker.cs
  3. 49
      tests/ImageSharp.Tests/Helpers/RowIntervalTests.cs

37
src/ImageSharp/Memory/RowInterval.cs

@ -1,6 +1,8 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System;
using SixLabors.Primitives; using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Memory namespace SixLabors.ImageSharp.Memory
@ -8,7 +10,7 @@ namespace SixLabors.ImageSharp.Memory
/// <summary> /// <summary>
/// Represents an interval of rows in a <see cref="Rectangle"/> and/or <see cref="Buffer2D{T}"/> /// Represents an interval of rows in a <see cref="Rectangle"/> and/or <see cref="Buffer2D{T}"/>
/// </summary> /// </summary>
internal readonly struct RowInterval internal readonly struct RowInterval : IEquatable<RowInterval>
{ {
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="RowInterval"/> struct. /// Initializes a new instance of the <see cref="RowInterval"/> struct.
@ -36,7 +38,40 @@ namespace SixLabors.ImageSharp.Memory
/// </summary> /// </summary>
public int Height => this.Max - this.Min; public int Height => this.Max - this.Min;
public static bool operator ==(RowInterval left, RowInterval right)
{
return left.Equals(right);
}
public static bool operator !=(RowInterval left, RowInterval right)
{
return !left.Equals(right);
}
/// <inheritdoc /> /// <inheritdoc />
public override string ToString() => $"RowInterval [{this.Min}->{this.Max}]"; public override string ToString() => $"RowInterval [{this.Min}->{this.Max}]";
public RowInterval Slice(int start) => new RowInterval(this.Min + start, this.Max);
public RowInterval Slice(int start, int length) => new RowInterval(this.Min + start, this.Min + start + length);
public bool Equals(RowInterval other)
{
return this.Min == other.Min && this.Max == other.Max;
}
public override bool Equals(object obj)
{
return !ReferenceEquals(null, obj) && obj is RowInterval other && this.Equals(other);
}
public override int GetHashCode()
{
unchecked
{
return (this.Min * 397) ^ this.Max;
}
}
} }
} }

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

@ -45,6 +45,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
private readonly int windowHeight; private readonly int windowHeight;
private RowInterval currentWindow;
public ResizeWorker( public ResizeWorker(
Configuration configuration, Configuration configuration,
BufferArea<TPixel> source, BufferArea<TPixel> source,
@ -82,14 +84,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
this.tempRowBuffer = configuration.MemoryAllocator.Allocate<Vector4>(this.sourceRectangle.Width); this.tempRowBuffer = configuration.MemoryAllocator.Allocate<Vector4>(this.sourceRectangle.Width);
this.tempColumnBuffer = configuration.MemoryAllocator.Allocate<Vector4>(destWidth); this.tempColumnBuffer = configuration.MemoryAllocator.Allocate<Vector4>(destWidth);
this.CurrentMinY = 0; this.currentWindow = new RowInterval(0, this.windowHeight);
this.CurrentMaxY = this.windowHeight;
} }
public int CurrentMaxY { get; private set; }
public int CurrentMinY { get; private set; }
public void Dispose() public void Dispose()
{ {
this.buffer.Dispose(); this.buffer.Dispose();
@ -100,18 +97,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public Span<Vector4> GetColumnSpan(int x, int startY) public Span<Vector4> GetColumnSpan(int x, int startY)
{ {
return this.buffer.GetRowSpan(x).Slice(startY - this.CurrentMinY); return this.buffer.GetRowSpan(x).Slice(startY - this.currentWindow.Min);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Span<Vector4> GetColumnSpan(int x)
{
return this.buffer.GetRowSpan(x);
}
public void Initialize() public void Initialize()
{ {
this.CalculateFirstPassValues(0, this.windowHeight); this.CalculateFirstPassValues(this.currentWindow);
} }
public void FillDestinationPixels(int minY, int maxY, int startY, Buffer2D<TPixel> destination) public void FillDestinationPixels(int minY, int maxY, int startY, Buffer2D<TPixel> destination)
@ -123,14 +115,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
// Ensure offsets are normalized for cropping and padding. // Ensure offsets are normalized for cropping and padding.
ResizeKernel kernel = this.verticalKernelMap.GetKernel(y - startY); ResizeKernel kernel = this.verticalKernelMap.GetKernel(y - startY);
while (kernel.StartIndex + kernel.Length > this.CurrentMaxY) while (kernel.StartIndex + kernel.Length > this.currentWindow.Max)
{ {
this.Slide(); this.Slide();
} }
ref Vector4 tempRowBase = ref MemoryMarshal.GetReference(tempColSpan); ref Vector4 tempRowBase = ref MemoryMarshal.GetReference(tempColSpan);
int top = kernel.StartIndex - this.CurrentMinY; int top = kernel.StartIndex - this.currentWindow.Min;
for (int x = 0; x < this.destWidth; x++) for (int x = 0; x < this.destWidth; x++)
{ {
@ -146,17 +138,24 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
} }
} }
public void Slide() [MethodImpl(MethodImplOptions.AggressiveInlining)]
private Span<Vector4> GetColumnSpan(int x)
{
return this.buffer.GetRowSpan(x);
}
private void Slide()
{ {
this.CurrentMinY = this.CurrentMinY + this.windowBandDiameter; int minY = this.currentWindow.Min + this.windowBandDiameter;
this.CurrentMaxY = Math.Min(this.CurrentMaxY + this.windowBandDiameter, this.sourceRectangle.Height); int maxY = Math.Min(this.currentWindow.Max + this.windowBandDiameter, this.sourceRectangle.Height);
this.CalculateFirstPassValues(this.CurrentMinY, this.CurrentMaxY); this.currentWindow = new RowInterval(minY, maxY);
this.CalculateFirstPassValues(this.currentWindow);
} }
private void CalculateFirstPassValues(int minY, int maxY) private void CalculateFirstPassValues(RowInterval window)
{ {
Span<Vector4> tempRowSpan = this.tempRowBuffer.GetSpan(); Span<Vector4> tempRowSpan = this.tempRowBuffer.GetSpan();
for (int y = minY; y < maxY; y++) for (int y = window.Min; y < window.Max; y++)
{ {
Span<TPixel> sourceRow = this.source.GetRowSpan(y); Span<TPixel> sourceRow = this.source.GetRowSpan(y);
@ -167,7 +166,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.buffer.Span.Slice(y - minY); Span<Vector4> firstPassSpan = this.buffer.Span.Slice(y - window.Min);
for (int x = this.destWorkingRect.Left; x < this.destWorkingRect.Right; x++) for (int x = this.destWorkingRect.Left; x < this.destWorkingRect.Right; x++)
{ {

49
tests/ImageSharp.Tests/Helpers/RowIntervalTests.cs

@ -34,5 +34,54 @@ namespace SixLabors.ImageSharp.Tests.Helpers
Assert.True(Unsafe.AreSame(ref expected0, ref actual0)); Assert.True(Unsafe.AreSame(ref expected0, ref actual0));
} }
} }
[Fact]
public void Slice1()
{
RowInterval rowInterval = new RowInterval(10, 20);
RowInterval sliced = rowInterval.Slice(5);
Assert.Equal(15, sliced.Min);
Assert.Equal(20, sliced.Max);
}
[Fact]
public void Slice2()
{
RowInterval rowInterval = new RowInterval(10, 20);
RowInterval sliced = rowInterval.Slice(3, 5);
Assert.Equal(13, sliced.Min);
Assert.Equal(18, sliced.Max);
}
[Fact]
public void Equality_WhenTrue()
{
RowInterval a = new RowInterval(42, 123);
RowInterval b = new RowInterval(42, 123);
Assert.True(a.Equals(b));
Assert.True(a.Equals((object)b));
Assert.True(a == b);
Assert.Equal(a.GetHashCode(), b.GetHashCode());
}
[Fact]
public void Equality_WhenFalse()
{
RowInterval a = new RowInterval(42, 123);
RowInterval b = new RowInterval(42, 125);
RowInterval c = new RowInterval(40, 123);
Assert.False(a.Equals(b));
Assert.False(c.Equals(a));
Assert.False(b.Equals(c));
Assert.False(a.Equals((object)b));
Assert.False(a.Equals(null));
Assert.False(a == b);
Assert.True(a != c);
}
} }
} }

Loading…
Cancel
Save