diff --git a/src/ImageSharp/Formats/Png/Filters/UpFilter.cs b/src/ImageSharp/Formats/Png/Filters/UpFilter.cs
index 7e0286991b..2d2a442a19 100644
--- a/src/ImageSharp/Formats/Png/Filters/UpFilter.cs
+++ b/src/ImageSharp/Formats/Png/Filters/UpFilter.cs
@@ -21,7 +21,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Filters
internal static class UpFilter
{
///
- /// Decodes the scanline
+ /// Decodes a scanline, which was filtered with the up filter.
///
/// The scanline to decode
/// The previous scanline.
@@ -30,6 +30,55 @@ namespace SixLabors.ImageSharp.Formats.Png.Filters
{
DebugGuard.MustBeSameSized(scanline, previousScanline, nameof(scanline));
+#if SUPPORTS_RUNTIME_INTRINSICS
+ if (Sse2.IsSupported)
+ {
+ DecodeSse2(scanline, previousScanline);
+ }
+ else
+#endif
+ {
+ DecodeScalar(scanline, previousScanline);
+ }
+ }
+
+#if SUPPORTS_RUNTIME_INTRINSICS
+ private static void DecodeSse2(Span scanline, Span previousScanline)
+ {
+ ref byte scanBaseRef = ref MemoryMarshal.GetReference(scanline);
+ ref byte prevBaseRef = ref MemoryMarshal.GetReference(previousScanline);
+
+ // Up(x) + Prior(x)
+ int rb = scanline.Length;
+ int offset = 1;
+ const int bytesPerBatch = 16;
+ while (rb >= bytesPerBatch)
+ {
+ ref byte scanRef = ref Unsafe.Add(ref scanBaseRef, offset);
+ Vector128 current = Unsafe.As>(ref scanRef);
+ Vector128 up = Unsafe.As>(ref Unsafe.Add(ref prevBaseRef, offset));
+
+ Vector128 sum = Sse2.Add(up, current);
+ Unsafe.As>(ref scanRef) = sum;
+
+ offset += bytesPerBatch;
+ rb -= bytesPerBatch;
+ }
+
+ // Handle left over.
+ for (int i = offset; i < scanline.Length; i++)
+ {
+ ref byte scan = ref Unsafe.Add(ref scanBaseRef, offset);
+ byte above = Unsafe.Add(ref prevBaseRef, offset);
+ scan = (byte)(scan + above);
+ offset++;
+ }
+ }
+#endif
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static void DecodeScalar(Span scanline, Span previousScanline)
+ {
ref byte scanBaseRef = ref MemoryMarshal.GetReference(scanline);
ref byte prevBaseRef = ref MemoryMarshal.GetReference(previousScanline);
@@ -43,12 +92,12 @@ namespace SixLabors.ImageSharp.Formats.Png.Filters
}
///
- /// Encodes the scanline
+ /// Encodes a scanline with the up filter applied.
///
- /// The scanline to encode
+ /// The scanline to encode.
/// The previous scanline.
/// The filtered scanline result.
- /// The sum of the total variance of the filtered row
+ /// The sum of the total variance of the filtered row.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Encode(ReadOnlySpan scanline, ReadOnlySpan previousScanline, Span result, out int sum)
{