From ea031c803d71b3a69101aa56aa5d7391b53cf605 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Fri, 18 Dec 2020 11:36:16 +0100 Subject: [PATCH] Attempt to use SSE in Subtract-Green Transform --- .../Formats/WebP/Lossless/LosslessUtils.cs | 80 ++++++++++++++++++- 1 file changed, 77 insertions(+), 3 deletions(-) diff --git a/src/ImageSharp/Formats/WebP/Lossless/LosslessUtils.cs b/src/ImageSharp/Formats/WebP/Lossless/LosslessUtils.cs index b37a9dd3a6..7121a06cd2 100644 --- a/src/ImageSharp/Formats/WebP/Lossless/LosslessUtils.cs +++ b/src/ImageSharp/Formats/WebP/Lossless/LosslessUtils.cs @@ -4,9 +4,13 @@ using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; - using SixLabors.ImageSharp.Memory; +#if SUPPORTS_RUNTIME_INTRINSICS +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; +#endif + namespace SixLabors.ImageSharp.Formats.Experimental.Webp.Lossless { /// @@ -98,7 +102,42 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Webp.Lossless /// The pixel data to apply the transformation. public static void AddGreenToBlueAndRed(Span pixelData) { - for (int i = 0; i < pixelData.Length; i++) +#if SUPPORTS_RUNTIME_INTRINSICS + if (Sse.IsSupported) + { + var mask = SimdUtils.Shuffle.MmShuffle(2, 2, 0, 0); + int numPixels = pixelData.Length; + int i; + fixed (uint* p = pixelData) + { + for (i = 0; i < numPixels; i += 4) + { + var idx = (ushort*)p + i; + Vector128 input = Sse2.LoadVector128(idx); + Vector128 a = Sse2.ShiftRightLogical(input.AsUInt16(), 8); // 0 a 0 g + Vector128 b = Sse2.ShuffleLow(a, mask); + Vector128 c = Sse2.ShuffleHigh(b, mask); // 0g0g + Vector128 output = Sse2.Add(input, c); + Sse2.Store(idx, output); + } + + if (i != numPixels) + { + AddGreenToBlueAndRedSequential(pixelData.Slice(i)); + } + } + } + else +#endif + { + AddGreenToBlueAndRedSequential(pixelData); + } + } + + private static void AddGreenToBlueAndRedSequential(Span pixelData) + { + int numPixels = pixelData.Length; + for (int i = 0; i < numPixels; i++) { uint argb = pixelData[i]; uint green = (argb >> 8) & 0xff; @@ -109,8 +148,43 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Webp.Lossless } } - public static void SubtractGreenFromBlueAndRed(Span pixelData, int numPixels) + public static void SubtractGreenFromBlueAndRed(Span pixelData) + { +#if SUPPORTS_RUNTIME_INTRINSICS + if (Sse.IsSupported) + { + var mask = SimdUtils.Shuffle.MmShuffle(2, 2, 0, 0); + int numPixels = pixelData.Length; + int i; + fixed (uint* p = pixelData) + { + for (i = 0; i < numPixels; i += 4) + { + var idx = (ushort*)p + i; + Vector128 input = Sse2.LoadVector128(idx); + Vector128 a = Sse2.ShiftRightLogical(input.AsUInt16(), 8); // 0 a 0 g + Vector128 b = Sse2.ShuffleLow(a, mask); + Vector128 c = Sse2.ShuffleHigh(b, mask); // 0g0g + Vector128 output = Sse2.Subtract(input, c); + Sse2.Store(idx, output); + } + + if (i != numPixels) + { + SubtractGreenFromBlueAndRedSequential(pixelData.Slice(i)); + } + } + } + else +#endif + { + SubtractGreenFromBlueAndRedSequential(pixelData); + } + } + + private static void SubtractGreenFromBlueAndRedSequential(Span pixelData) { + int numPixels = pixelData.Length; for (int i = 0; i < numPixels; i++) { uint argb = pixelData[i];