Browse Source

clean up PNG filters

pull/2226/head
Clinton Ingram 4 years ago
parent
commit
919721342f
  1. 36
      src/ImageSharp/Common/Helpers/Numerics.cs
  2. 39
      src/ImageSharp/Formats/Png/Filters/AverageFilter.cs
  3. 6
      src/ImageSharp/Formats/Png/Filters/NoneFilter.cs
  4. 29
      src/ImageSharp/Formats/Png/Filters/PaethFilter.cs
  5. 12
      src/ImageSharp/Formats/Png/Filters/SubFilter.cs
  6. 26
      src/ImageSharp/Formats/Png/Filters/UpFilter.cs
  7. 10
      tests/ImageSharp.Tests/Formats/Png/ReferenceImplementations.cs

36
src/ImageSharp/Common/Helpers/Numerics.cs

@ -780,25 +780,13 @@ namespace SixLabors.ImageSharp
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int ReduceSum(Vector128<int> accumulator) public static int ReduceSum(Vector128<int> accumulator)
{ {
if (Ssse3.IsSupported) // Add odd to even.
{ Vector128<int> vsum = Sse2.Add(accumulator, Sse2.Shuffle(accumulator, 0b_11_11_01_01));
Vector128<int> hadd = Ssse3.HorizontalAdd(accumulator, accumulator);
Vector128<int> swapped = Sse2.Shuffle(hadd, 0x1);
Vector128<int> tmp = Sse2.Add(hadd, swapped);
// Vector128<int>.ToScalar() isn't optimized pre-net5.0 https://github.com/dotnet/runtime/pull/37882 // Add high to low.
return Sse2.ConvertToInt32(tmp); vsum = Sse2.Add(vsum, Sse2.Shuffle(vsum, 0b_11_10_11_10));
}
else
{
int sum = 0;
for (int i = 0; i < Vector128<int>.Count; i++)
{
sum += accumulator.GetElement(i);
}
return sum; return Sse2.ConvertToInt32(vsum);
}
} }
/// <summary> /// <summary>
@ -821,6 +809,20 @@ namespace SixLabors.ImageSharp
return Sse2.ConvertToInt32(vsum); return Sse2.ConvertToInt32(vsum);
} }
/// <summary>
/// Reduces even elements of the vector into one sum.
/// </summary>
/// <param name="accumulator">The accumulator to reduce.</param>
/// <returns>The sum of even elements.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int EvenReduceSum(Vector128<int> accumulator)
{
// Add high to low.
Vector128<int> vsum = Sse2.Add(accumulator, Sse2.Shuffle(accumulator, 0b_11_10_11_10));
return Sse2.ConvertToInt32(vsum);
}
/// <summary> /// <summary>
/// Reduces even elements of the vector into one sum. /// Reduces even elements of the vector into one sum.
/// </summary> /// </summary>

39
src/ImageSharp/Formats/Png/Filters/AverageFilter.cs

@ -119,9 +119,9 @@ namespace SixLabors.ImageSharp.Formats.Png.Filters
sum = 0; sum = 0;
// Average(x) = Raw(x) - floor((Raw(x-bpp)+Prior(x))/2) // Average(x) = Raw(x) - floor((Raw(x-bpp)+Prior(x))/2)
resultBaseRef = 3; resultBaseRef = (byte)FilterType.Average;
int x = 0; nint x = 0;
for (; x < bytesPerPixel; /* Note: ++x happens in the body to avoid one add operation */) for (; x < bytesPerPixel; /* Note: ++x happens in the body to avoid one add operation */)
{ {
byte scan = Unsafe.Add(ref scanBaseRef, x); byte scan = Unsafe.Add(ref scanBaseRef, x);
@ -138,7 +138,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Filters
Vector256<int> sumAccumulator = Vector256<int>.Zero; Vector256<int> sumAccumulator = Vector256<int>.Zero;
Vector256<byte> allBitsSet = Avx2.CompareEqual(sumAccumulator, sumAccumulator).AsByte(); Vector256<byte> allBitsSet = Avx2.CompareEqual(sumAccumulator, sumAccumulator).AsByte();
for (int xLeft = x - bytesPerPixel; x + Vector256<byte>.Count <= scanline.Length; xLeft += Vector256<byte>.Count) for (nint xLeft = x - bytesPerPixel; x <= scanline.Length - Vector256<byte>.Count; xLeft += Vector256<byte>.Count)
{ {
Vector256<byte> scan = Unsafe.As<byte, Vector256<byte>>(ref Unsafe.Add(ref scanBaseRef, x)); Vector256<byte> scan = Unsafe.As<byte, Vector256<byte>>(ref Unsafe.Add(ref scanBaseRef, x));
Vector256<byte> left = Unsafe.As<byte, Vector256<byte>>(ref Unsafe.Add(ref scanBaseRef, xLeft)); Vector256<byte> left = Unsafe.As<byte, Vector256<byte>>(ref Unsafe.Add(ref scanBaseRef, xLeft));
@ -157,12 +157,11 @@ namespace SixLabors.ImageSharp.Formats.Png.Filters
} }
else if (Sse2.IsSupported) else if (Sse2.IsSupported)
{ {
Vector128<sbyte> zero8 = Vector128<sbyte>.Zero; Vector128<byte> zero = Vector128<byte>.Zero;
Vector128<short> zero16 = Vector128<short>.Zero;
Vector128<int> sumAccumulator = Vector128<int>.Zero; Vector128<int> sumAccumulator = Vector128<int>.Zero;
Vector128<byte> allBitsSet = Sse2.CompareEqual(sumAccumulator, sumAccumulator).AsByte(); Vector128<byte> allBitsSet = Sse2.CompareEqual(sumAccumulator, sumAccumulator).AsByte();
for (int xLeft = x - bytesPerPixel; x + Vector128<byte>.Count <= scanline.Length; xLeft += Vector128<byte>.Count) for (nint xLeft = x - bytesPerPixel; x <= scanline.Length - Vector128<byte>.Count; xLeft += Vector128<byte>.Count)
{ {
Vector128<byte> scan = Unsafe.As<byte, Vector128<byte>>(ref Unsafe.Add(ref scanBaseRef, x)); Vector128<byte> scan = Unsafe.As<byte, Vector128<byte>>(ref Unsafe.Add(ref scanBaseRef, x));
Vector128<byte> left = Unsafe.As<byte, Vector128<byte>>(ref Unsafe.Add(ref scanBaseRef, xLeft)); Vector128<byte> left = Unsafe.As<byte, Vector128<byte>>(ref Unsafe.Add(ref scanBaseRef, xLeft));
@ -174,36 +173,24 @@ namespace SixLabors.ImageSharp.Formats.Png.Filters
Unsafe.As<byte, Vector128<byte>>(ref Unsafe.Add(ref resultBaseRef, x + 1)) = res; // +1 to skip filter type Unsafe.As<byte, Vector128<byte>>(ref Unsafe.Add(ref resultBaseRef, x + 1)) = res; // +1 to skip filter type
x += Vector128<byte>.Count; x += Vector128<byte>.Count;
Vector128<sbyte> absRes; Vector128<byte> absRes;
if (Ssse3.IsSupported) if (Ssse3.IsSupported)
{ {
absRes = Ssse3.Abs(res.AsSByte()).AsSByte(); absRes = Ssse3.Abs(res.AsSByte());
} }
else else
{ {
Vector128<sbyte> mask = Sse2.CompareGreaterThan(res.AsSByte(), zero8); Vector128<sbyte> mask = Sse2.CompareGreaterThan(zero.AsSByte(), res.AsSByte());
mask = Sse2.Xor(mask, allBitsSet.AsSByte()); absRes = Sse2.Xor(Sse2.Add(res.AsSByte(), mask), mask).AsByte();
absRes = Sse2.Xor(Sse2.Add(res.AsSByte(), mask), mask);
} }
Vector128<short> loRes16 = Sse2.UnpackLow(absRes, zero8).AsInt16(); sumAccumulator = Sse2.Add(sumAccumulator, Sse2.SumAbsoluteDifferences(absRes, zero).AsInt32());
Vector128<short> hiRes16 = Sse2.UnpackHigh(absRes, zero8).AsInt16();
Vector128<int> loRes32 = Sse2.UnpackLow(loRes16, zero16).AsInt32();
Vector128<int> hiRes32 = Sse2.UnpackHigh(loRes16, zero16).AsInt32();
sumAccumulator = Sse2.Add(sumAccumulator, loRes32);
sumAccumulator = Sse2.Add(sumAccumulator, hiRes32);
loRes32 = Sse2.UnpackLow(hiRes16, zero16).AsInt32();
hiRes32 = Sse2.UnpackHigh(hiRes16, zero16).AsInt32();
sumAccumulator = Sse2.Add(sumAccumulator, loRes32);
sumAccumulator = Sse2.Add(sumAccumulator, hiRes32);
} }
sum += Numerics.ReduceSum(sumAccumulator); sum += Numerics.EvenReduceSum(sumAccumulator);
} }
for (int xLeft = x - bytesPerPixel; x < scanline.Length; ++xLeft /* Note: ++x happens in the body to avoid one add operation */) for (nint xLeft = x - bytesPerPixel; x < scanline.Length; ++xLeft /* Note: ++x happens in the body to avoid one add operation */)
{ {
byte scan = Unsafe.Add(ref scanBaseRef, x); byte scan = Unsafe.Add(ref scanBaseRef, x);
byte left = Unsafe.Add(ref scanBaseRef, xLeft); byte left = Unsafe.Add(ref scanBaseRef, xLeft);
@ -213,8 +200,6 @@ namespace SixLabors.ImageSharp.Formats.Png.Filters
res = (byte)(scan - Average(left, above)); res = (byte)(scan - Average(left, above));
sum += Numerics.Abs(unchecked((sbyte)res)); sum += Numerics.Abs(unchecked((sbyte)res));
} }
sum -= 3;
} }
/// <summary> /// <summary>

6
src/ImageSharp/Formats/Png/Filters/NoneFilter.cs

@ -1,4 +1,4 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Six Labors Split License. // Licensed under the Six Labors Split License.
using System; using System;
@ -21,8 +21,8 @@ namespace SixLabors.ImageSharp.Formats.Png.Filters
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Encode(ReadOnlySpan<byte> scanline, Span<byte> result) public static void Encode(ReadOnlySpan<byte> scanline, Span<byte> result)
{ {
// Insert a byte before the data. // Insert row filter byte before the data.
result[0] = 0; result[0] = (byte)FilterType.None;
result = result[1..]; result = result[1..];
scanline[..Math.Min(scanline.Length, result.Length)].CopyTo(result); scanline[..Math.Min(scanline.Length, result.Length)].CopyTo(result);
} }

29
src/ImageSharp/Formats/Png/Filters/PaethFilter.cs

@ -108,7 +108,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Filters
// Paeth(x) + PaethPredictor(Raw(x-bpp), Prior(x), Prior(x-bpp)) // Paeth(x) + PaethPredictor(Raw(x-bpp), Prior(x), Prior(x-bpp))
int offset = bytesPerPixel + 1; // Add one because x starts at one. int offset = bytesPerPixel + 1; // Add one because x starts at one.
int x = 1; nint x = 1;
for (; x < offset; x++) for (; x < offset; x++)
{ {
ref byte scan = ref Unsafe.Add(ref scanBaseRef, x); ref byte scan = ref Unsafe.Add(ref scanBaseRef, x);
@ -146,9 +146,9 @@ namespace SixLabors.ImageSharp.Formats.Png.Filters
sum = 0; sum = 0;
// Paeth(x) = Raw(x) - PaethPredictor(Raw(x-bpp), Prior(x), Prior(x - bpp)) // Paeth(x) = Raw(x) - PaethPredictor(Raw(x-bpp), Prior(x), Prior(x - bpp))
resultBaseRef = 4; resultBaseRef = (byte)FilterType.Paeth;
int x = 0; nint x = 0;
for (; x < bytesPerPixel; /* Note: ++x happens in the body to avoid one add operation */) for (; x < bytesPerPixel; /* Note: ++x happens in the body to avoid one add operation */)
{ {
byte scan = Unsafe.Add(ref scanBaseRef, x); byte scan = Unsafe.Add(ref scanBaseRef, x);
@ -164,7 +164,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Filters
Vector256<byte> zero = Vector256<byte>.Zero; Vector256<byte> zero = Vector256<byte>.Zero;
Vector256<int> sumAccumulator = Vector256<int>.Zero; Vector256<int> sumAccumulator = Vector256<int>.Zero;
for (int xLeft = x - bytesPerPixel; x + Vector256<byte>.Count <= scanline.Length; xLeft += Vector256<byte>.Count) for (nint xLeft = x - bytesPerPixel; x <= scanline.Length - Vector256<byte>.Count; xLeft += Vector256<byte>.Count)
{ {
Vector256<byte> scan = Unsafe.As<byte, Vector256<byte>>(ref Unsafe.Add(ref scanBaseRef, x)); Vector256<byte> scan = Unsafe.As<byte, Vector256<byte>>(ref Unsafe.Add(ref scanBaseRef, x));
Vector256<byte> left = Unsafe.As<byte, Vector256<byte>>(ref Unsafe.Add(ref scanBaseRef, xLeft)); Vector256<byte> left = Unsafe.As<byte, Vector256<byte>>(ref Unsafe.Add(ref scanBaseRef, xLeft));
@ -184,7 +184,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Filters
{ {
Vector<uint> sumAccumulator = Vector<uint>.Zero; Vector<uint> sumAccumulator = Vector<uint>.Zero;
for (int xLeft = x - bytesPerPixel; x + Vector<byte>.Count <= scanline.Length; xLeft += Vector<byte>.Count) for (nint xLeft = x - bytesPerPixel; x <= scanline.Length - Vector<byte>.Count; xLeft += Vector<byte>.Count)
{ {
Vector<byte> scan = Unsafe.As<byte, Vector<byte>>(ref Unsafe.Add(ref scanBaseRef, x)); Vector<byte> scan = Unsafe.As<byte, Vector<byte>>(ref Unsafe.Add(ref scanBaseRef, x));
Vector<byte> left = Unsafe.As<byte, Vector<byte>>(ref Unsafe.Add(ref scanBaseRef, xLeft)); Vector<byte> left = Unsafe.As<byte, Vector<byte>>(ref Unsafe.Add(ref scanBaseRef, xLeft));
@ -204,7 +204,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Filters
} }
} }
for (int xLeft = x - bytesPerPixel; x < scanline.Length; ++xLeft /* Note: ++x happens in the body to avoid one add operation */) for (nint xLeft = x - bytesPerPixel; x < scanline.Length; ++xLeft /* Note: ++x happens in the body to avoid one add operation */)
{ {
byte scan = Unsafe.Add(ref scanBaseRef, x); byte scan = Unsafe.Add(ref scanBaseRef, x);
byte left = Unsafe.Add(ref scanBaseRef, xLeft); byte left = Unsafe.Add(ref scanBaseRef, xLeft);
@ -215,8 +215,6 @@ namespace SixLabors.ImageSharp.Formats.Png.Filters
res = (byte)(scan - PaethPredictor(left, above, upperLeft)); res = (byte)(scan - PaethPredictor(left, above, upperLeft));
sum += Numerics.Abs(unchecked((sbyte)res)); sum += Numerics.Abs(unchecked((sbyte)res));
} }
sum -= 4;
} }
/// <summary> /// <summary>
@ -250,6 +248,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Filters
return upperLeft; return upperLeft;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Vector256<byte> PaethPredictor(Vector256<byte> left, Vector256<byte> above, Vector256<byte> upleft) private static Vector256<byte> PaethPredictor(Vector256<byte> left, Vector256<byte> above, Vector256<byte> upleft)
{ {
Vector256<byte> zero = Vector256<byte>.Zero; Vector256<byte> zero = Vector256<byte>.Zero;
@ -282,6 +281,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Filters
return Avx2.BlendVariable(resbc, left, Avx2.CompareEqual(Avx2.Min(minbc, pa), pa)); return Avx2.BlendVariable(resbc, left, Avx2.CompareEqual(Avx2.Min(minbc, pa), pa));
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Vector<byte> PaethPredictor(Vector<byte> left, Vector<byte> above, Vector<byte> upperLeft) private static Vector<byte> PaethPredictor(Vector<byte> left, Vector<byte> above, Vector<byte> upperLeft)
{ {
Vector.Widen(left, out Vector<ushort> a1, out Vector<ushort> a2); Vector.Widen(left, out Vector<ushort> a1, out Vector<ushort> a2);
@ -293,16 +293,17 @@ namespace SixLabors.ImageSharp.Formats.Png.Filters
return Vector.AsVectorByte(Vector.Narrow(p1, p2)); return Vector.AsVectorByte(Vector.Narrow(p1, p2));
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Vector<short> PaethPredictor(Vector<short> left, Vector<short> above, Vector<short> upperLeft) private static Vector<short> PaethPredictor(Vector<short> left, Vector<short> above, Vector<short> upperLeft)
{ {
Vector<short> p = left + above - upperLeft; Vector<short> p = left + above - upperLeft;
var pa = Vector.Abs(p - left); Vector<short> pa = Vector.Abs(p - left);
var pb = Vector.Abs(p - above); Vector<short> pb = Vector.Abs(p - above);
var pc = Vector.Abs(p - upperLeft); Vector<short> pc = Vector.Abs(p - upperLeft);
var pa_pb = Vector.LessThanOrEqual(pa, pb); Vector<short> pa_pb = Vector.LessThanOrEqual(pa, pb);
var pa_pc = Vector.LessThanOrEqual(pa, pc); Vector<short> pa_pc = Vector.LessThanOrEqual(pa, pc);
var pb_pc = Vector.LessThanOrEqual(pb, pc); Vector<short> pb_pc = Vector.LessThanOrEqual(pb, pc);
return Vector.ConditionalSelect( return Vector.ConditionalSelect(
condition: Vector.BitwiseAnd(pa_pb, pa_pc), condition: Vector.BitwiseAnd(pa_pb, pa_pc),

12
src/ImageSharp/Formats/Png/Filters/SubFilter.cs

@ -91,9 +91,9 @@ namespace SixLabors.ImageSharp.Formats.Png.Filters
sum = 0; sum = 0;
// Sub(x) = Raw(x) - Raw(x-bpp) // Sub(x) = Raw(x) - Raw(x-bpp)
resultBaseRef = 1; resultBaseRef = (byte)FilterType.Sub;
int x = 0; nint x = 0;
for (; x < bytesPerPixel; /* Note: ++x happens in the body to avoid one add operation */) for (; x < bytesPerPixel; /* Note: ++x happens in the body to avoid one add operation */)
{ {
byte scan = Unsafe.Add(ref scanBaseRef, x); byte scan = Unsafe.Add(ref scanBaseRef, x);
@ -108,7 +108,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Filters
Vector256<byte> zero = Vector256<byte>.Zero; Vector256<byte> zero = Vector256<byte>.Zero;
Vector256<int> sumAccumulator = Vector256<int>.Zero; Vector256<int> sumAccumulator = Vector256<int>.Zero;
for (int xLeft = x - bytesPerPixel; x + Vector256<byte>.Count <= scanline.Length; xLeft += Vector256<byte>.Count) for (nint xLeft = x - bytesPerPixel; x <= scanline.Length - Vector256<byte>.Count; xLeft += Vector256<byte>.Count)
{ {
Vector256<byte> scan = Unsafe.As<byte, Vector256<byte>>(ref Unsafe.Add(ref scanBaseRef, x)); Vector256<byte> scan = Unsafe.As<byte, Vector256<byte>>(ref Unsafe.Add(ref scanBaseRef, x));
Vector256<byte> prev = Unsafe.As<byte, Vector256<byte>>(ref Unsafe.Add(ref scanBaseRef, xLeft)); Vector256<byte> prev = Unsafe.As<byte, Vector256<byte>>(ref Unsafe.Add(ref scanBaseRef, xLeft));
@ -126,7 +126,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Filters
{ {
Vector<uint> sumAccumulator = Vector<uint>.Zero; Vector<uint> sumAccumulator = Vector<uint>.Zero;
for (int xLeft = x - bytesPerPixel; x + Vector<byte>.Count <= scanline.Length; xLeft += Vector<byte>.Count) for (nint xLeft = x - bytesPerPixel; x <= scanline.Length - Vector<byte>.Count; xLeft += Vector<byte>.Count)
{ {
Vector<byte> scan = Unsafe.As<byte, Vector<byte>>(ref Unsafe.Add(ref scanBaseRef, x)); Vector<byte> scan = Unsafe.As<byte, Vector<byte>>(ref Unsafe.Add(ref scanBaseRef, x));
Vector<byte> prev = Unsafe.As<byte, Vector<byte>>(ref Unsafe.Add(ref scanBaseRef, xLeft)); Vector<byte> prev = Unsafe.As<byte, Vector<byte>>(ref Unsafe.Add(ref scanBaseRef, xLeft));
@ -144,7 +144,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Filters
} }
} }
for (int xLeft = x - bytesPerPixel; x < scanline.Length; ++xLeft /* Note: ++x happens in the body to avoid one add operation */) for (nint xLeft = x - bytesPerPixel; x < scanline.Length; ++xLeft /* Note: ++x happens in the body to avoid one add operation */)
{ {
byte scan = Unsafe.Add(ref scanBaseRef, x); byte scan = Unsafe.Add(ref scanBaseRef, x);
byte prev = Unsafe.Add(ref scanBaseRef, xLeft); byte prev = Unsafe.Add(ref scanBaseRef, xLeft);
@ -153,8 +153,6 @@ namespace SixLabors.ImageSharp.Formats.Png.Filters
res = (byte)(scan - prev); res = (byte)(scan - prev);
sum += Numerics.Abs(unchecked((sbyte)res)); sum += Numerics.Abs(unchecked((sbyte)res));
} }
sum--;
} }
} }
} }

26
src/ImageSharp/Formats/Png/Filters/UpFilter.cs

@ -49,8 +49,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Filters
// Up(x) + Prior(x) // Up(x) + Prior(x)
int rb = scanline.Length; int rb = scanline.Length;
nint offset = 1; nint offset = 1;
const int bytesPerBatch = 32; while (rb >= Vector256<byte>.Count)
while (rb >= bytesPerBatch)
{ {
ref byte scanRef = ref Unsafe.Add(ref scanBaseRef, offset); ref byte scanRef = ref Unsafe.Add(ref scanBaseRef, offset);
Vector256<byte> current = Unsafe.As<byte, Vector256<byte>>(ref scanRef); Vector256<byte> current = Unsafe.As<byte, Vector256<byte>>(ref scanRef);
@ -59,8 +58,8 @@ namespace SixLabors.ImageSharp.Formats.Png.Filters
Vector256<byte> sum = Avx2.Add(up, current); Vector256<byte> sum = Avx2.Add(up, current);
Unsafe.As<byte, Vector256<byte>>(ref scanRef) = sum; Unsafe.As<byte, Vector256<byte>>(ref scanRef) = sum;
offset += bytesPerBatch; offset += Vector256<byte>.Count;
rb -= bytesPerBatch; rb -= Vector256<byte>.Count;
} }
// Handle left over. // Handle left over.
@ -81,8 +80,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Filters
// Up(x) + Prior(x) // Up(x) + Prior(x)
int rb = scanline.Length; int rb = scanline.Length;
nint offset = 1; nint offset = 1;
const int bytesPerBatch = 16; while (rb >= Vector128<byte>.Count)
while (rb >= bytesPerBatch)
{ {
ref byte scanRef = ref Unsafe.Add(ref scanBaseRef, offset); ref byte scanRef = ref Unsafe.Add(ref scanBaseRef, offset);
Vector128<byte> current = Unsafe.As<byte, Vector128<byte>>(ref scanRef); Vector128<byte> current = Unsafe.As<byte, Vector128<byte>>(ref scanRef);
@ -91,8 +89,8 @@ namespace SixLabors.ImageSharp.Formats.Png.Filters
Vector128<byte> sum = Sse2.Add(up, current); Vector128<byte> sum = Sse2.Add(up, current);
Unsafe.As<byte, Vector128<byte>>(ref scanRef) = sum; Unsafe.As<byte, Vector128<byte>>(ref scanRef) = sum;
offset += bytesPerBatch; offset += Vector128<byte>.Count;
rb -= bytesPerBatch; rb -= Vector128<byte>.Count;
} }
// Handle left over. // Handle left over.
@ -112,7 +110,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Filters
ref byte prevBaseRef = ref MemoryMarshal.GetReference(previousScanline); ref byte prevBaseRef = ref MemoryMarshal.GetReference(previousScanline);
// Up(x) + Prior(x) // Up(x) + Prior(x)
for (int x = 1; x < scanline.Length; x++) for (nint x = 1; x < scanline.Length; x++)
{ {
ref byte scan = ref Unsafe.Add(ref scanBaseRef, x); ref byte scan = ref Unsafe.Add(ref scanBaseRef, x);
byte above = Unsafe.Add(ref prevBaseRef, x); byte above = Unsafe.Add(ref prevBaseRef, x);
@ -139,16 +137,16 @@ namespace SixLabors.ImageSharp.Formats.Png.Filters
sum = 0; sum = 0;
// Up(x) = Raw(x) - Prior(x) // Up(x) = Raw(x) - Prior(x)
resultBaseRef = 2; resultBaseRef = (byte)FilterType.Up;
int x = 0; nint x = 0;
if (Avx2.IsSupported) if (Avx2.IsSupported)
{ {
Vector256<byte> zero = Vector256<byte>.Zero; Vector256<byte> zero = Vector256<byte>.Zero;
Vector256<int> sumAccumulator = Vector256<int>.Zero; Vector256<int> sumAccumulator = Vector256<int>.Zero;
for (; x + Vector256<byte>.Count <= scanline.Length;) for (; x <= scanline.Length - Vector256<byte>.Count;)
{ {
Vector256<byte> scan = Unsafe.As<byte, Vector256<byte>>(ref Unsafe.Add(ref scanBaseRef, x)); Vector256<byte> scan = Unsafe.As<byte, Vector256<byte>>(ref Unsafe.Add(ref scanBaseRef, x));
Vector256<byte> above = Unsafe.As<byte, Vector256<byte>>(ref Unsafe.Add(ref prevBaseRef, x)); Vector256<byte> above = Unsafe.As<byte, Vector256<byte>>(ref Unsafe.Add(ref prevBaseRef, x));
@ -166,7 +164,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Filters
{ {
Vector<uint> sumAccumulator = Vector<uint>.Zero; Vector<uint> sumAccumulator = Vector<uint>.Zero;
for (; x + Vector<byte>.Count <= scanline.Length;) for (; x <= scanline.Length - Vector<byte>.Count;)
{ {
Vector<byte> scan = Unsafe.As<byte, Vector<byte>>(ref Unsafe.Add(ref scanBaseRef, x)); Vector<byte> scan = Unsafe.As<byte, Vector<byte>>(ref Unsafe.Add(ref scanBaseRef, x));
Vector<byte> above = Unsafe.As<byte, Vector<byte>>(ref Unsafe.Add(ref prevBaseRef, x)); Vector<byte> above = Unsafe.As<byte, Vector<byte>>(ref Unsafe.Add(ref prevBaseRef, x));
@ -193,8 +191,6 @@ namespace SixLabors.ImageSharp.Formats.Png.Filters
res = (byte)(scan - above); res = (byte)(scan - above);
sum += Numerics.Abs(unchecked((sbyte)res)); sum += Numerics.Abs(unchecked((sbyte)res));
} }
sum -= 2;
} }
} }
} }

10
tests/ImageSharp.Tests/Formats/Png/ReferenceImplementations.cs

@ -24,7 +24,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void EncodePaethFilter(ReadOnlySpan<byte> scanline, Span<byte> previousScanline, Span<byte> result, int bytesPerPixel, out int sum) public static void EncodePaethFilter(ReadOnlySpan<byte> scanline, Span<byte> previousScanline, Span<byte> result, int bytesPerPixel, out int sum)
{ {
DebugGuard.MustBeSameSized<byte>(scanline, previousScanline, nameof(scanline)); DebugGuard.MustBeSameSized(scanline, previousScanline, nameof(scanline));
DebugGuard.MustBeSizedAtLeast(result, scanline, nameof(result)); DebugGuard.MustBeSizedAtLeast(result, scanline, nameof(result));
ref byte scanBaseRef = ref MemoryMarshal.GetReference(scanline); ref byte scanBaseRef = ref MemoryMarshal.GetReference(scanline);
@ -57,8 +57,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png
res = (byte)(scan - PaethPredictor(left, above, upperLeft)); res = (byte)(scan - PaethPredictor(left, above, upperLeft));
sum += Numerics.Abs(unchecked((sbyte)res)); sum += Numerics.Abs(unchecked((sbyte)res));
} }
sum -= 4;
} }
/// <summary> /// <summary>
@ -99,8 +97,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png
res = (byte)(scan - prev); res = (byte)(scan - prev);
sum += Numerics.Abs(unchecked((sbyte)res)); sum += Numerics.Abs(unchecked((sbyte)res));
} }
sum -= 1;
} }
/// <summary> /// <summary>
@ -135,8 +131,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png
res = (byte)(scan - above); res = (byte)(scan - above);
sum += Numerics.Abs(unchecked((sbyte)res)); sum += Numerics.Abs(unchecked((sbyte)res));
} }
sum -= 2;
} }
/// <summary> /// <summary>
@ -182,8 +176,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png
res = (byte)(scan - Average(left, above)); res = (byte)(scan - Average(left, above));
sum += Numerics.Abs(unchecked((sbyte)res)); sum += Numerics.Abs(unchecked((sbyte)res));
} }
sum -= 3;
} }
/// <summary> /// <summary>

Loading…
Cancel
Save