Browse Source

Vectorized PaethFilter

pull/1630/head
TechPizza 5 years ago
parent
commit
02d0a808c3
  1. 69
      src/ImageSharp/Formats/Png/Filters/PaethFilter.cs

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

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
@ -82,6 +83,43 @@ namespace SixLabors.ImageSharp.Formats.Png.Filters
sum += Numerics.Abs(unchecked((sbyte)res));
}
#if SUPPORTS_RUNTIME_INTRINSICS
if (Vector.IsHardwareAccelerated)
{
Vector<int> sumAccumulator = Vector<int>.Zero;
for (int xLeft = x - bytesPerPixel; x + Vector<byte>.Count <= scanline.Length; xLeft += Vector<byte>.Count)
{
var scan = new Vector<byte>(scanline.Slice(x));
var left = new Vector<byte>(scanline.Slice(xLeft));
var above = new Vector<byte>(previousScanline.Slice(x));
var upperLeft = new Vector<byte>(previousScanline.Slice(xLeft));
Vector<byte> res = scan - PaethPredictor(left, above, upperLeft);
res.CopyTo(result.Slice(x + 1)); // + 1 to skip filter type
x += Vector<byte>.Count;
Vector.Widen(
Vector.Abs(Vector.AsVectorSByte(res)),
out Vector<short> shortLow,
out Vector<short> shortHigh);
Vector.Widen(shortLow, out Vector<int> intLow, out Vector<int> intHigh);
sumAccumulator += intLow;
sumAccumulator += intHigh;
Vector.Widen(shortHigh, out intLow, out intHigh);
sumAccumulator += intLow;
sumAccumulator += intHigh;
}
for (int i = 0; i < Vector<int>.Count; i++)
{
sum += sumAccumulator[i];
}
}
#endif
for (int 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);
@ -127,5 +165,36 @@ namespace SixLabors.ImageSharp.Formats.Png.Filters
return 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(above, out Vector<ushort> b1, out Vector<ushort> b2);
Vector.Widen(upperLeft, out Vector<ushort> c1, out Vector<ushort> c2);
Vector<short> p1 = PaethPredictor(Vector.AsVectorInt16(a1), Vector.AsVectorInt16(b1), Vector.AsVectorInt16(c1));
Vector<short> p2 = PaethPredictor(Vector.AsVectorInt16(a2), Vector.AsVectorInt16(b2), Vector.AsVectorInt16(c2));
return Vector.AsVectorByte(Vector.Narrow(p1, p2));
}
private static Vector<short> PaethPredictor(Vector<short> left, Vector<short> above, Vector<short> upperLeft)
{
Vector<short> p = left + above - upperLeft;
var pa = Vector.Abs(p - left);
var pb = Vector.Abs(p - above);
var pc = Vector.Abs(p - upperLeft);
var pa_pb = Vector.LessThanOrEqual(pa, pb);
var pa_pc = Vector.LessThanOrEqual(pa, pc);
var pb_pc = Vector.LessThanOrEqual(pb, pc);
return Vector.ConditionalSelect(
condition: Vector.BitwiseAnd(pa_pb, pa_pc),
left: left,
right: Vector.ConditionalSelect(
condition: pb_pc,
left: above,
right: upperLeft));
}
}
}

Loading…
Cancel
Save