From 1c726da0df83789ce0dcce77271d81524a49a1e3 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 25 Jul 2026 23:24:10 +1000 Subject: [PATCH] Clean up normalized SIMD pipelines --- .../ColorProfileConverterExtensionsIcc.cs | 9 +- .../Common/Helpers/Shuffle/IPad3Shuffle4.cs | 33 +- .../Common/Helpers/Shuffle/IShuffle3.cs | 15 +- .../Common/Helpers/Shuffle/IShuffle4.cs | 219 ++-- .../Common/Helpers/Shuffle/IShuffle4Slice3.cs | 39 +- .../Common/Helpers/SimdUtils.Shuffle.cs | 94 +- .../Common/Helpers/Vector128Utilities.cs | 19 +- .../Common/Helpers/Vector256Utilities.cs | 6 +- .../Common/Helpers/Vector512Utilities.cs | 20 + .../JpegColorConverter.CmykOperator.cs | 90 +- .../JpegColorConverter.GrayScaleOperator.cs | 105 +- .../JpegColorConverter.Operator.cs | 167 +-- .../JpegColorConverter.Packing.cs | 305 +++++ .../JpegColorConverter.RgbOperator.cs | 90 +- .../JpegColorConverter.YCbCrOperator.cs | 150 +-- .../JpegColorConverter.YccKOperator.cs | 4 + .../ColorConverters/JpegColorConverterBase.cs | 135 +-- .../Components/Encoder/ComponentProcessor.cs | 4 + .../Formats/Png/Filters/AverageFilter.cs | 7 +- .../Formats/Png/Filters/IPngFilterOperator.cs | 341 ++---- .../Formats/Png/Filters/PaethFilter.cs | 7 +- .../Formats/Png/Filters/PngFilterEncoder.cs | 121 +- .../Formats/Png/Filters/SubFilter.cs | 12 +- .../Formats/Png/Filters/UpFilter.cs | 10 +- src/ImageSharp/Formats/Webp/AlphaDecoder.cs | 1 + .../Formats/Webp/Lossless/Vp8LHistogram.cs | 18 +- .../AssociatedAlphaPixelBlenders.Generated.cs | 1080 ++++------------- .../AssociatedAlphaPixelBlenders.Generated.tt | 10 +- ...atedAlphaPixelBlender{TPixel,TOperator}.cs | 5 +- .../DefaultPixelBlenders.Generated.cs | 1080 ++++------------- .../DefaultPixelBlenders.Generated.tt | 10 +- .../PixelBlenders/IPixelBlenderOperator.cs | 10 +- .../PixelBlender{TPixel,TOperator}.cs | 302 ++--- .../Utils/Vector4Converters.Affine.cs | 9 +- .../Vector4Converters.AffineOperators.cs | 8 +- .../ColorConversion/CmykColorConversion.cs | 3 +- .../GrayscaleColorConversion.cs | 3 +- .../Jpeg/ColorConversion/JpegColorPacking.cs | 178 +++ .../ColorConversion/JpegColorPackingScalar.cs | 117 ++ .../ColorConversion/RgbColorConversion.cs | 3 +- .../ColorConversion/YCbCrColorConversion.cs | 3 +- .../ColorConversion/YCbCrOperatorAssembly.cs | 244 ---- .../ColorConversion/YccKColorConverter.cs | 3 +- .../Codecs/Png/PngFilterEncodeAssembly.cs | 64 - .../BasicMath/TensorPrimitivesAssembly.cs | 175 --- .../PackedPixelConversionAssembly.cs | 128 -- .../Vector4AffineTransformAssembly.cs | 59 - .../PixelBlenderTraversalAssembly.cs | 327 ----- .../Common/SimdUtilsTests.Shuffle.cs | 70 +- .../Formats/Jpg/JpegColorConverterTests.cs | 105 +- .../Formats/Jpg/JpegColorPackingTests.cs | 168 +++ .../Formats/Png/PngEncoderFilterTests.cs | 79 +- .../PixelFormats/PixelBlenderTests.cs | 16 +- .../PixelFormats/Vector4ConvertersTests.cs | 32 +- 54 files changed, 1839 insertions(+), 4473 deletions(-) create mode 100644 src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.Packing.cs create mode 100644 tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/JpegColorPacking.cs create mode 100644 tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/JpegColorPackingScalar.cs delete mode 100644 tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YCbCrOperatorAssembly.cs delete mode 100644 tests/ImageSharp.Benchmarks/Codecs/Png/PngFilterEncodeAssembly.cs delete mode 100644 tests/ImageSharp.Benchmarks/General/BasicMath/TensorPrimitivesAssembly.cs delete mode 100644 tests/ImageSharp.Benchmarks/General/PixelConversion/PackedPixelConversionAssembly.cs delete mode 100644 tests/ImageSharp.Benchmarks/General/PixelConversion/Vector4AffineTransformAssembly.cs delete mode 100644 tests/ImageSharp.Benchmarks/PixelBlenders/PixelBlenderTraversalAssembly.cs create mode 100644 tests/ImageSharp.Tests/Formats/Jpg/JpegColorPackingTests.cs diff --git a/src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsIcc.cs b/src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsIcc.cs index 78f88932f..7f08a7a9b 100644 --- a/src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsIcc.cs +++ b/src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsIcc.cs @@ -660,6 +660,8 @@ internal static class ColorProfileConverterExtensionsIcc private static void ClipNegative(Span source) { + // Vector4 values are contiguous floats, so flattening preserves the component order + // while allowing one shared tensor traversal to process every channel and SIMD tail. Span values = MemoryMarshal.Cast(source); TensorPrimitives_.Max(values, 0F, values); } @@ -680,10 +682,9 @@ internal static class ColorProfileConverterExtensionsIcc private static void LabToLab(Span source, Span destination, [ConstantExpected] float scale) { - TensorPrimitives_.Multiply( - MemoryMarshal.Cast(source), - scale, - MemoryMarshal.Cast(destination)); + // Reinterpreting both spans exposes all four components to one multiplication traversal; + // the source and destination retain their original Vector4 boundaries after the operation. + TensorPrimitives_.Multiply(MemoryMarshal.Cast(source), scale, MemoryMarshal.Cast(destination)); } private class ConversionParams diff --git a/src/ImageSharp/Common/Helpers/Shuffle/IPad3Shuffle4.cs b/src/ImageSharp/Common/Helpers/Shuffle/IPad3Shuffle4.cs index d9d8e35fc..2c80d8f57 100644 --- a/src/ImageSharp/Common/Helpers/Shuffle/IPad3Shuffle4.cs +++ b/src/ImageSharp/Common/Helpers/Shuffle/IPad3Shuffle4.cs @@ -1,8 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using System.Buffers.Binary; -using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.Intrinsics; using SixLabors.ImageSharp.Common.Helpers; @@ -37,11 +35,18 @@ internal readonly struct WXYZPad3Shuffle4 : IPad3Shuffle4 { /// [MethodImpl(InliningOptions.ShortMethod)] - public static uint Invoke(uint source) => BitOperations.RotateLeft(source, 8); + public static uint Invoke(uint source) + + // The scalar pipeline has already appended opaque W, so the four-component + // WXYZ operator performs the complete remaining permutation. + => WXYZShuffle4.Invoke(source); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector128 Invoke(Vector128 source) + + // Each four-byte group is an XYZW pixel with opaque W. Selecting [3, 0, 1, 2] + // produces WXYZ, and offsets 4, 8, and 12 repeat that rotation for the next pixels. => Vector128_.ShuffleNative(source, Vector128.Create((byte)3, 0, 1, 2, 7, 4, 5, 6, 11, 8, 9, 10, 15, 12, 13, 14)); } @@ -52,11 +57,18 @@ internal readonly struct WZYXPad3Shuffle4 : IPad3Shuffle4 { /// [MethodImpl(InliningOptions.ShortMethod)] - public static uint Invoke(uint source) => BinaryPrimitives.ReverseEndianness(source); + public static uint Invoke(uint source) + + // The scalar pipeline has already appended opaque W, so the four-component + // WZYX operator performs the complete remaining permutation. + => WZYXShuffle4.Invoke(source); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector128 Invoke(Vector128 source) + + // Each four-byte group is an XYZW pixel with opaque W. Selecting [3, 2, 1, 0] + // produces WZYX, and offsets 4, 8, and 12 repeat that reversal for the next pixels. => Vector128_.ShuffleNative(source, Vector128.Create((byte)3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12)); } @@ -68,15 +80,16 @@ internal readonly struct ZYXWPad3Shuffle4 : IPad3Shuffle4 /// [MethodImpl(InliningOptions.ShortMethod)] public static uint Invoke(uint source) - { - // Preserve opaque W and Y while exchanging X and Z. - uint wy = source & 0xFF00FF00; - uint xz = source & 0x00FF00FF; - return wy | BitOperations.RotateLeft(xz, 16); - } + + // The scalar pipeline has already appended opaque W, so the four-component + // ZYXW operator performs the complete remaining permutation. + => ZYXWShuffle4.Invoke(source); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector128 Invoke(Vector128 source) + + // Each four-byte group is an XYZW pixel with opaque W. Selecting [2, 1, 0, 3] + // exchanges X and Z to produce ZYXW, with offsets 4, 8, and 12 covering the next pixels. => Vector128_.ShuffleNative(source, Vector128.Create((byte)2, 1, 0, 3, 6, 5, 4, 7, 10, 9, 8, 11, 14, 13, 12, 15)); } diff --git a/src/ImageSharp/Common/Helpers/Shuffle/IShuffle3.cs b/src/ImageSharp/Common/Helpers/Shuffle/IShuffle3.cs index eab5a41da..7de8af4e4 100644 --- a/src/ImageSharp/Common/Helpers/Shuffle/IShuffle3.cs +++ b/src/ImageSharp/Common/Helpers/Shuffle/IShuffle3.cs @@ -22,16 +22,17 @@ internal readonly struct ZYXShuffle3 : IShuffle3 /// [MethodImpl(InliningOptions.ShortMethod)] public static uint Invoke(uint source) - { - // Y is already centered; shift X and Z directly into each other's byte positions. - uint y = source & 0x0000FF00; - uint x = (source & 0x000000FF) << 16; - uint z = (source & 0x00FF0000) >> 16; - return x | y | z; - } + + // The scalar tail is staged as XYZW with an unused W byte. Reusing the four-component + // ZYXW operator produces ZYX in the low three bytes consumed by the caller. + => ZYXWShuffle4.Invoke(source); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector128 Invoke(Vector128 source) + + // Each four-byte group is a temporary XYZW pixel created by the shuffle pipeline. + // Selecting [2, 1, 0, 3] produces ZYXW, and offsets 4, 8, and 12 repeat that + // permutation for the next pixels. The pipeline subsequently discards every W byte. => Vector128_.ShuffleNative(source, Vector128.Create((byte)2, 1, 0, 3, 6, 5, 4, 7, 10, 9, 8, 11, 14, 13, 12, 15)); } diff --git a/src/ImageSharp/Common/Helpers/Shuffle/IShuffle4.cs b/src/ImageSharp/Common/Helpers/Shuffle/IShuffle4.cs index 2a5a6668f..713de342f 100644 --- a/src/ImageSharp/Common/Helpers/Shuffle/IShuffle4.cs +++ b/src/ImageSharp/Common/Helpers/Shuffle/IShuffle4.cs @@ -27,6 +27,30 @@ internal interface IShuffle4 : IComponentShuffle /// The source pixels. /// The reordered pixels. public static abstract Vector512 Invoke(Vector512 source); + + /// + /// Expands one 128-bit lane mask into absolute indices for a 512-bit shuffle. + /// + /// The indices, from zero through fifteen, for one 128-bit lane. + /// The corresponding absolute indices for all four 128-bit lanes. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector512 ExpandLaneMask(Vector128 laneMask) + { + // A 512-bit vector contains four 128-bit lanes, and each lane contains four packed + // XYZW pixels. The supplied mask addresses bytes 0..15 in the first lane. The managed + // Vector512.Shuffle fallback addresses the complete 64-byte vector, so the same + // permutation must address bytes 16..31, 32..47, and 48..63 in the remaining lanes. + // + // AVX-512BW VPSHUFB instead interprets indices independently within each 128-bit lane + // and uses only the low four bits to select a byte. Adding the lane offsets therefore + // satisfies the managed absolute-index contract without changing the native lane-local + // permutation. + Vector128 lane1 = laneMask + Vector128.Create((byte)16); + Vector128 lane2 = laneMask + Vector128.Create((byte)32); + Vector128 lane3 = laneMask + Vector128.Create((byte)48); + + return Vector512.Create(Vector256.Create(laneMask, lane1), Vector256.Create(lane2, lane3)); + } } /// @@ -37,58 +61,42 @@ internal readonly struct WXYZShuffle4 : IShuffle4 /// [MethodImpl(InliningOptions.ShortMethod)] public static uint Invoke(uint source) - { + // source = [W Z Y X] // ROTL(8, source) = [Z Y X W] - return BitOperations.RotateLeft(source, 8); - } + => BitOperations.RotateLeft(source, 8); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector128 Invoke(Vector128 source) - => Vector128_.ShuffleNative(source, CreateMask()); + => Vector128_.ShuffleNative(source, CreateLaneMask()); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector256 Invoke(Vector256 source) { // AVX2 byte shuffles select within 128-bit lanes, so both halves use the same pixel-local indices. - Vector128 mask = CreateMask(); + Vector128 mask = CreateLaneMask(); return Vector256_.ShufflePerLane(source, Vector256.Create(mask, mask)); } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector512 Invoke(Vector512 source) - => Vector512_.ShuffleNative(source, CreateMask512()); + + // Expand the four-pixel lane permutation across all four 128-bit lanes. + => Vector512_.ShuffleNative(source, IShuffle4.ExpandLaneMask(CreateLaneMask())); /// /// Creates the indices that rotate each XYZW pixel to WXYZ within one 128-bit lane. /// /// The pixel-local byte shuffle indices. [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static Vector128 CreateMask() - => Vector128.Create((byte)3, 0, 1, 2, 7, 4, 5, 6, 11, 8, 9, 10, 15, 12, 13, 14); + private static Vector128 CreateLaneMask() - /// - /// Creates absolute indices for all four 128-bit lanes in a 512-bit vector. - /// - /// The absolute byte shuffle indices. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static Vector512 CreateMask512() - { - // Native vpshufb ignores the lane offsets, while Vector512.Shuffle treats the indices as - // absolute. Encoding both meanings keeps the AVX-512 and managed fallback results identical. - return Vector512.Create( - 0x0605040702010003UL, - 0x0E0D0C0F0A09080BUL, - 0x1615141712111013UL, - 0x1E1D1C1F1A19181BUL, - 0x2625242722212023UL, - 0x2E2D2C2F2A29282BUL, - 0x3635343732313033UL, - 0x3E3D3C3F3A39383BUL).AsByte(); - } + // Each four-byte group is one XYZW pixel. Selecting [3, 0, 1, 2] produces + // WXYZ, and offsets 4, 8, and 12 repeat that permutation for the next pixels. + => Vector128.Create((byte)3, 0, 1, 2, 7, 4, 5, 6, 11, 8, 9, 10, 15, 12, 13, 14); } /// @@ -99,52 +107,42 @@ internal readonly struct WZYXShuffle4 : IShuffle4 /// [MethodImpl(InliningOptions.ShortMethod)] public static uint Invoke(uint source) - { - // Reversing the integer's endianness also reverses the four byte components. - return BinaryPrimitives.ReverseEndianness(source); - } + + // source = [W Z Y X] + // REVERSE(source) = [X Y Z W] + => BinaryPrimitives.ReverseEndianness(source); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector128 Invoke(Vector128 source) - => Vector128_.ShuffleNative(source, CreateMask()); + => Vector128_.ShuffleNative(source, CreateLaneMask()); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector256 Invoke(Vector256 source) { - Vector128 mask = CreateMask(); + // AVX2 byte shuffles select within 128-bit lanes, so both halves use the same pixel-local indices. + Vector128 mask = CreateLaneMask(); return Vector256_.ShufflePerLane(source, Vector256.Create(mask, mask)); } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector512 Invoke(Vector512 source) - => Vector512_.ShuffleNative(source, CreateMask512()); + + // Expand the four-pixel lane permutation across all four 128-bit lanes. + => Vector512_.ShuffleNative(source, IShuffle4.ExpandLaneMask(CreateLaneMask())); /// /// Creates the indices that reverse each XYZW pixel to WZYX within one 128-bit lane. /// /// The pixel-local byte shuffle indices. [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static Vector128 CreateMask() - => Vector128.Create((byte)3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12); + private static Vector128 CreateLaneMask() - /// - /// Creates absolute indices for all four 128-bit lanes in a 512-bit vector. - /// - /// The absolute byte shuffle indices. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static Vector512 CreateMask512() - => Vector512.Create( - 0x0405060700010203UL, - 0x0C0D0E0F08090A0BUL, - 0x1415161710111213UL, - 0x1C1D1E1F18191A1BUL, - 0x2425262720212223UL, - 0x2C2D2E2F28292A2BUL, - 0x3435363730313233UL, - 0x3C3D3E3F38393A3BUL).AsByte(); + // Each four-byte group is one XYZW pixel. Selecting [3, 2, 1, 0] produces + // WZYX, and offsets 4, 8, and 12 repeat that reversal for the next pixels. + => Vector128.Create((byte)3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12); } /// @@ -155,53 +153,42 @@ internal readonly struct YZWXShuffle4 : IShuffle4 /// [MethodImpl(InliningOptions.ShortMethod)] public static uint Invoke(uint source) - { + // source = [W Z Y X] // ROTR(8, source) = [X W Z Y] - return BitOperations.RotateRight(source, 8); - } + => BitOperations.RotateRight(source, 8); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector128 Invoke(Vector128 source) - => Vector128_.ShuffleNative(source, CreateMask()); + => Vector128_.ShuffleNative(source, CreateLaneMask()); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector256 Invoke(Vector256 source) { - Vector128 mask = CreateMask(); + // AVX2 byte shuffles select within 128-bit lanes, so both halves use the same pixel-local indices. + Vector128 mask = CreateLaneMask(); return Vector256_.ShufflePerLane(source, Vector256.Create(mask, mask)); } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector512 Invoke(Vector512 source) - => Vector512_.ShuffleNative(source, CreateMask512()); + + // Expand the four-pixel lane permutation across all four 128-bit lanes. + => Vector512_.ShuffleNative(source, IShuffle4.ExpandLaneMask(CreateLaneMask())); /// /// Creates the indices that rotate each XYZW pixel to YZWX within one 128-bit lane. /// /// The pixel-local byte shuffle indices. [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static Vector128 CreateMask() - => Vector128.Create((byte)1, 2, 3, 0, 5, 6, 7, 4, 9, 10, 11, 8, 13, 14, 15, 12); + private static Vector128 CreateLaneMask() - /// - /// Creates absolute indices for all four 128-bit lanes in a 512-bit vector. - /// - /// The absolute byte shuffle indices. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static Vector512 CreateMask512() - => Vector512.Create( - 0x0407060500030201UL, - 0x0C0F0E0D080B0A09UL, - 0x1417161510131211UL, - 0x1C1F1E1D181B1A19UL, - 0x2427262520232221UL, - 0x2C2F2E2D282B2A29UL, - 0x3437363530333231UL, - 0x3C3F3E3D383B3A39UL).AsByte(); + // Each four-byte group is one XYZW pixel. Selecting [1, 2, 3, 0] produces + // YZWX, and offsets 4, 8, and 12 repeat that rotation for the next pixels. + => Vector128.Create((byte)1, 2, 3, 0, 5, 6, 7, 4, 9, 10, 11, 8, 13, 14, 15, 12); } /// @@ -212,54 +199,44 @@ internal readonly struct ZYXWShuffle4 : IShuffle4 /// [MethodImpl(InliningOptions.ShortMethod)] public static uint Invoke(uint source) - { - // Preserve W and Y while rotating the masked X/Z bytes into each other's positions. - uint wy = source & 0xFF00FF00; - uint xz = source & 0x00FF00FF; - return wy | BitOperations.RotateLeft(xz, 16); - } + + // source = [W Z Y X] + // source & 0xFF00FF00 = [W 0 Y 0] + // ROTL(source & 0x00FF00FF) = [0 X 0 Z] + // combined = [W X Y Z] + => (source & 0xFF00FF00) | BitOperations.RotateLeft(source & 0x00FF00FF, 16); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector128 Invoke(Vector128 source) - => Vector128_.ShuffleNative(source, CreateMask()); + => Vector128_.ShuffleNative(source, CreateLaneMask()); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector256 Invoke(Vector256 source) { - Vector128 mask = CreateMask(); + // AVX2 byte shuffles select within 128-bit lanes, so both halves use the same pixel-local indices. + Vector128 mask = CreateLaneMask(); return Vector256_.ShufflePerLane(source, Vector256.Create(mask, mask)); } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector512 Invoke(Vector512 source) - => Vector512_.ShuffleNative(source, CreateMask512()); + + // Expand the four-pixel lane permutation across all four 128-bit lanes. + => Vector512_.ShuffleNative(source, IShuffle4.ExpandLaneMask(CreateLaneMask())); /// /// Creates the indices that exchange X and Z in each XYZW pixel within one 128-bit lane. /// /// The pixel-local byte shuffle indices. [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static Vector128 CreateMask() - => Vector128.Create((byte)2, 1, 0, 3, 6, 5, 4, 7, 10, 9, 8, 11, 14, 13, 12, 15); + private static Vector128 CreateLaneMask() - /// - /// Creates absolute indices for all four 128-bit lanes in a 512-bit vector. - /// - /// The absolute byte shuffle indices. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static Vector512 CreateMask512() - => Vector512.Create( - 0x0704050603000102UL, - 0x0F0C0D0E0B08090AUL, - 0x1714151613101112UL, - 0x1F1C1D1E1B18191AUL, - 0x2724252623202122UL, - 0x2F2C2D2E2B28292AUL, - 0x3734353633303132UL, - 0x3F3C3D3E3B38393AUL).AsByte(); + // Each four-byte group is one XYZW pixel. Selecting [2, 1, 0, 3] exchanges + // X and Z to produce ZYXW, with offsets 4, 8, and 12 covering the next pixels. + => Vector128.Create((byte)2, 1, 0, 3, 6, 5, 4, 7, 10, 9, 8, 11, 14, 13, 12, 15); } /// @@ -270,52 +247,42 @@ internal readonly struct XWZYShuffle4 : IShuffle4 /// [MethodImpl(InliningOptions.ShortMethod)] public static uint Invoke(uint source) - { - // Preserve X and Z while rotating the masked Y/W bytes into each other's positions. - uint xz = source & 0x00FF00FF; - uint yw = source & 0xFF00FF00; - return xz | BitOperations.RotateLeft(yw, 16); - } + + // source = [W Z Y X] + // source & 0x00FF00FF = [0 Z 0 X] + // ROTL(source & 0xFF00FF00) = [Y 0 W 0] + // combined = [Y Z W X] + => (source & 0x00FF00FF) | BitOperations.RotateLeft(source & 0xFF00FF00, 16); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector128 Invoke(Vector128 source) - => Vector128_.ShuffleNative(source, CreateMask()); + => Vector128_.ShuffleNative(source, CreateLaneMask()); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector256 Invoke(Vector256 source) { - Vector128 mask = CreateMask(); + // AVX2 byte shuffles select within 128-bit lanes, so both halves use the same pixel-local indices. + Vector128 mask = CreateLaneMask(); return Vector256_.ShufflePerLane(source, Vector256.Create(mask, mask)); } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector512 Invoke(Vector512 source) - => Vector512_.ShuffleNative(source, CreateMask512()); + + // Expand the four-pixel lane permutation across all four 128-bit lanes. + => Vector512_.ShuffleNative(source, IShuffle4.ExpandLaneMask(CreateLaneMask())); /// /// Creates the indices that exchange Y and W in each XYZW pixel within one 128-bit lane. /// /// The pixel-local byte shuffle indices. [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static Vector128 CreateMask() - => Vector128.Create((byte)0, 3, 2, 1, 4, 7, 6, 5, 8, 11, 10, 9, 12, 15, 14, 13); + private static Vector128 CreateLaneMask() - /// - /// Creates absolute indices for all four 128-bit lanes in a 512-bit vector. - /// - /// The absolute byte shuffle indices. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static Vector512 CreateMask512() - => Vector512.Create( - 0x0506070401020300UL, - 0x0D0E0F0C090A0B08UL, - 0x1516171411121310UL, - 0x1D1E1F1C191A1B18UL, - 0x2526272421222320UL, - 0x2D2E2F2C292A2B28UL, - 0x3536373431323330UL, - 0x3D3E3F3C393A3B38UL).AsByte(); + // Each four-byte group is one XYZW pixel. Selecting [0, 3, 2, 1] exchanges + // Y and W to produce XWZY, with offsets 4, 8, and 12 covering the next pixels. + => Vector128.Create((byte)0, 3, 2, 1, 4, 7, 6, 5, 8, 11, 10, 9, 12, 15, 14, 13); } diff --git a/src/ImageSharp/Common/Helpers/Shuffle/IShuffle4Slice3.cs b/src/ImageSharp/Common/Helpers/Shuffle/IShuffle4Slice3.cs index 17ec503e5..8f32a5a6c 100644 --- a/src/ImageSharp/Common/Helpers/Shuffle/IShuffle4Slice3.cs +++ b/src/ImageSharp/Common/Helpers/Shuffle/IShuffle4Slice3.cs @@ -1,8 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using System.Buffers.Binary; -using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Intrinsics; @@ -38,11 +36,19 @@ internal readonly struct YZWXShuffle4Slice3 : IShuffle4Slice3 { /// [MethodImpl(InliningOptions.ShortMethod)] - public static uint Invoke(uint source) => BitOperations.RotateRight(source, 8); + public static uint Invoke(uint source) + + // Reuse the four-component rotation; the caller stores only the low YZW + // bytes and therefore discards the rotated X byte. + => YZWXShuffle4.Invoke(source); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector128 Invoke(Vector128 source) + + // Each four-byte group is an XYZW pixel. Selecting [1, 2, 3, 0] produces + // YZWX, and offsets 4, 8, and 12 repeat that rotation for the next pixels. + // The surrounding pipeline subsequently removes every fourth byte. => Vector128_.ShuffleNative(source, Vector128.Create((byte)1, 2, 3, 0, 5, 6, 7, 4, 9, 10, 11, 8, 13, 14, 15, 12)); } @@ -53,11 +59,19 @@ internal readonly struct WZYXShuffle4Slice3 : IShuffle4Slice3 { /// [MethodImpl(InliningOptions.ShortMethod)] - public static uint Invoke(uint source) => BinaryPrimitives.ReverseEndianness(source); + public static uint Invoke(uint source) + + // Reuse the four-component reversal; the caller stores only the low WZY + // bytes and therefore discards the reversed X byte. + => WZYXShuffle4.Invoke(source); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector128 Invoke(Vector128 source) + + // Each four-byte group is an XYZW pixel. Selecting [3, 2, 1, 0] produces + // WZYX, and offsets 4, 8, and 12 repeat that reversal for the next pixels. + // The surrounding pipeline subsequently removes every fourth byte. => Vector128_.ShuffleNative(source, Vector128.Create((byte)3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12)); } @@ -69,19 +83,24 @@ internal readonly struct ZYXWShuffle4Slice3 : IShuffle4Slice3 /// [MethodImpl(InliningOptions.ShortMethod)] public static uint Invoke(uint source) - { - // Preserve W and Y while exchanging X and Z; W is subsequently discarded. - uint wy = source & 0xFF00FF00; - uint xz = source & 0x00FF00FF; - return wy | BitOperations.RotateLeft(xz, 16); - } + + // Reuse the four-component exchange; the caller stores only the low ZYX + // bytes and therefore discards the preserved W byte. + => ZYXWShuffle4.Invoke(source); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector128 Invoke(Vector128 source) + + // Each four-byte group is an XYZW pixel. Selecting [2, 1, 0, 3] produces + // ZYXW, and offsets 4, 8, and 12 repeat that exchange for the next pixels. + // The surrounding pipeline subsequently removes every fourth byte. => Vector128_.ShuffleNative(source, Vector128.Create((byte)2, 1, 0, 3, 6, 5, 4, 7, 10, 9, 8, 11, 14, 13, 12, 15)); } +/// +/// Represents one tightly packed three-byte value for scalar four-to-three component writes. +/// [StructLayout(LayoutKind.Explicit, Size = 3)] internal readonly struct Byte3 { diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.Shuffle.cs b/src/ImageSharp/Common/Helpers/SimdUtils.Shuffle.cs index e709cc8d4..0eeb4832f 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.Shuffle.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.Shuffle.cs @@ -67,22 +67,17 @@ internal static partial class SimdUtils { // Four independent vectors amortize loop control and expose enough work for the CPU // to overlap loads, byte shuffles, and stores without changing pixel ordering. - TShuffle.Invoke(Vector512.LoadUnsafe(ref sourceBase, (nuint)i)) - .StoreUnsafe(ref destinationBase, (nuint)i); - TShuffle.Invoke(Vector512.LoadUnsafe(ref sourceBase, (nuint)(i + Vector512.Count))) - .StoreUnsafe(ref destinationBase, (nuint)(i + Vector512.Count)); - TShuffle.Invoke(Vector512.LoadUnsafe(ref sourceBase, (nuint)(i + (Vector512.Count * 2)))) - .StoreUnsafe(ref destinationBase, (nuint)(i + (Vector512.Count * 2))); - TShuffle.Invoke(Vector512.LoadUnsafe(ref sourceBase, (nuint)(i + (Vector512.Count * 3)))) - .StoreUnsafe(ref destinationBase, (nuint)(i + (Vector512.Count * 3))); + TShuffle.Invoke(Vector512.LoadUnsafe(ref sourceBase, (nuint)i)).StoreUnsafe(ref destinationBase, (nuint)i); + TShuffle.Invoke(Vector512.LoadUnsafe(ref sourceBase, (nuint)(i + Vector512.Count))).StoreUnsafe(ref destinationBase, (nuint)(i + Vector512.Count)); + TShuffle.Invoke(Vector512.LoadUnsafe(ref sourceBase, (nuint)(i + (Vector512.Count * 2)))).StoreUnsafe(ref destinationBase, (nuint)(i + (Vector512.Count * 2))); + TShuffle.Invoke(Vector512.LoadUnsafe(ref sourceBase, (nuint)(i + (Vector512.Count * 3)))).StoreUnsafe(ref destinationBase, (nuint)(i + (Vector512.Count * 3))); } int oneVectorFromEnd = length - Vector512.Count; for (; i <= oneVectorFromEnd; i += Vector512.Count) { - TShuffle.Invoke(Vector512.LoadUnsafe(ref sourceBase, (nuint)i)) - .StoreUnsafe(ref destinationBase, (nuint)i); + TShuffle.Invoke(Vector512.LoadUnsafe(ref sourceBase, (nuint)i)).StoreUnsafe(ref destinationBase, (nuint)i); } } @@ -92,22 +87,17 @@ internal static partial class SimdUtils for (; i <= fourVectorsFromEnd; i += Vector256.Count * 4) { - TShuffle.Invoke(Vector256.LoadUnsafe(ref sourceBase, (nuint)i)) - .StoreUnsafe(ref destinationBase, (nuint)i); - TShuffle.Invoke(Vector256.LoadUnsafe(ref sourceBase, (nuint)(i + Vector256.Count))) - .StoreUnsafe(ref destinationBase, (nuint)(i + Vector256.Count)); - TShuffle.Invoke(Vector256.LoadUnsafe(ref sourceBase, (nuint)(i + (Vector256.Count * 2)))) - .StoreUnsafe(ref destinationBase, (nuint)(i + (Vector256.Count * 2))); - TShuffle.Invoke(Vector256.LoadUnsafe(ref sourceBase, (nuint)(i + (Vector256.Count * 3)))) - .StoreUnsafe(ref destinationBase, (nuint)(i + (Vector256.Count * 3))); + TShuffle.Invoke(Vector256.LoadUnsafe(ref sourceBase, (nuint)i)).StoreUnsafe(ref destinationBase, (nuint)i); + TShuffle.Invoke(Vector256.LoadUnsafe(ref sourceBase, (nuint)(i + Vector256.Count))).StoreUnsafe(ref destinationBase, (nuint)(i + Vector256.Count)); + TShuffle.Invoke(Vector256.LoadUnsafe(ref sourceBase, (nuint)(i + (Vector256.Count * 2)))).StoreUnsafe(ref destinationBase, (nuint)(i + (Vector256.Count * 2))); + TShuffle.Invoke(Vector256.LoadUnsafe(ref sourceBase, (nuint)(i + (Vector256.Count * 3)))).StoreUnsafe(ref destinationBase, (nuint)(i + (Vector256.Count * 3))); } int oneVectorFromEnd = length - Vector256.Count; for (; i <= oneVectorFromEnd; i += Vector256.Count) { - TShuffle.Invoke(Vector256.LoadUnsafe(ref sourceBase, (nuint)i)) - .StoreUnsafe(ref destinationBase, (nuint)i); + TShuffle.Invoke(Vector256.LoadUnsafe(ref sourceBase, (nuint)i)).StoreUnsafe(ref destinationBase, (nuint)i); } } @@ -117,22 +107,17 @@ internal static partial class SimdUtils for (; i <= fourVectorsFromEnd; i += Vector128.Count * 4) { - TShuffle.Invoke(Vector128.LoadUnsafe(ref sourceBase, (nuint)i)) - .StoreUnsafe(ref destinationBase, (nuint)i); - TShuffle.Invoke(Vector128.LoadUnsafe(ref sourceBase, (nuint)(i + Vector128.Count))) - .StoreUnsafe(ref destinationBase, (nuint)(i + Vector128.Count)); - TShuffle.Invoke(Vector128.LoadUnsafe(ref sourceBase, (nuint)(i + (Vector128.Count * 2)))) - .StoreUnsafe(ref destinationBase, (nuint)(i + (Vector128.Count * 2))); - TShuffle.Invoke(Vector128.LoadUnsafe(ref sourceBase, (nuint)(i + (Vector128.Count * 3)))) - .StoreUnsafe(ref destinationBase, (nuint)(i + (Vector128.Count * 3))); + TShuffle.Invoke(Vector128.LoadUnsafe(ref sourceBase, (nuint)i)).StoreUnsafe(ref destinationBase, (nuint)i); + TShuffle.Invoke(Vector128.LoadUnsafe(ref sourceBase, (nuint)(i + Vector128.Count))).StoreUnsafe(ref destinationBase, (nuint)(i + Vector128.Count)); + TShuffle.Invoke(Vector128.LoadUnsafe(ref sourceBase, (nuint)(i + (Vector128.Count * 2)))).StoreUnsafe(ref destinationBase, (nuint)(i + (Vector128.Count * 2))); + TShuffle.Invoke(Vector128.LoadUnsafe(ref sourceBase, (nuint)(i + (Vector128.Count * 3)))).StoreUnsafe(ref destinationBase, (nuint)(i + (Vector128.Count * 3))); } int oneVectorFromEnd = length - Vector128.Count; for (; i <= oneVectorFromEnd; i += Vector128.Count) { - TShuffle.Invoke(Vector128.LoadUnsafe(ref sourceBase, (nuint)i)) - .StoreUnsafe(ref destinationBase, (nuint)i); + TShuffle.Invoke(Vector128.LoadUnsafe(ref sourceBase, (nuint)i)).StoreUnsafe(ref destinationBase, (nuint)i); } } @@ -167,15 +152,17 @@ internal static partial class SimdUtils if (Vector128.IsHardwareAccelerated) { - // Each group contains sixteen XYZ pixels in three registers. The pad mask expands - // four triplets per register to XYZW, with 0x80 selecting zero for the temporary W lane. - Vector128 padMask = Vector128.Create( - (byte)0, 1, 2, 0x80, 3, 4, 5, 0x80, 6, 7, 8, 0x80, 9, 10, 11, 0x80); - - // After the operator has reordered padded pixels, these masks remove every temporary - // W lane and repack the four registers into three contiguous XYZ destination registers. - Vector128 sliceMask = Vector128.Create( - (byte)0, 1, 2, 4, 5, 6, 8, 9, 10, 12, 13, 14, 0x80, 0x80, 0x80, 0x80); + // Each group contains sixteen XYZ pixels in three registers. For a register beginning + // [X0,Y0,Z0,X1,Y1,Z1,...], the indices [0,1,2,0x80,3,4,5,0x80,...] + // produce four [X,Y,Z,0] pixels. Index 0x80 selects zero on the native byte-shuffle + // instructions and on the portable helper, creating a temporary W lane for TShuffle. + Vector128 padMask = Vector128.Create((byte)0, 1, 2, 0x80, 3, 4, 5, 0x80, 6, 7, 8, 0x80, 9, 10, 11, 0x80); + + // After TShuffle places the retained components in bytes 0..2 of each four-byte pixel, + // [0,1,2,4,5,6,8,9,10,12,13,14] packs four triplets into twelve bytes. Rotating that + // mask by twelve positions moves the packed bytes four positions right. Alternating the + // two alignments lets AlignRight stitch four twelve-byte results into three full registers. + Vector128 sliceMask = Vector128.Create((byte)0, 1, 2, 4, 5, 6, 8, 9, 10, 12, 13, 14, 0x80, 0x80, 0x80, 0x80); Vector128 sliceEndMask = Vector128_.AlignRight(sliceMask, sliceMask, 12); ref Vector128 sourceVectors = ref Unsafe.As>(ref sourceBase); ref Vector128 destinationVectors = ref Unsafe.As>(ref destinationBase); @@ -284,10 +271,13 @@ internal static partial class SimdUtils if (Vector128.IsHardwareAccelerated) { - // The fixed mask expands four XYZ triplets to four XYZW pixels. The zeroed W bytes - // are then filled with opaque alpha before the selected operator reorders each pixel. - Vector128 padMask = Vector128.Create( - (byte)0, 1, 2, 0x80, 3, 4, 5, 0x80, 6, 7, 8, 0x80, 9, 10, 11, 0x80); + // For source bytes [X0,Y0,Z0,X1,Y1,Z1,...], the indices + // [0,1,2,0x80,3,4,5,0x80,...] form four [X,Y,Z,0] pixels. The native + // and portable shuffle paths both interpret 0x80 as a zero-producing index. + Vector128 padMask = Vector128.Create((byte)0, 1, 2, 0x80, 3, 4, 5, 0x80, 6, 7, 8, 0x80, 9, 10, 11, 0x80); + + // The broadcast ulong has 0xFF in bytes 3 and 7; repeating it across 128 bits + // fills W at byte positions 3, 7, 11, and 15 without modifying X, Y, or Z. Vector128 opaqueAlpha = Vector128.Create(0xFF000000FF000000UL).AsByte(); ref Vector128 sourceVectors = ref Unsafe.As>(ref sourceBase); ref Vector128 destinationVectors = ref Unsafe.As>(ref destinationBase); @@ -366,10 +356,14 @@ internal static partial class SimdUtils if (Vector128.IsHardwareAccelerated) { - // Each operator first places the three retained components in the low bytes of every - // four-byte pixel. These masks then delete the fourth byte and compact sixteen pixels. - Vector128 sliceMask = Vector128.Create( - (byte)0, 1, 2, 4, 5, 6, 8, 9, 10, 12, 13, 14, 0x80, 0x80, 0x80, 0x80); + // Each operator first places the retained components in bytes 0..2 of every four-byte + // pixel. The indices [0,1,2,4,5,6,8,9,10,12,13,14] delete each fourth byte and + // pack four triplets into the low twelve bytes. Indices 0x80 zero the unused bytes. + Vector128 sliceMask = Vector128.Create((byte)0, 1, 2, 4, 5, 6, 8, 9, 10, 12, 13, 14, 0x80, 0x80, 0x80, 0x80); + + // Rotating the mask by twelve moves its packed result four bytes right. Alternating + // shifted and unshifted results gives AlignRight the overlap needed to concatenate + // four twelve-byte groups into three complete destination registers. Vector128 sliceEndMask = Vector128_.AlignRight(sliceMask, sliceMask, 12); ref Vector128 sourceVectors = ref Unsafe.As>(ref sourceBase); ref Vector128 destinationVectors = ref Unsafe.As>(ref destinationBase); @@ -377,8 +371,7 @@ internal static partial class SimdUtils nuint sourceVectorIndex = 0; nuint destinationVectorIndex = 0; - for (; sourceVectorIndex + 3 < sourceVectorCount; - sourceVectorIndex += 4, destinationVectorIndex += 3) + for (; sourceVectorIndex + 3 < sourceVectorCount; sourceVectorIndex += 4, destinationVectorIndex += 3) { // Load and transform all sixteen source pixels before writing the shorter output group. // This preserves forward progress when source and destination begin at the same address. @@ -413,8 +406,7 @@ internal static partial class SimdUtils { // The operator arranges the three retained components at the front of each pixel. // One fixed shuffle then compacts four pixels into the low twelve vector bytes. - Vector128 result = TShuffle.Invoke( - Vector128.LoadUnsafe(ref sourceBase, (nuint)sourceOffset)); + Vector128 result = TShuffle.Invoke(Vector128.LoadUnsafe(ref sourceBase, (nuint)sourceOffset)); result = Vector128_.ShuffleNative(result, sliceMask); diff --git a/src/ImageSharp/Common/Helpers/Vector128Utilities.cs b/src/ImageSharp/Common/Helpers/Vector128Utilities.cs index ce8af4d6f..4a53fdda4 100644 --- a/src/ImageSharp/Common/Helpers/Vector128Utilities.cs +++ b/src/ImageSharp/Common/Helpers/Vector128Utilities.cs @@ -1296,22 +1296,9 @@ internal static class Vector128_ return PackedSimd.SubtractSaturate(left, right); } - // Widen inputs to 16-bit - (Vector128 leftLo, Vector128 leftHi) = Vector128.Widen(left); - (Vector128 rightLo, Vector128 rightHi) = Vector128.Widen(right); - - // Subtract - Vector128 diffLo = leftLo - rightLo; - Vector128 diffHi = leftHi - rightHi; - - // Clamp to signed 8-bit range - Vector128 max = Vector128.Create((ushort)byte.MaxValue); - - diffLo = Clamp(diffLo, Vector128.Zero, max); - diffHi = Clamp(diffHi, Vector128.Zero, max); - - // Narrow back to bytes - return Vector128.Narrow(diffLo, diffHi); + // Subtracting the smaller operand implements the .NET 10 unsigned contract: + // lanes where right exceeds left subtract left from itself and therefore saturate at zero. + return left - Vector128.Min(left, right); } /// diff --git a/src/ImageSharp/Common/Helpers/Vector256Utilities.cs b/src/ImageSharp/Common/Helpers/Vector256Utilities.cs index 1f3ebb35f..681f80013 100644 --- a/src/ImageSharp/Common/Helpers/Vector256Utilities.cs +++ b/src/ImageSharp/Common/Helpers/Vector256Utilities.cs @@ -495,9 +495,9 @@ internal static class Vector256_ return Avx2.SubtractSaturate(left, right); } - return Vector256.Create( - Vector128_.SubtractSaturate(left.GetLower(), right.GetLower()), - Vector128_.SubtractSaturate(left.GetUpper(), right.GetUpper())); + // The .NET 10 portable implementation applies the same saturated operation to + // both 128-bit halves, allowing each half to select its native instruction set. + return Vector256.Create(Vector128_.SubtractSaturate(left.GetLower(), right.GetLower()), Vector128_.SubtractSaturate(left.GetUpper(), right.GetUpper())); } /// diff --git a/src/ImageSharp/Common/Helpers/Vector512Utilities.cs b/src/ImageSharp/Common/Helpers/Vector512Utilities.cs index 0193a51ba..d2c5b4a87 100644 --- a/src/ImageSharp/Common/Helpers/Vector512Utilities.cs +++ b/src/ImageSharp/Common/Helpers/Vector512Utilities.cs @@ -129,6 +129,26 @@ internal static class Vector512_ return Vector512.Create(lower, upper); } + /// + /// Subtracts packed unsigned 8-bit integers in from + /// , saturating negative lane results to zero. + /// + /// The vector from which is subtracted. + /// The vector to subtract from . + /// The element-wise saturated differences. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector512 SubtractSaturate(Vector512 left, Vector512 right) + { + if (Avx512BW.IsSupported) + { + return Avx512BW.SubtractSaturate(left, right); + } + + // This mirrors the .NET 10 portable implementation: recursively processing both + // 256-bit halves preserves lane order and lets each half select its available ISA. + return Vector512.Create(Vector256_.SubtractSaturate(left.GetLower(), right.GetLower()), Vector256_.SubtractSaturate(left.GetUpper(), right.GetUpper())); + } + /// /// Performs a multiplication and a negated addition of the . /// diff --git a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.CmykOperator.cs b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.CmykOperator.cs index dad093124..2f67e0f53 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.CmykOperator.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.CmykOperator.cs @@ -27,14 +27,7 @@ internal abstract partial class JpegColorConverterBase /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void ConvertToRgb( - ref float c0, - ref float c1, - ref float c2, - float c3, - float maximumValue, - float halfValue, - float scale) + public static void ConvertToRgb(ref float c0, ref float c1, ref float c2, float c3, float maximumValue, float halfValue, float scale) { // Adobe-style CMYK stores inverted component samples. Multiplying K by scale twice folds the // two sample-domain divisions into one factor before it modulates the C, M, and Y planes. @@ -46,14 +39,7 @@ internal abstract partial class JpegColorConverterBase /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void ConvertToRgb( - ref Vector128 c0, - ref Vector128 c1, - ref Vector128 c2, - Vector128 c3, - Vector128 maximumValue, - Vector128 halfValue, - Vector128 scale) + public static void ConvertToRgb(ref Vector128 c0, ref Vector128 c1, ref Vector128 c2, Vector128 c3, Vector128 maximumValue, Vector128 halfValue, Vector128 scale) { // Each K lane supplies the common modulation factor for the corresponding C, M, and Y lanes. Vector128 scaledK = c3 * scale * scale; @@ -64,14 +50,7 @@ internal abstract partial class JpegColorConverterBase /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void ConvertToRgb( - ref Vector256 c0, - ref Vector256 c1, - ref Vector256 c2, - Vector256 c3, - Vector256 maximumValue, - Vector256 halfValue, - Vector256 scale) + public static void ConvertToRgb(ref Vector256 c0, ref Vector256 c1, ref Vector256 c2, Vector256 c3, Vector256 maximumValue, Vector256 halfValue, Vector256 scale) { // Eight independent CMYK samples remain lane-aligned throughout the modulation. Vector256 scaledK = c3 * scale * scale; @@ -82,14 +61,7 @@ internal abstract partial class JpegColorConverterBase /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void ConvertToRgb( - ref Vector512 c0, - ref Vector512 c1, - ref Vector512 c2, - Vector512 c3, - Vector512 maximumValue, - Vector512 halfValue, - Vector512 scale) + public static void ConvertToRgb(ref Vector512 c0, ref Vector512 c1, ref Vector512 c2, Vector512 c3, Vector512 maximumValue, Vector512 halfValue, Vector512 scale) { // Sixteen independent CMYK samples remain lane-aligned throughout the modulation. Vector512 scaledK = c3 * scale * scale; @@ -100,17 +72,7 @@ internal abstract partial class JpegColorConverterBase /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void ConvertFromRgb( - float r, - float g, - float b, - float maximumValue, - float halfValue, - float scale, - out float c0, - out float c1, - out float c2, - out float c3) + public static void ConvertFromRgb(float r, float g, float b, float maximumValue, float halfValue, float scale, out float c0, out float c1, out float c2, out float c3) { float c = maximumValue - r; float m = maximumValue - g; @@ -144,17 +106,7 @@ internal abstract partial class JpegColorConverterBase /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void ConvertFromRgb( - Vector128 r, - Vector128 g, - Vector128 b, - Vector128 maximumValue, - Vector128 halfValue, - Vector128 scale, - out Vector128 c0, - out Vector128 c1, - out Vector128 c2, - out Vector128 c3) + public static void ConvertFromRgb(Vector128 r, Vector128 g, Vector128 b, Vector128 maximumValue, Vector128 halfValue, Vector128 scale, out Vector128 c0, out Vector128 c1, out Vector128 c2, out Vector128 c3) { Vector128 c = maximumValue - r; Vector128 m = maximumValue - g; @@ -176,17 +128,7 @@ internal abstract partial class JpegColorConverterBase /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void ConvertFromRgb( - Vector256 r, - Vector256 g, - Vector256 b, - Vector256 maximumValue, - Vector256 halfValue, - Vector256 scale, - out Vector256 c0, - out Vector256 c1, - out Vector256 c2, - out Vector256 c3) + public static void ConvertFromRgb(Vector256 r, Vector256 g, Vector256 b, Vector256 maximumValue, Vector256 halfValue, Vector256 scale, out Vector256 c0, out Vector256 c1, out Vector256 c2, out Vector256 c3) { Vector256 c = maximumValue - r; Vector256 m = maximumValue - g; @@ -208,17 +150,7 @@ internal abstract partial class JpegColorConverterBase /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void ConvertFromRgb( - Vector512 r, - Vector512 g, - Vector512 b, - Vector512 maximumValue, - Vector512 halfValue, - Vector512 scale, - out Vector512 c0, - out Vector512 c1, - out Vector512 c2, - out Vector512 c3) + public static void ConvertFromRgb(Vector512 r, Vector512 g, Vector512 b, Vector512 maximumValue, Vector512 halfValue, Vector512 scale, out Vector512 c0, out Vector512 c1, out Vector512 c2, out Vector512 c3) { Vector512 c = maximumValue - r; Vector512 m = maximumValue - g; @@ -240,11 +172,7 @@ internal abstract partial class JpegColorConverterBase } /// - public static void ConvertToRgbInPlaceWithIcc( - Configuration configuration, - IccProfile profile, - in ComponentValues values, - float maximumValue) + public static void ConvertToRgbInPlaceWithIcc(Configuration configuration, IccProfile profile, in ComponentValues values, float maximumValue) { using IMemoryOwner memoryOwner = configuration.MemoryAllocator.Allocate(values.Component0.Length * 4); Span packed = memoryOwner.Memory.Span; diff --git a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.GrayScaleOperator.cs b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.GrayScaleOperator.cs index 20b68e8b1..8522fbf5c 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.GrayScaleOperator.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.GrayScaleOperator.cs @@ -28,14 +28,7 @@ internal abstract partial class JpegColorConverterBase /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void ConvertToRgb( - ref float c0, - ref float c1, - ref float c2, - float c3, - float maximumValue, - float halfValue, - float scale) + public static void ConvertToRgb(ref float c0, ref float c1, ref float c2, float c3, float maximumValue, float halfValue, float scale) { // JPEG stores luminance in the integer sample domain. Normalize it once, then duplicate the // same value into all three RGB planes. Keeping it local also prevents potentially aliasing @@ -48,14 +41,7 @@ internal abstract partial class JpegColorConverterBase /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void ConvertToRgb( - ref Vector128 c0, - ref Vector128 c1, - ref Vector128 c2, - Vector128 c3, - Vector128 maximumValue, - Vector128 halfValue, - Vector128 scale) + public static void ConvertToRgb(ref Vector128 c0, ref Vector128 c1, ref Vector128 c2, Vector128 c3, Vector128 maximumValue, Vector128 halfValue, Vector128 scale) { // Each XMM lane is one independent luminance sample. Reusing the normalized vector for R, G, // and B avoids recomputing the scale and keeps it live across potentially aliasing byref stores. @@ -67,14 +53,7 @@ internal abstract partial class JpegColorConverterBase /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void ConvertToRgb( - ref Vector256 c0, - ref Vector256 c1, - ref Vector256 c2, - Vector256 c3, - Vector256 maximumValue, - Vector256 halfValue, - Vector256 scale) + public static void ConvertToRgb(ref Vector256 c0, ref Vector256 c1, ref Vector256 c2, Vector256 c3, Vector256 maximumValue, Vector256 halfValue, Vector256 scale) { // Eight luminance samples occupy the YMM lanes. The local retains the normalized vector across // all three output stores even when the destination planes alias. @@ -86,14 +65,7 @@ internal abstract partial class JpegColorConverterBase /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void ConvertToRgb( - ref Vector512 c0, - ref Vector512 c1, - ref Vector512 c2, - Vector512 c3, - Vector512 maximumValue, - Vector512 halfValue, - Vector512 scale) + public static void ConvertToRgb(ref Vector512 c0, ref Vector512 c1, ref Vector512 c2, Vector512 c3, Vector512 maximumValue, Vector512 halfValue, Vector512 scale) { // Sixteen luminance samples occupy the ZMM lanes. The local retains the normalized vector across // all three output stores without shuffles, interleaving, or source reloads. @@ -105,17 +77,7 @@ internal abstract partial class JpegColorConverterBase /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void ConvertFromRgb( - float r, - float g, - float b, - float maximumValue, - float halfValue, - float scale, - out float c0, - out float c1, - out float c2, - out float c3) + public static void ConvertFromRgb(float r, float g, float b, float maximumValue, float halfValue, float scale, out float c0, out float c1, out float c2, out float c3) { // Rec.601 luma weights operate directly in the encoder sample domain. Only c0 is stored for a // one-component model; the remaining out values exist solely to satisfy the common operator shape. @@ -127,23 +89,10 @@ internal abstract partial class JpegColorConverterBase /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void ConvertFromRgb( - Vector128 r, - Vector128 g, - Vector128 b, - Vector128 maximumValue, - Vector128 halfValue, - Vector128 scale, - out Vector128 c0, - out Vector128 c1, - out Vector128 c2, - out Vector128 c3) + public static void ConvertFromRgb(Vector128 r, Vector128 g, Vector128 b, Vector128 maximumValue, Vector128 halfValue, Vector128 scale, out Vector128 c0, out Vector128 c1, out Vector128 c2, out Vector128 c3) { // The nested estimate gives each pixel the same multiply-add grouping as the scalar Rec.601 formula. - c0 = Vector128_.MultiplyAddEstimate( - Vector128.Create(0.299F), - r, - Vector128_.MultiplyAddEstimate(Vector128.Create(0.587F), g, Vector128.Create(0.114F) * b)); + c0 = Vector128_.MultiplyAddEstimate(Vector128.Create(0.299F), r, Vector128_.MultiplyAddEstimate(Vector128.Create(0.587F), g, Vector128.Create(0.114F) * b)); c1 = default; c2 = default; c3 = default; @@ -151,23 +100,10 @@ internal abstract partial class JpegColorConverterBase /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void ConvertFromRgb( - Vector256 r, - Vector256 g, - Vector256 b, - Vector256 maximumValue, - Vector256 halfValue, - Vector256 scale, - out Vector256 c0, - out Vector256 c1, - out Vector256 c2, - out Vector256 c3) + public static void ConvertFromRgb(Vector256 r, Vector256 g, Vector256 b, Vector256 maximumValue, Vector256 halfValue, Vector256 scale, out Vector256 c0, out Vector256 c1, out Vector256 c2, out Vector256 c3) { // YMM lanes evaluate the same Rec.601 equation independently, with no horizontal lane reduction. - c0 = Vector256_.MultiplyAddEstimate( - Vector256.Create(0.299F), - r, - Vector256_.MultiplyAddEstimate(Vector256.Create(0.587F), g, Vector256.Create(0.114F) * b)); + c0 = Vector256_.MultiplyAddEstimate(Vector256.Create(0.299F), r, Vector256_.MultiplyAddEstimate(Vector256.Create(0.587F), g, Vector256.Create(0.114F) * b)); c1 = default; c2 = default; c3 = default; @@ -175,34 +111,17 @@ internal abstract partial class JpegColorConverterBase /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void ConvertFromRgb( - Vector512 r, - Vector512 g, - Vector512 b, - Vector512 maximumValue, - Vector512 halfValue, - Vector512 scale, - out Vector512 c0, - out Vector512 c1, - out Vector512 c2, - out Vector512 c3) + public static void ConvertFromRgb(Vector512 r, Vector512 g, Vector512 b, Vector512 maximumValue, Vector512 halfValue, Vector512 scale, out Vector512 c0, out Vector512 c1, out Vector512 c2, out Vector512 c3) { // ZMM lanes retain the same arithmetic order as narrower paths so only SIMD width changes. - c0 = Vector512_.MultiplyAddEstimate( - Vector512.Create(0.299F), - r, - Vector512_.MultiplyAddEstimate(Vector512.Create(0.587F), g, Vector512.Create(0.114F) * b)); + c0 = Vector512_.MultiplyAddEstimate(Vector512.Create(0.299F), r, Vector512_.MultiplyAddEstimate(Vector512.Create(0.587F), g, Vector512.Create(0.114F) * b)); c1 = default; c2 = default; c3 = default; } /// - public static void ConvertToRgbInPlaceWithIcc( - Configuration configuration, - IccProfile profile, - in ComponentValues values, - float maximumValue) + public static void ConvertToRgbInPlaceWithIcc(Configuration configuration, IccProfile profile, in ComponentValues values, float maximumValue) { using IMemoryOwner memoryOwner = configuration.MemoryAllocator.Allocate(values.Component0.Length * 3); Span packed = memoryOwner.Memory.Span; diff --git a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.Operator.cs b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.Operator.cs index 86851a9d6..0058a6213 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.Operator.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.Operator.cs @@ -40,14 +40,7 @@ internal abstract partial class JpegColorConverterBase /// The maximum component value for the configured precision. /// The midpoint component value for the configured precision. /// The reciprocal of . - public static abstract void ConvertToRgb( - ref float c0, - ref float c1, - ref float c2, - float c3, - float maximumValue, - float halfValue, - float scale); + public static abstract void ConvertToRgb(ref float c0, ref float c1, ref float c2, float c3, float maximumValue, float halfValue, float scale); /// /// Converts four JPEG samples to normalized RGB. @@ -59,14 +52,7 @@ internal abstract partial class JpegColorConverterBase /// The maximum component value for the configured precision. /// The midpoint component value for the configured precision. /// The reciprocal of in every lane. - public static abstract void ConvertToRgb( - ref Vector128 c0, - ref Vector128 c1, - ref Vector128 c2, - Vector128 c3, - Vector128 maximumValue, - Vector128 halfValue, - Vector128 scale); + public static abstract void ConvertToRgb(ref Vector128 c0, ref Vector128 c1, ref Vector128 c2, Vector128 c3, Vector128 maximumValue, Vector128 halfValue, Vector128 scale); /// /// Converts eight JPEG samples to normalized RGB. @@ -78,14 +64,7 @@ internal abstract partial class JpegColorConverterBase /// The maximum component value for the configured precision. /// The midpoint component value for the configured precision. /// The reciprocal of in every lane. - public static abstract void ConvertToRgb( - ref Vector256 c0, - ref Vector256 c1, - ref Vector256 c2, - Vector256 c3, - Vector256 maximumValue, - Vector256 halfValue, - Vector256 scale); + public static abstract void ConvertToRgb(ref Vector256 c0, ref Vector256 c1, ref Vector256 c2, Vector256 c3, Vector256 maximumValue, Vector256 halfValue, Vector256 scale); /// /// Converts sixteen JPEG samples to normalized RGB. @@ -97,14 +76,7 @@ internal abstract partial class JpegColorConverterBase /// The maximum component value for the configured precision. /// The midpoint component value for the configured precision. /// The reciprocal of in every lane. - public static abstract void ConvertToRgb( - ref Vector512 c0, - ref Vector512 c1, - ref Vector512 c2, - Vector512 c3, - Vector512 maximumValue, - Vector512 halfValue, - Vector512 scale); + public static abstract void ConvertToRgb(ref Vector512 c0, ref Vector512 c1, ref Vector512 c2, Vector512 c3, Vector512 maximumValue, Vector512 halfValue, Vector512 scale); /// /// Converts one RGB sample to JPEG components. @@ -119,17 +91,7 @@ internal abstract partial class JpegColorConverterBase /// The second converted component. /// The third converted component. /// The fourth converted component, if used. - public static abstract void ConvertFromRgb( - float r, - float g, - float b, - float maximumValue, - float halfValue, - float scale, - out float c0, - out float c1, - out float c2, - out float c3); + public static abstract void ConvertFromRgb(float r, float g, float b, float maximumValue, float halfValue, float scale, out float c0, out float c1, out float c2, out float c3); /// /// Converts four RGB samples to JPEG components. @@ -144,17 +106,7 @@ internal abstract partial class JpegColorConverterBase /// The second converted component lanes. /// The third converted component lanes. /// The fourth converted component lanes, if used. - public static abstract void ConvertFromRgb( - Vector128 r, - Vector128 g, - Vector128 b, - Vector128 maximumValue, - Vector128 halfValue, - Vector128 scale, - out Vector128 c0, - out Vector128 c1, - out Vector128 c2, - out Vector128 c3); + public static abstract void ConvertFromRgb(Vector128 r, Vector128 g, Vector128 b, Vector128 maximumValue, Vector128 halfValue, Vector128 scale, out Vector128 c0, out Vector128 c1, out Vector128 c2, out Vector128 c3); /// /// Converts eight RGB samples to JPEG components. @@ -169,17 +121,7 @@ internal abstract partial class JpegColorConverterBase /// The second converted component lanes. /// The third converted component lanes. /// The fourth converted component lanes, if used. - public static abstract void ConvertFromRgb( - Vector256 r, - Vector256 g, - Vector256 b, - Vector256 maximumValue, - Vector256 halfValue, - Vector256 scale, - out Vector256 c0, - out Vector256 c1, - out Vector256 c2, - out Vector256 c3); + public static abstract void ConvertFromRgb(Vector256 r, Vector256 g, Vector256 b, Vector256 maximumValue, Vector256 halfValue, Vector256 scale, out Vector256 c0, out Vector256 c1, out Vector256 c2, out Vector256 c3); /// /// Converts sixteen RGB samples to JPEG components. @@ -194,17 +136,7 @@ internal abstract partial class JpegColorConverterBase /// The second converted component lanes. /// The third converted component lanes. /// The fourth converted component lanes, if used. - public static abstract void ConvertFromRgb( - Vector512 r, - Vector512 g, - Vector512 b, - Vector512 maximumValue, - Vector512 halfValue, - Vector512 scale, - out Vector512 c0, - out Vector512 c1, - out Vector512 c2, - out Vector512 c3); + public static abstract void ConvertFromRgb(Vector512 r, Vector512 g, Vector512 b, Vector512 maximumValue, Vector512 halfValue, Vector512 scale, out Vector512 c0, out Vector512 c1, out Vector512 c2, out Vector512 c3); /// /// Converts JPEG component values to RGB using the supplied ICC profile. @@ -213,11 +145,7 @@ internal abstract partial class JpegColorConverterBase /// The source ICC profile. /// The component values to convert. /// The maximum component value for the configured precision. - public static abstract void ConvertToRgbInPlaceWithIcc( - Configuration configuration, - IccProfile profile, - in ComponentValues values, - float maximumValue); + public static abstract void ConvertToRgbInPlaceWithIcc(Configuration configuration, IccProfile profile, in ComponentValues values, float maximumValue); } /// @@ -241,13 +169,7 @@ internal abstract partial class JpegColorConverterBase /// public override int ElementsPerBatch - => Vector512.IsHardwareAccelerated - ? Vector512.Count - : Vector256.IsHardwareAccelerated - ? Vector256.Count - : Vector128.IsHardwareAccelerated - ? Vector128.Count - : 1; + => Vector512.IsHardwareAccelerated ? Vector512.Count : Vector256.IsHardwareAccelerated ? Vector256.Count : Vector128.IsHardwareAccelerated ? Vector128.Count : 1; /// public override void ConvertToRgbInPlace(in ComponentValues values) @@ -289,9 +211,7 @@ internal abstract partial class JpegColorConverterBase // ComponentCount is a static property on the closed operator type, so the JIT removes // this choice. Three-component models never dereference the empty Component3 byref. - Vector512 c3 = TOperator.ComponentCount == 4 - ? Unsafe.As>(ref Unsafe.Add(ref c3Base, i)) - : default; + Vector512 c3 = TOperator.ComponentCount == 4 ? Unsafe.As>(ref Unsafe.Add(ref c3Base, i)) : default; // c0-c2 alias the planar source vectors and are replaced in place with normalized RGB. // c3 is passed by value because the fourth JPEG component must remain unchanged. @@ -321,9 +241,7 @@ internal abstract partial class JpegColorConverterBase // The closed operator makes this a compile-time color-model choice, not a per-vector // runtime abstraction or interface dispatch. - Vector256 c3 = TOperator.ComponentCount == 4 - ? Unsafe.As>(ref Unsafe.Add(ref c3Base, i)) - : default; + Vector256 c3 = TOperator.ComponentCount == 4 ? Unsafe.As>(ref Unsafe.Add(ref c3Base, i)) : default; TOperator.ConvertToRgb(ref c0, ref c1, ref c2, c3, maximumValue, halfValue, scaleVector); } @@ -350,9 +268,7 @@ internal abstract partial class JpegColorConverterBase ref Vector128 c2 = ref Unsafe.As>(ref Unsafe.Add(ref c2Base, i)); // As at the wider stages, the fourth vector is loaded only for CMYK-shaped operators. - Vector128 c3 = TOperator.ComponentCount == 4 - ? Unsafe.As>(ref Unsafe.Add(ref c3Base, i)) - : default; + Vector128 c3 = TOperator.ComponentCount == 4 ? Unsafe.As>(ref Unsafe.Add(ref c3Base, i)) : default; TOperator.ConvertToRgb(ref c0, ref c1, ref c2, c3, maximumValue, halfValue, scaleVector); } @@ -365,14 +281,7 @@ internal abstract partial class JpegColorConverterBase { float c3 = TOperator.ComponentCount == 4 ? Unsafe.Add(ref c3Base, i) : 0; - TOperator.ConvertToRgb( - ref Unsafe.Add(ref c0Base, i), - ref Unsafe.Add(ref c1Base, i), - ref Unsafe.Add(ref c2Base, i), - c3, - this.MaximumValue, - this.HalfValue, - scale); + TOperator.ConvertToRgb(ref Unsafe.Add(ref c0Base, i), ref Unsafe.Add(ref c1Base, i), ref Unsafe.Add(ref c2Base, i), c3, this.MaximumValue, this.HalfValue, scale); } } @@ -420,17 +329,7 @@ internal abstract partial class JpegColorConverterBase Vector512 g = Unsafe.As>(ref Unsafe.Add(ref gBase, i)); Vector512 b = Unsafe.As>(ref Unsafe.Add(ref bBase, i)); - TOperator.ConvertFromRgb( - r, - g, - b, - maximumValue, - halfValue, - scaleVector, - out Vector512 c0, - out Vector512 c1, - out Vector512 c2, - out Vector512 c3); + TOperator.ConvertFromRgb(r, g, b, maximumValue, halfValue, scaleVector, out Vector512 c0, out Vector512 c1, out Vector512 c2, out Vector512 c3); // Outputs remain planar: each vector contains sixteen consecutive samples from one // JPEG component. Static count checks prevent grayscale from touching absent planes @@ -473,17 +372,7 @@ internal abstract partial class JpegColorConverterBase Vector256 g = Unsafe.As>(ref Unsafe.Add(ref gBase, i)); Vector256 b = Unsafe.As>(ref Unsafe.Add(ref bBase, i)); - TOperator.ConvertFromRgb( - r, - g, - b, - maximumValue, - halfValue, - scaleVector, - out Vector256 c0, - out Vector256 c1, - out Vector256 c2, - out Vector256 c3); + TOperator.ConvertFromRgb(r, g, b, maximumValue, halfValue, scaleVector, out Vector256 c0, out Vector256 c1, out Vector256 c2, out Vector256 c3); // Static count checks write only planes owned by this color model. Unsafe.As>(ref Unsafe.Add(ref c0Base, i)) = c0; @@ -524,17 +413,7 @@ internal abstract partial class JpegColorConverterBase Vector128 g = Unsafe.As>(ref Unsafe.Add(ref gBase, i)); Vector128 b = Unsafe.As>(ref Unsafe.Add(ref bBase, i)); - TOperator.ConvertFromRgb( - r, - g, - b, - maximumValue, - halfValue, - scaleVector, - out Vector128 c0, - out Vector128 c1, - out Vector128 c2, - out Vector128 c3); + TOperator.ConvertFromRgb(r, g, b, maximumValue, halfValue, scaleVector, out Vector128 c0, out Vector128 c1, out Vector128 c2, out Vector128 c3); // Four results are stored only for the planes represented by the closed operator. Unsafe.As>(ref Unsafe.Add(ref c0Base, i)) = c0; @@ -560,17 +439,7 @@ internal abstract partial class JpegColorConverterBase // Scalar conversion is reserved for the zero-to-three samples that cannot fill Vector128. for (; i < length; i++) { - TOperator.ConvertFromRgb( - Unsafe.Add(ref rBase, i), - Unsafe.Add(ref gBase, i), - Unsafe.Add(ref bBase, i), - this.MaximumValue, - this.HalfValue, - scale, - out float c0, - out float c1, - out float c2, - out float c3); + TOperator.ConvertFromRgb(Unsafe.Add(ref rBase, i), Unsafe.Add(ref gBase, i), Unsafe.Add(ref bBase, i), this.MaximumValue, this.HalfValue, scale, out float c0, out float c1, out float c2, out float c3); Unsafe.Add(ref c0Base, i) = c0; diff --git a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.Packing.cs b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.Packing.cs new file mode 100644 index 000000000..749e4773d --- /dev/null +++ b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.Packing.cs @@ -0,0 +1,305 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using SixLabors.ImageSharp.Common.Helpers; + +namespace SixLabors.ImageSharp.Formats.Jpeg.Components; + +internal abstract partial class JpegColorConverterBase +{ + /// + /// Normalizes three planar component lanes and interleaves them into packed XYZ values. + /// + /// The planar X components. + /// The planar Y components. + /// The planar Z components. + /// The destination ordered as consecutive XYZ triples. + /// The normalization factor applied to every component. + public static void PackedNormalizeInterleave3(ReadOnlySpan xLane, ReadOnlySpan yLane, ReadOnlySpan zLane, Span packed, float scale) + { + DebugGuard.IsTrue(packed.Length % 3 == 0, "Packed length must be divisible by 3."); + DebugGuard.IsTrue(yLane.Length == xLane.Length, nameof(yLane), "Channels must be of same size!"); + DebugGuard.IsTrue(zLane.Length == xLane.Length, nameof(zLane), "Channels must be of same size!"); + DebugGuard.MustBeLessThanOrEqualTo(packed.Length / 3, xLane.Length, nameof(packed)); + + ref float xLaneRef = ref MemoryMarshal.GetReference(xLane); + ref float yLaneRef = ref MemoryMarshal.GetReference(yLane); + ref float zLaneRef = ref MemoryMarshal.GetReference(zLane); + ref float packedRef = ref MemoryMarshal.GetReference(packed); + int i = 0; + + if (Vector128.IsHardwareAccelerated) + { + Vector128 scaleVector = Vector128.Create(scale); + int oneVectorFromEnd = xLane.Length - Vector128.Count; + + for (; i <= oneVectorFromEnd; i += Vector128.Count) + { + // Each source vector contains four consecutive samples from one plane: + // x = [X0 X1 X2 X3] + // y = [Y0 Y1 Y2 Y3] + // z = [Z0 Z1 Z2 Z3] + // Shifting X by one sample supplies the value that follows each XYZ triple: + // shiftedX = [X1 X2 X3 0] + // The transpose therefore produces overlapping rows [Xn Yn Zn Xn+1]. + // AlignRight joins those rows into three complete destination vectors, avoiding + // the scalar-sized stores that writing four independent Vector3 values requires. + Vector128 x = Unsafe.As>(ref Unsafe.Add(ref xLaneRef, i)) * scaleVector; + Vector128 y = Unsafe.As>(ref Unsafe.Add(ref yLaneRef, i)) * scaleVector; + Vector128 z = Unsafe.As>(ref Unsafe.Add(ref zLaneRef, i)) * scaleVector; + Vector128 shiftedX = Vector128_.ShiftRightBytesInVector(x.AsByte(), sizeof(float)).AsSingle(); + + Transpose4(x, y, z, shiftedX, out Vector128 pixel0, out Vector128 pixel1, out Vector128 pixel2, out Vector128 pixel3); + + // Dropping pixel2.X lets [Y2] complete [Y1 Z1 X2] from pixel1. + Vector128 shiftedPixel2 = Vector128_.ShiftRightBytesInVector(pixel2.AsByte(), sizeof(float)); + Vector128 packed1 = Vector128_.AlignRight(shiftedPixel2, pixel1.AsByte(), sizeof(float)).AsSingle(); + + // Dropping pixel3.X leaves [Y3 Z3] to complete [Z2 X3] from pixel2. + Vector128 shiftedPixel3 = Vector128_.ShiftRightBytesInVector(pixel3.AsByte(), sizeof(float)); + Vector128 packed2 = Vector128_.AlignRight(shiftedPixel3, pixel2.AsByte(), sizeof(float) * 2).AsSingle(); + + ref Vector128 destination = ref Unsafe.As>(ref Unsafe.Add(ref packedRef, (uint)i * 3)); + + destination = pixel0; + Unsafe.Add(ref destination, 1) = packed1; + Unsafe.Add(ref destination, 2) = packed2; + } + } + + // Fewer than four pixels remain after SIMD, or every pixel reaches this path + // when the runtime cannot accelerate the cross-vector transpose. + for (; i < xLane.Length; i++) + { + nuint sourceOffset = (uint)i; + nuint packedOffset = sourceOffset * 3; + Unsafe.Add(ref packedRef, packedOffset) = Unsafe.Add(ref xLaneRef, sourceOffset) * scale; + Unsafe.Add(ref packedRef, packedOffset + 1) = Unsafe.Add(ref yLaneRef, sourceOffset) * scale; + Unsafe.Add(ref packedRef, packedOffset + 2) = Unsafe.Add(ref zLaneRef, sourceOffset) * scale; + } + } + + /// + /// Deinterleaves packed XYZ values into three planar component lanes. + /// + /// The source ordered as consecutive XYZ triples. + /// The destination X components. + /// The destination Y components. + /// The destination Z components. + public static void UnpackDeinterleave3(ReadOnlySpan packed, Span xLane, Span yLane, Span zLane) + { + DebugGuard.IsTrue(packed.Length == xLane.Length, nameof(packed), "Channels must be of same size!"); + DebugGuard.IsTrue(yLane.Length == xLane.Length, nameof(yLane), "Channels must be of same size!"); + DebugGuard.IsTrue(zLane.Length == xLane.Length, nameof(zLane), "Channels must be of same size!"); + + ref float packedRef = ref MemoryMarshal.GetReference(MemoryMarshal.Cast(packed)); + ref float xLaneRef = ref MemoryMarshal.GetReference(xLane); + ref float yLaneRef = ref MemoryMarshal.GetReference(yLane); + ref float zLaneRef = ref MemoryMarshal.GetReference(zLane); + int i = 0; + + if (Vector128.IsHardwareAccelerated) + { + int oneVectorFromEnd = packed.Length - Vector128.Count; + + for (; i <= oneVectorFromEnd; i += Vector128.Count) + { + // A Vector3 occupies twelve contiguous bytes, so a sixteen-byte load beginning + // at one pixel also reads the X component of the following pixel: + // pixel0 = [X0 Y0 Z0 X1] + // pixel1 = [X1 Y1 Z1 X2] + // The transpose discards this fourth column, making the overlap useful padding + // and avoiding two insert instructions per pixel. The final row needs explicit + // zero padding only when pixel3 is the last element in the source span. + nuint packedOffset = (uint)i * 3; + Vector128 pixel0 = Unsafe.As>(ref Unsafe.Add(ref packedRef, packedOffset)); + Vector128 pixel1 = Unsafe.As>(ref Unsafe.Add(ref packedRef, packedOffset + 3)); + Vector128 pixel2 = Unsafe.As>(ref Unsafe.Add(ref packedRef, packedOffset + 6)); + ref float pixel3Ref = ref Unsafe.Add(ref packedRef, packedOffset + 9); + Vector128 pixel3 = i + Vector128.Count < packed.Length ? Unsafe.As>(ref pixel3Ref) : Unsafe.As(ref pixel3Ref).AsVector128(); + + Transpose4(pixel0, pixel1, pixel2, pixel3, out Vector128 x, out Vector128 y, out Vector128 z, out _); + + Unsafe.As>(ref Unsafe.Add(ref xLaneRef, i)) = x; + Unsafe.As>(ref Unsafe.Add(ref yLaneRef, i)) = y; + Unsafe.As>(ref Unsafe.Add(ref zLaneRef, i)) = z; + } + } + + // The scalar remainder preserves the original scatter behavior for zero to + // three pixels and provides the complete fallback on unsupported hardware. + for (; i < packed.Length; i++) + { + nuint packedOffset = (uint)i * 3; + Unsafe.Add(ref xLaneRef, i) = Unsafe.Add(ref packedRef, packedOffset); + Unsafe.Add(ref yLaneRef, i) = Unsafe.Add(ref packedRef, packedOffset + 1); + Unsafe.Add(ref zLaneRef, i) = Unsafe.Add(ref packedRef, packedOffset + 2); + } + } + + /// + /// Normalizes four planar component lanes and interleaves them into packed XYZW values. + /// + /// The planar X components. + /// The planar Y components. + /// The planar Z components. + /// The planar W components. + /// The destination ordered as consecutive XYZW groups. + /// The maximum component value used to normalize each component. + public static void PackedNormalizeInterleave4(ReadOnlySpan xLane, ReadOnlySpan yLane, ReadOnlySpan zLane, ReadOnlySpan wLane, Span packed, float maxValue) + { + DebugGuard.IsTrue(packed.Length % 4 == 0, "Packed length must be divisible by 4."); + DebugGuard.IsTrue(yLane.Length == xLane.Length, nameof(yLane), "Channels must be of same size!"); + DebugGuard.IsTrue(zLane.Length == xLane.Length, nameof(zLane), "Channels must be of same size!"); + DebugGuard.IsTrue(wLane.Length == xLane.Length, nameof(wLane), "Channels must be of same size!"); + DebugGuard.MustBeLessThanOrEqualTo(packed.Length / 4, xLane.Length, nameof(packed)); + + float scale = 1F / maxValue; + ref float xLaneRef = ref MemoryMarshal.GetReference(xLane); + ref float yLaneRef = ref MemoryMarshal.GetReference(yLane); + ref float zLaneRef = ref MemoryMarshal.GetReference(zLane); + ref float wLaneRef = ref MemoryMarshal.GetReference(wLane); + ref float packedRef = ref MemoryMarshal.GetReference(packed); + int i = 0; + + if (Vector128.IsHardwareAccelerated) + { + Vector128 scaleVector = Vector128.Create(scale); + int oneVectorFromEnd = xLane.Length - Vector128.Count; + + for (; i <= oneVectorFromEnd; i += Vector128.Count) + { + // Four planar vectors form the rows of a 4x4 matrix. Transposition + // converts them into four complete [Xn Yn Zn Wn] pixel vectors, so + // normalization and interleaving require only four loads, four + // multiplies, the register transpose, and four contiguous stores. + Vector128 x = Unsafe.As>(ref Unsafe.Add(ref xLaneRef, i)) * scaleVector; + Vector128 y = Unsafe.As>(ref Unsafe.Add(ref yLaneRef, i)) * scaleVector; + Vector128 z = Unsafe.As>(ref Unsafe.Add(ref zLaneRef, i)) * scaleVector; + Vector128 w = Unsafe.As>(ref Unsafe.Add(ref wLaneRef, i)) * scaleVector; + + Transpose4(x, y, z, w, out Vector128 pixel0, out Vector128 pixel1, out Vector128 pixel2, out Vector128 pixel3); + + ref Vector128 destination = ref Unsafe.As>(ref Unsafe.Add(ref packedRef, (uint)i * 4)); + + destination = pixel0; + Unsafe.Add(ref destination, 1) = pixel1; + Unsafe.Add(ref destination, 2) = pixel2; + Unsafe.Add(ref destination, 3) = pixel3; + } + } + + // Process the zero-to-three trailing pixels with the same normalization + // and component order as the vector transpose. + for (; i < xLane.Length; i++) + { + nuint sourceOffset = (uint)i; + nuint packedOffset = sourceOffset * 4; + Unsafe.Add(ref packedRef, packedOffset) = Unsafe.Add(ref xLaneRef, sourceOffset) * scale; + Unsafe.Add(ref packedRef, packedOffset + 1) = Unsafe.Add(ref yLaneRef, sourceOffset) * scale; + Unsafe.Add(ref packedRef, packedOffset + 2) = Unsafe.Add(ref zLaneRef, sourceOffset) * scale; + Unsafe.Add(ref packedRef, packedOffset + 3) = Unsafe.Add(ref wLaneRef, sourceOffset) * scale; + } + } + + /// + /// Inverts and normalizes four planar component lanes before interleaving them into packed XYZW values. + /// + /// The inverted planar X components. + /// The inverted planar Y components. + /// The inverted planar Z components. + /// The inverted planar W components. + /// The destination ordered as consecutive conventional XYZW groups. + /// The maximum component value used for inversion and normalization. + public static void PackedInvertNormalizeInterleave4(ReadOnlySpan xLane, ReadOnlySpan yLane, ReadOnlySpan zLane, ReadOnlySpan wLane, Span packed, float maxValue) + { + DebugGuard.IsTrue(packed.Length % 4 == 0, "Packed length must be divisible by 4."); + DebugGuard.IsTrue(yLane.Length == xLane.Length, nameof(yLane), "Channels must be of same size!"); + DebugGuard.IsTrue(zLane.Length == xLane.Length, nameof(zLane), "Channels must be of same size!"); + DebugGuard.IsTrue(wLane.Length == xLane.Length, nameof(wLane), "Channels must be of same size!"); + DebugGuard.MustBeLessThanOrEqualTo(packed.Length / 4, xLane.Length, nameof(packed)); + + float scale = 1F / maxValue; + ref float xLaneRef = ref MemoryMarshal.GetReference(xLane); + ref float yLaneRef = ref MemoryMarshal.GetReference(yLane); + ref float zLaneRef = ref MemoryMarshal.GetReference(zLane); + ref float wLaneRef = ref MemoryMarshal.GetReference(wLane); + ref float packedRef = ref MemoryMarshal.GetReference(packed); + int i = 0; + + if (Vector128.IsHardwareAccelerated) + { + Vector128 maximumVector = Vector128.Create(maxValue); + Vector128 scaleVector = Vector128.Create(scale); + int oneVectorFromEnd = xLane.Length - Vector128.Count; + + for (; i <= oneVectorFromEnd; i += Vector128.Count) + { + // Adobe JPEG stores all four components inverted in the sample + // domain. Reflecting and normalizing the planar vectors before the + // transpose keeps both arithmetic operations lane-wise and leaves + // the transpose responsible only for the planar-to-packed layout. + Vector128 x = (maximumVector - Unsafe.As>(ref Unsafe.Add(ref xLaneRef, i))) * scaleVector; + Vector128 y = (maximumVector - Unsafe.As>(ref Unsafe.Add(ref yLaneRef, i))) * scaleVector; + Vector128 z = (maximumVector - Unsafe.As>(ref Unsafe.Add(ref zLaneRef, i))) * scaleVector; + Vector128 w = (maximumVector - Unsafe.As>(ref Unsafe.Add(ref wLaneRef, i))) * scaleVector; + + Transpose4(x, y, z, w, out Vector128 pixel0, out Vector128 pixel1, out Vector128 pixel2, out Vector128 pixel3); + + ref Vector128 destination = ref Unsafe.As>(ref Unsafe.Add(ref packedRef, (uint)i * 4)); + + destination = pixel0; + Unsafe.Add(ref destination, 1) = pixel1; + Unsafe.Add(ref destination, 2) = pixel2; + Unsafe.Add(ref destination, 3) = pixel3; + } + } + + // Preserve the original operation order for the zero-to-three trailing pixels: + // subtract in the sample domain, then multiply by the reciprocal maximum. + for (; i < xLane.Length; i++) + { + nuint sourceOffset = (uint)i; + nuint packedOffset = sourceOffset * 4; + Unsafe.Add(ref packedRef, packedOffset) = (maxValue - Unsafe.Add(ref xLaneRef, sourceOffset)) * scale; + Unsafe.Add(ref packedRef, packedOffset + 1) = (maxValue - Unsafe.Add(ref yLaneRef, sourceOffset)) * scale; + Unsafe.Add(ref packedRef, packedOffset + 2) = (maxValue - Unsafe.Add(ref zLaneRef, sourceOffset)) * scale; + Unsafe.Add(ref packedRef, packedOffset + 3) = (maxValue - Unsafe.Add(ref wLaneRef, sourceOffset)) * scale; + } + } + + /// + /// Transposes four four-lane rows into four four-lane columns. + /// + /// The first matrix row. + /// The second matrix row. + /// The third matrix row. + /// The fourth matrix row. + /// The first matrix column. + /// The second matrix column. + /// The third matrix column. + /// The fourth matrix column. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void Transpose4(Vector128 row0, Vector128 row1, Vector128 row2, Vector128 row3, out Vector128 column0, out Vector128 column1, out Vector128 column2, out Vector128 column3) + { + // The first unpack interleaves adjacent 32-bit lanes from rows 0/1 and 2/3: + // row01Low = [r0c0 r1c0 r0c1 r1c1] + // row23Low = [r2c0 r3c0 r2c1 r3c1] + // A second unpack treats each adjacent pair as one 64-bit lane and combines + // the row01 and row23 pairs into complete columns. The integer views only + // expose the cross-platform unpack helpers; every floating-point bit is preserved. + Vector128 row01Low = Vector128_.UnpackLow(row0.AsInt32(), row1.AsInt32()); + Vector128 row01High = Vector128_.UnpackHigh(row0.AsInt32(), row1.AsInt32()); + Vector128 row23Low = Vector128_.UnpackLow(row2.AsInt32(), row3.AsInt32()); + Vector128 row23High = Vector128_.UnpackHigh(row2.AsInt32(), row3.AsInt32()); + + column0 = Vector128_.UnpackLow(row01Low.AsInt64(), row23Low.AsInt64()).AsSingle(); + column1 = Vector128_.UnpackHigh(row01Low.AsInt64(), row23Low.AsInt64()).AsSingle(); + column2 = Vector128_.UnpackLow(row01High.AsInt64(), row23High.AsInt64()).AsSingle(); + column3 = Vector128_.UnpackHigh(row01High.AsInt64(), row23High.AsInt64()).AsSingle(); + } +} diff --git a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.RgbOperator.cs b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.RgbOperator.cs index 8559b818d..a97144de9 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.RgbOperator.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.RgbOperator.cs @@ -27,14 +27,7 @@ internal abstract partial class JpegColorConverterBase /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void ConvertToRgb( - ref float c0, - ref float c1, - ref float c2, - float c3, - float maximumValue, - float halfValue, - float scale) + public static void ConvertToRgb(ref float c0, ref float c1, ref float c2, float c3, float maximumValue, float halfValue, float scale) { // The JPEG planes already represent R, G, and B. Conversion therefore consists only of moving // each integer-domain sample into the normalized floating-point domain consumed by pixel packing. @@ -45,14 +38,7 @@ internal abstract partial class JpegColorConverterBase /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void ConvertToRgb( - ref Vector128 c0, - ref Vector128 c1, - ref Vector128 c2, - Vector128 c3, - Vector128 maximumValue, - Vector128 halfValue, - Vector128 scale) + public static void ConvertToRgb(ref Vector128 c0, ref Vector128 c1, ref Vector128 c2, Vector128 c3, Vector128 maximumValue, Vector128 halfValue, Vector128 scale) { // Four samples from each planar channel remain in their lanes while sharing one normalization vector. c0 *= scale; @@ -62,14 +48,7 @@ internal abstract partial class JpegColorConverterBase /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void ConvertToRgb( - ref Vector256 c0, - ref Vector256 c1, - ref Vector256 c2, - Vector256 c3, - Vector256 maximumValue, - Vector256 halfValue, - Vector256 scale) + public static void ConvertToRgb(ref Vector256 c0, ref Vector256 c1, ref Vector256 c2, Vector256 c3, Vector256 maximumValue, Vector256 halfValue, Vector256 scale) { // Eight samples per plane are normalized independently without channel shuffles. c0 *= scale; @@ -79,14 +58,7 @@ internal abstract partial class JpegColorConverterBase /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void ConvertToRgb( - ref Vector512 c0, - ref Vector512 c1, - ref Vector512 c2, - Vector512 c3, - Vector512 maximumValue, - Vector512 halfValue, - Vector512 scale) + public static void ConvertToRgb(ref Vector512 c0, ref Vector512 c1, ref Vector512 c2, Vector512 c3, Vector512 maximumValue, Vector512 halfValue, Vector512 scale) { // Sixteen samples per plane are normalized independently without changing planar ordering. c0 *= scale; @@ -96,17 +68,7 @@ internal abstract partial class JpegColorConverterBase /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void ConvertFromRgb( - float r, - float g, - float b, - float maximumValue, - float halfValue, - float scale, - out float c0, - out float c1, - out float c2, - out float c3) + public static void ConvertFromRgb(float r, float g, float b, float maximumValue, float halfValue, float scale, out float c0, out float c1, out float c2, out float c3) { // Encoder RGB lanes already use the JPEG sample domain, so the direct color model copies them. c0 = r; @@ -117,17 +79,7 @@ internal abstract partial class JpegColorConverterBase /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void ConvertFromRgb( - Vector128 r, - Vector128 g, - Vector128 b, - Vector128 maximumValue, - Vector128 halfValue, - Vector128 scale, - out Vector128 c0, - out Vector128 c1, - out Vector128 c2, - out Vector128 c3) + public static void ConvertFromRgb(Vector128 r, Vector128 g, Vector128 b, Vector128 maximumValue, Vector128 halfValue, Vector128 scale, out Vector128 c0, out Vector128 c1, out Vector128 c2, out Vector128 c3) { // The planar vectors map one-to-one to JPEG components; the fourth result is statically discarded. c0 = r; @@ -138,17 +90,7 @@ internal abstract partial class JpegColorConverterBase /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void ConvertFromRgb( - Vector256 r, - Vector256 g, - Vector256 b, - Vector256 maximumValue, - Vector256 halfValue, - Vector256 scale, - out Vector256 c0, - out Vector256 c1, - out Vector256 c2, - out Vector256 c3) + public static void ConvertFromRgb(Vector256 r, Vector256 g, Vector256 b, Vector256 maximumValue, Vector256 halfValue, Vector256 scale, out Vector256 c0, out Vector256 c1, out Vector256 c2, out Vector256 c3) { // The planar vectors map one-to-one to JPEG components; no arithmetic or rearrangement is required. c0 = r; @@ -159,17 +101,7 @@ internal abstract partial class JpegColorConverterBase /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void ConvertFromRgb( - Vector512 r, - Vector512 g, - Vector512 b, - Vector512 maximumValue, - Vector512 halfValue, - Vector512 scale, - out Vector512 c0, - out Vector512 c1, - out Vector512 c2, - out Vector512 c3) + public static void ConvertFromRgb(Vector512 r, Vector512 g, Vector512 b, Vector512 maximumValue, Vector512 halfValue, Vector512 scale, out Vector512 c0, out Vector512 c1, out Vector512 c2, out Vector512 c3) { // The widest path is likewise a register-to-register planar copy for sixteen pixels. c0 = r; @@ -179,11 +111,7 @@ internal abstract partial class JpegColorConverterBase } /// - public static void ConvertToRgbInPlaceWithIcc( - Configuration configuration, - IccProfile profile, - in ComponentValues values, - float maximumValue) + public static void ConvertToRgbInPlaceWithIcc(Configuration configuration, IccProfile profile, in ComponentValues values, float maximumValue) { using IMemoryOwner memoryOwner = configuration.MemoryAllocator.Allocate(values.Component0.Length * 3); Span packed = memoryOwner.Memory.Span; diff --git a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YCbCrOperator.cs b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YCbCrOperator.cs index 931b96dff..9ceb7b44b 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YCbCrOperator.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YCbCrOperator.cs @@ -48,14 +48,7 @@ internal abstract partial class JpegColorConverterBase /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void ConvertToRgb( - ref float c0, - ref float c1, - ref float c2, - float c3, - float maximumValue, - float halfValue, - float scale) + public static void ConvertToRgb(ref float c0, ref float c1, ref float c2, float c3, float maximumValue, float halfValue, float scale) { float y = c0; float cb = c1 - halfValue; @@ -72,14 +65,7 @@ internal abstract partial class JpegColorConverterBase /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void ConvertToRgb( - ref Vector128 c0, - ref Vector128 c1, - ref Vector128 c2, - Vector128 c3, - Vector128 maximumValue, - Vector128 halfValue, - Vector128 scale) + public static void ConvertToRgb(ref Vector128 c0, ref Vector128 c1, ref Vector128 c2, Vector128 c3, Vector128 maximumValue, Vector128 halfValue, Vector128 scale) { Vector128 y = c0; Vector128 cb = c1 - halfValue; @@ -89,10 +75,7 @@ internal abstract partial class JpegColorConverterBase // R uses Cr, B uses Cb, and G subtracts both chroma contributions. Rounding occurs in the sample // domain before the common normalization scale so all precisions use integer JPEG sample semantics. Vector128 r = Vector128_.MultiplyAddEstimate(cr, Vector128.Create(RCrMult), y); - Vector128 g = Vector128_.MultiplyAddEstimate( - cr, - Vector128.Create(-GCrMult), - Vector128_.MultiplyAddEstimate(cb, Vector128.Create(-GCbMult), y)); + Vector128 g = Vector128_.MultiplyAddEstimate(cr, Vector128.Create(-GCrMult), Vector128_.MultiplyAddEstimate(cb, Vector128.Create(-GCbMult), y)); Vector128 b = Vector128_.MultiplyAddEstimate(cb, Vector128.Create(BCbMult), y); c0 = Vector128_.RoundToNearestInteger(r) * scale; @@ -102,14 +85,7 @@ internal abstract partial class JpegColorConverterBase /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void ConvertToRgb( - ref Vector256 c0, - ref Vector256 c1, - ref Vector256 c2, - Vector256 c3, - Vector256 maximumValue, - Vector256 halfValue, - Vector256 scale) + public static void ConvertToRgb(ref Vector256 c0, ref Vector256 c1, ref Vector256 c2, Vector256 c3, Vector256 maximumValue, Vector256 halfValue, Vector256 scale) { Vector256 y = c0; Vector256 cb = c1 - halfValue; @@ -119,10 +95,7 @@ internal abstract partial class JpegColorConverterBase // Keeping an explicit overload allows the JIT to emit native YMM operations without a width // switch or decomposing the vector into smaller values. Vector256 r = Vector256_.MultiplyAddEstimate(cr, Vector256.Create(RCrMult), y); - Vector256 g = Vector256_.MultiplyAddEstimate( - cr, - Vector256.Create(-GCrMult), - Vector256_.MultiplyAddEstimate(cb, Vector256.Create(-GCbMult), y)); + Vector256 g = Vector256_.MultiplyAddEstimate(cr, Vector256.Create(-GCrMult), Vector256_.MultiplyAddEstimate(cb, Vector256.Create(-GCbMult), y)); Vector256 b = Vector256_.MultiplyAddEstimate(cb, Vector256.Create(BCbMult), y); c0 = Vector256_.RoundToNearestInteger(r) * scale; @@ -132,14 +105,7 @@ internal abstract partial class JpegColorConverterBase /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void ConvertToRgb( - ref Vector512 c0, - ref Vector512 c1, - ref Vector512 c2, - Vector512 c3, - Vector512 maximumValue, - Vector512 halfValue, - Vector512 scale) + public static void ConvertToRgb(ref Vector512 c0, ref Vector512 c1, ref Vector512 c2, Vector512 c3, Vector512 maximumValue, Vector512 halfValue, Vector512 scale) { Vector512 y = c0; Vector512 cb = c1 - halfValue; @@ -149,10 +115,7 @@ internal abstract partial class JpegColorConverterBase // assembly inspection verifies the JIT hoists them from the loop and retains fused operations. // The formula and rounding order remain identical to the narrower overloads. Vector512 r = Vector512_.MultiplyAddEstimate(cr, Vector512.Create(RCrMult), y); - Vector512 g = Vector512_.MultiplyAddEstimate( - cr, - Vector512.Create(-GCrMult), - Vector512_.MultiplyAddEstimate(cb, Vector512.Create(-GCbMult), y)); + Vector512 g = Vector512_.MultiplyAddEstimate(cr, Vector512.Create(-GCrMult), Vector512_.MultiplyAddEstimate(cb, Vector512.Create(-GCbMult), y)); Vector512 b = Vector512_.MultiplyAddEstimate(cb, Vector512.Create(BCbMult), y); c0 = Vector512_.RoundToNearestInteger(r) * scale; @@ -162,17 +125,7 @@ internal abstract partial class JpegColorConverterBase /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void ConvertFromRgb( - float r, - float g, - float b, - float maximumValue, - float halfValue, - float scale, - out float c0, - out float c1, - out float c2, - out float c3) + public static void ConvertFromRgb(float r, float g, float b, float maximumValue, float halfValue, float scale, out float c0, out float c1, out float c2, out float c3) { // The RGB inputs are unnormalized 0..255 encoder lanes. The BT.601 luma weights form Y, // while the signed chroma projections are biased by halfValue into the JPEG sample domain. @@ -185,104 +138,43 @@ internal abstract partial class JpegColorConverterBase /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void ConvertFromRgb( - Vector128 r, - Vector128 g, - Vector128 b, - Vector128 maximumValue, - Vector128 halfValue, - Vector128 scale, - out Vector128 c0, - out Vector128 c1, - out Vector128 c2, - out Vector128 c3) + public static void ConvertFromRgb(Vector128 r, Vector128 g, Vector128 b, Vector128 maximumValue, Vector128 halfValue, Vector128 scale, out Vector128 c0, out Vector128 c1, out Vector128 c2, out Vector128 c3) { // Each vector holds four consecutive values from one RGB plane. The nested multiply-add sequence // produces four Y lanes, four Cb lanes, and four Cr lanes without transposition. The association // exposes two FMA opportunities per output while preserving the scalar formula's term grouping. - c0 = Vector128_.MultiplyAddEstimate( - Vector128.Create(0.299F), - r, - Vector128_.MultiplyAddEstimate(Vector128.Create(0.587F), g, Vector128.Create(0.114F) * b)); - c1 = halfValue + Vector128_.MultiplyAddEstimate( - Vector128.Create(-0.168736F), - r, - Vector128_.MultiplyAddEstimate(Vector128.Create(-0.331264F), g, Vector128.Create(0.5F) * b)); - c2 = halfValue + Vector128_.MultiplyAddEstimate( - Vector128.Create(0.5F), - r, - Vector128_.MultiplyAddEstimate(Vector128.Create(-0.418688F), g, Vector128.Create(-0.081312F) * b)); + c0 = Vector128_.MultiplyAddEstimate(Vector128.Create(0.299F), r, Vector128_.MultiplyAddEstimate(Vector128.Create(0.587F), g, Vector128.Create(0.114F) * b)); + c1 = halfValue + Vector128_.MultiplyAddEstimate(Vector128.Create(-0.168736F), r, Vector128_.MultiplyAddEstimate(Vector128.Create(-0.331264F), g, Vector128.Create(0.5F) * b)); + c2 = halfValue + Vector128_.MultiplyAddEstimate(Vector128.Create(0.5F), r, Vector128_.MultiplyAddEstimate(Vector128.Create(-0.418688F), g, Vector128.Create(-0.081312F) * b)); c3 = default; } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void ConvertFromRgb( - Vector256 r, - Vector256 g, - Vector256 b, - Vector256 maximumValue, - Vector256 halfValue, - Vector256 scale, - out Vector256 c0, - out Vector256 c1, - out Vector256 c2, - out Vector256 c3) + public static void ConvertFromRgb(Vector256 r, Vector256 g, Vector256 b, Vector256 maximumValue, Vector256 halfValue, Vector256 scale, out Vector256 c0, out Vector256 c1, out Vector256 c2, out Vector256 c3) { // Eight planar RGB samples use the identical association as Vector128, allowing direct YMM FMA // generation while preserving the component-per-vector output layout. - c0 = Vector256_.MultiplyAddEstimate( - Vector256.Create(0.299F), - r, - Vector256_.MultiplyAddEstimate(Vector256.Create(0.587F), g, Vector256.Create(0.114F) * b)); - c1 = halfValue + Vector256_.MultiplyAddEstimate( - Vector256.Create(-0.168736F), - r, - Vector256_.MultiplyAddEstimate(Vector256.Create(-0.331264F), g, Vector256.Create(0.5F) * b)); - c2 = halfValue + Vector256_.MultiplyAddEstimate( - Vector256.Create(0.5F), - r, - Vector256_.MultiplyAddEstimate(Vector256.Create(-0.418688F), g, Vector256.Create(-0.081312F) * b)); + c0 = Vector256_.MultiplyAddEstimate(Vector256.Create(0.299F), r, Vector256_.MultiplyAddEstimate(Vector256.Create(0.587F), g, Vector256.Create(0.114F) * b)); + c1 = halfValue + Vector256_.MultiplyAddEstimate(Vector256.Create(-0.168736F), r, Vector256_.MultiplyAddEstimate(Vector256.Create(-0.331264F), g, Vector256.Create(0.5F) * b)); + c2 = halfValue + Vector256_.MultiplyAddEstimate(Vector256.Create(0.5F), r, Vector256_.MultiplyAddEstimate(Vector256.Create(-0.418688F), g, Vector256.Create(-0.081312F) * b)); c3 = default; } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void ConvertFromRgb( - Vector512 r, - Vector512 g, - Vector512 b, - Vector512 maximumValue, - Vector512 halfValue, - Vector512 scale, - out Vector512 c0, - out Vector512 c1, - out Vector512 c2, - out Vector512 c3) + public static void ConvertFromRgb(Vector512 r, Vector512 g, Vector512 b, Vector512 maximumValue, Vector512 halfValue, Vector512 scale, out Vector512 c0, out Vector512 c1, out Vector512 c2, out Vector512 c3) { // Sixteen planar RGB samples use the same nested form. Constants are lane broadcasts and c3 is // deliberately zero because the shared traversal removes the unused fourth store for this operator. - c0 = Vector512_.MultiplyAddEstimate( - Vector512.Create(0.299F), - r, - Vector512_.MultiplyAddEstimate(Vector512.Create(0.587F), g, Vector512.Create(0.114F) * b)); - c1 = halfValue + Vector512_.MultiplyAddEstimate( - Vector512.Create(-0.168736F), - r, - Vector512_.MultiplyAddEstimate(Vector512.Create(-0.331264F), g, Vector512.Create(0.5F) * b)); - c2 = halfValue + Vector512_.MultiplyAddEstimate( - Vector512.Create(0.5F), - r, - Vector512_.MultiplyAddEstimate(Vector512.Create(-0.418688F), g, Vector512.Create(-0.081312F) * b)); + c0 = Vector512_.MultiplyAddEstimate(Vector512.Create(0.299F), r, Vector512_.MultiplyAddEstimate(Vector512.Create(0.587F), g, Vector512.Create(0.114F) * b)); + c1 = halfValue + Vector512_.MultiplyAddEstimate(Vector512.Create(-0.168736F), r, Vector512_.MultiplyAddEstimate(Vector512.Create(-0.331264F), g, Vector512.Create(0.5F) * b)); + c2 = halfValue + Vector512_.MultiplyAddEstimate(Vector512.Create(0.5F), r, Vector512_.MultiplyAddEstimate(Vector512.Create(-0.418688F), g, Vector512.Create(-0.081312F) * b)); c3 = default; } /// - public static void ConvertToRgbInPlaceWithIcc( - Configuration configuration, - IccProfile profile, - in ComponentValues values, - float maximumValue) + public static void ConvertToRgbInPlaceWithIcc(Configuration configuration, IccProfile profile, in ComponentValues values, float maximumValue) { using IMemoryOwner memoryOwner = configuration.MemoryAllocator.Allocate(values.Component0.Length * 3); Span packed = memoryOwner.Memory.Span; diff --git a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YccKOperator.cs b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YccKOperator.cs index fb85194e6..003c77227 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YccKOperator.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YccKOperator.cs @@ -103,6 +103,7 @@ internal abstract partial class JpegColorConverterBase // CMYK extraction supplies inverted chromatic samples and K. Reflecting the first three results // reconstructs the chromatic RGB that YCbCr encodes, while K passes through untouched. CmykOperator.ConvertFromRgb(r, g, b, maximumValue, halfValue, scale, out float c, out float m, out float y, out c3); + YCbCrOperator.ConvertFromRgb(maximumValue - c, maximumValue - m, maximumValue - y, maximumValue, halfValue, scale, out c0, out c1, out c2, out _); } @@ -112,6 +113,7 @@ internal abstract partial class JpegColorConverterBase { // Static constrained calls inline both stages, keeping four pixels in registers without materializing CMYK planes. CmykOperator.ConvertFromRgb(r, g, b, maximumValue, halfValue, scale, out Vector128 c, out Vector128 m, out Vector128 y, out c3); + YCbCrOperator.ConvertFromRgb(maximumValue - c, maximumValue - m, maximumValue - y, maximumValue, halfValue, scale, out c0, out c1, out c2, out _); } @@ -121,6 +123,7 @@ internal abstract partial class JpegColorConverterBase { // Eight pixels flow through CMYK extraction and YCbCr projection entirely in YMM registers. CmykOperator.ConvertFromRgb(r, g, b, maximumValue, halfValue, scale, out Vector256 c, out Vector256 m, out Vector256 y, out c3); + YCbCrOperator.ConvertFromRgb(maximumValue - c, maximumValue - m, maximumValue - y, maximumValue, halfValue, scale, out c0, out c1, out c2, out _); } @@ -130,6 +133,7 @@ internal abstract partial class JpegColorConverterBase { // Sixteen pixels flow through both mathematical stages in registers without materializing intermediate planes. CmykOperator.ConvertFromRgb(r, g, b, maximumValue, halfValue, scale, out Vector512 c, out Vector512 m, out Vector512 y, out c3); + YCbCrOperator.ConvertFromRgb(maximumValue - c, maximumValue - m, maximumValue - y, maximumValue, halfValue, scale, out c0, out c1, out c2, out _); } diff --git a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterBase.cs b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterBase.cs index 26e4c3584..36adf8f75 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterBase.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterBase.cs @@ -2,9 +2,6 @@ // Licensed under the Six Labors Split License. #nullable disable -using System.Numerics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Metadata.Profiles.Icc; @@ -101,124 +98,6 @@ internal abstract partial class JpegColorConverterBase /// Blue colors lane. public abstract void ConvertFromRgb(in ComponentValues values, Span rLane, Span gLane, Span bLane); - public static void PackedNormalizeInterleave3( - ReadOnlySpan xLane, - ReadOnlySpan yLane, - ReadOnlySpan zLane, - Span packed, - float scale) - { - DebugGuard.IsTrue(packed.Length % 3 == 0, "Packed length must be divisible by 3."); - DebugGuard.IsTrue(yLane.Length == xLane.Length, nameof(yLane), "Channels must be of same size!"); - DebugGuard.IsTrue(zLane.Length == xLane.Length, nameof(zLane), "Channels must be of same size!"); - DebugGuard.MustBeLessThanOrEqualTo(packed.Length / 3, xLane.Length, nameof(packed)); - - // TODO: Investigate SIMD version of this. - ref float xLaneRef = ref MemoryMarshal.GetReference(xLane); - ref float yLaneRef = ref MemoryMarshal.GetReference(yLane); - ref float zLaneRef = ref MemoryMarshal.GetReference(zLane); - ref float packedRef = ref MemoryMarshal.GetReference(packed); - - for (nuint i = 0; i < (nuint)xLane.Length; i++) - { - nuint baseIdx = i * 3; - Unsafe.Add(ref packedRef, baseIdx) = Unsafe.Add(ref xLaneRef, i) * scale; - Unsafe.Add(ref packedRef, baseIdx + 1) = Unsafe.Add(ref yLaneRef, i) * scale; - Unsafe.Add(ref packedRef, baseIdx + 2) = Unsafe.Add(ref zLaneRef, i) * scale; - } - } - - public static void UnpackDeinterleave3( - ReadOnlySpan packed, - Span xLane, - Span yLane, - Span zLane) - { - DebugGuard.IsTrue(packed.Length == xLane.Length, nameof(packed), "Channels must be of same size!"); - DebugGuard.IsTrue(yLane.Length == xLane.Length, nameof(yLane), "Channels must be of same size!"); - DebugGuard.IsTrue(zLane.Length == xLane.Length, nameof(zLane), "Channels must be of same size!"); - - // TODO: Investigate SIMD version of this. - ref float packedRef = ref MemoryMarshal.GetReference(MemoryMarshal.Cast(packed)); - ref float xLaneRef = ref MemoryMarshal.GetReference(xLane); - ref float yLaneRef = ref MemoryMarshal.GetReference(yLane); - ref float zLaneRef = ref MemoryMarshal.GetReference(zLane); - - for (nuint i = 0; i < (nuint)packed.Length; i++) - { - nuint baseIdx = i * 3; - Unsafe.Add(ref xLaneRef, i) = Unsafe.Add(ref packedRef, baseIdx); - Unsafe.Add(ref yLaneRef, i) = Unsafe.Add(ref packedRef, baseIdx + 1); - Unsafe.Add(ref zLaneRef, i) = Unsafe.Add(ref packedRef, baseIdx + 2); - } - } - - public static void PackedNormalizeInterleave4( - ReadOnlySpan xLane, - ReadOnlySpan yLane, - ReadOnlySpan zLane, - ReadOnlySpan wLane, - Span packed, - float maxValue) - { - DebugGuard.IsTrue(packed.Length % 4 == 0, "Packed length must be divisible by 4."); - DebugGuard.IsTrue(yLane.Length == xLane.Length, nameof(yLane), "Channels must be of same size!"); - DebugGuard.IsTrue(zLane.Length == xLane.Length, nameof(zLane), "Channels must be of same size!"); - DebugGuard.IsTrue(wLane.Length == xLane.Length, nameof(wLane), "Channels must be of same size!"); - DebugGuard.MustBeLessThanOrEqualTo(packed.Length / 4, xLane.Length, nameof(packed)); - - float scale = 1F / maxValue; - - // TODO: Investigate SIMD version of this. - ref float xLaneRef = ref MemoryMarshal.GetReference(xLane); - ref float yLaneRef = ref MemoryMarshal.GetReference(yLane); - ref float zLaneRef = ref MemoryMarshal.GetReference(zLane); - ref float wLaneRef = ref MemoryMarshal.GetReference(wLane); - ref float packedRef = ref MemoryMarshal.GetReference(packed); - - for (nuint i = 0; i < (nuint)xLane.Length; i++) - { - nuint baseIdx = i * 4; - Unsafe.Add(ref packedRef, baseIdx) = Unsafe.Add(ref xLaneRef, i) * scale; - Unsafe.Add(ref packedRef, baseIdx + 1) = Unsafe.Add(ref yLaneRef, i) * scale; - Unsafe.Add(ref packedRef, baseIdx + 2) = Unsafe.Add(ref zLaneRef, i) * scale; - Unsafe.Add(ref packedRef, baseIdx + 3) = Unsafe.Add(ref wLaneRef, i) * scale; - } - } - - public static void PackedInvertNormalizeInterleave4( - ReadOnlySpan xLane, - ReadOnlySpan yLane, - ReadOnlySpan zLane, - ReadOnlySpan wLane, - Span packed, - float maxValue) - { - DebugGuard.IsTrue(packed.Length % 4 == 0, "Packed length must be divisible by 4."); - DebugGuard.IsTrue(yLane.Length == xLane.Length, nameof(yLane), "Channels must be of same size!"); - DebugGuard.IsTrue(zLane.Length == xLane.Length, nameof(zLane), "Channels must be of same size!"); - DebugGuard.IsTrue(wLane.Length == xLane.Length, nameof(wLane), "Channels must be of same size!"); - DebugGuard.MustBeLessThanOrEqualTo(packed.Length / 4, xLane.Length, nameof(packed)); - - float scale = 1F / maxValue; - - // TODO: Investigate SIMD version of this. - ref float xLaneRef = ref MemoryMarshal.GetReference(xLane); - ref float yLaneRef = ref MemoryMarshal.GetReference(yLane); - ref float zLaneRef = ref MemoryMarshal.GetReference(zLane); - ref float wLaneRef = ref MemoryMarshal.GetReference(wLane); - ref float packedRef = ref MemoryMarshal.GetReference(packed); - - for (nuint i = 0; i < (nuint)xLane.Length; i++) - { - nuint baseIdx = i * 4; - Unsafe.Add(ref packedRef, baseIdx) = (maxValue - Unsafe.Add(ref xLaneRef, i)) * scale; - Unsafe.Add(ref packedRef, baseIdx + 1) = (maxValue - Unsafe.Add(ref yLaneRef, i)) * scale; - Unsafe.Add(ref packedRef, baseIdx + 2) = (maxValue - Unsafe.Add(ref zLaneRef, i)) * scale; - Unsafe.Add(ref packedRef, baseIdx + 3) = (maxValue - Unsafe.Add(ref wLaneRef, i)) * scale; - } - } - /// /// Returns the s for all supported color spaces and precisions. /// @@ -382,6 +261,14 @@ internal abstract partial class JpegColorConverterBase this.Component3 = this.ComponentCount > 3 ? processors[3].GetColorBufferRowSpan(row) : []; } + /// + /// Initializes a new instance of the struct from explicitly supplied planar spans. + /// + /// The number of populated component planes. + /// The first component plane. + /// The second component plane, if present. + /// The third component plane, if present. + /// The fourth component plane, if present. internal ComponentValues( int componentCount, Span c0, @@ -396,6 +283,12 @@ internal abstract partial class JpegColorConverterBase this.Component3 = c3; } + /// + /// Creates a view over the same component planes for the requested sample range. + /// + /// The zero-based sample offset. + /// The number of samples in each returned plane. + /// The sliced component values. public ComponentValues Slice(int start, int length) { Span c0 = this.Component0.Slice(start, length); diff --git a/src/ImageSharp/Formats/Jpeg/Components/Encoder/ComponentProcessor.cs b/src/ImageSharp/Formats/Jpeg/Components/Encoder/ComponentProcessor.cs index 177e9b44f..c68dd19b4 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Encoder/ComponentProcessor.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Encoder/ComponentProcessor.cs @@ -116,6 +116,8 @@ internal class ComponentProcessor : IDisposable } static void SumVertical(Span target, Span source) + + // Exact destination overlap is supported, so each accumulated row remains in target. => TensorPrimitives_.Add(target, source, target); static void SumHorizontal(Span target, int factor) @@ -164,6 +166,8 @@ internal class ComponentProcessor : IDisposable } static void MultiplyToAverage(Span target, float multiplier) + + // Apply the subsampling reciprocal in place after all contributing rows have been summed. => TensorPrimitives_.Multiply(target, multiplier, target); } } diff --git a/src/ImageSharp/Formats/Png/Filters/AverageFilter.cs b/src/ImageSharp/Formats/Png/Filters/AverageFilter.cs index 942a80ab7..2cd88d6bb 100644 --- a/src/ImageSharp/Formats/Png/Filters/AverageFilter.cs +++ b/src/ImageSharp/Formats/Png/Filters/AverageFilter.cs @@ -140,12 +140,7 @@ internal static class AverageFilter /// The sum of the total variance of the filtered row. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Encode(ReadOnlySpan scanline, ReadOnlySpan previousScanline, Span result, uint bytesPerPixel, out int sum) - => PngFilterEncoder.Encode( - scanline, - previousScanline, - result, - bytesPerPixel, - out sum); + => PngFilterEncoder.Encode(scanline, previousScanline, result, bytesPerPixel, out sum); /// /// Calculates the average value of two bytes diff --git a/src/ImageSharp/Formats/Png/Filters/IPngFilterOperator.cs b/src/ImageSharp/Formats/Png/Filters/IPngFilterOperator.cs index 9fcec7b78..c81187775 100644 --- a/src/ImageSharp/Formats/Png/Filters/IPngFilterOperator.cs +++ b/src/ImageSharp/Formats/Png/Filters/IPngFilterOperator.cs @@ -3,8 +3,8 @@ using System.Runtime.CompilerServices; using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.Arm; using System.Runtime.Intrinsics.X86; +using SixLabors.ImageSharp.Common.Helpers; namespace SixLabors.ImageSharp.Formats.Png.Filters; @@ -51,11 +51,7 @@ internal interface IPngFilterOperator /// The corresponding components in the preceding scanline. /// The preceding components in the preceding scanline. /// The filtered residuals. - public static abstract Vector128 Invoke( - Vector128 scan, - Vector128 left, - Vector128 above, - Vector128 upperLeft); + public static abstract Vector128 Invoke(Vector128 scan, Vector128 left, Vector128 above, Vector128 upperLeft); /// /// Filters thirty-two byte lanes from their PNG neighborhoods. @@ -65,11 +61,7 @@ internal interface IPngFilterOperator /// The corresponding components in the preceding scanline. /// The preceding components in the preceding scanline. /// The filtered residuals. - public static abstract Vector256 Invoke( - Vector256 scan, - Vector256 left, - Vector256 above, - Vector256 upperLeft); + public static abstract Vector256 Invoke(Vector256 scan, Vector256 left, Vector256 above, Vector256 upperLeft); /// /// Filters sixty-four byte lanes from their PNG neighborhoods. @@ -79,11 +71,7 @@ internal interface IPngFilterOperator /// The corresponding components in the preceding scanline. /// The preceding components in the preceding scanline. /// The filtered residuals. - public static abstract Vector512 Invoke( - Vector512 scan, - Vector512 left, - Vector512 above, - Vector512 upperLeft); + public static abstract Vector512 Invoke(Vector512 scan, Vector512 left, Vector512 above, Vector512 upperLeft); } /// @@ -109,29 +97,17 @@ internal readonly struct SubFilterOperator : IPngFilterOperator /// [MethodImpl(InliningOptions.AlwaysInline)] - public static Vector128 Invoke( - Vector128 scan, - Vector128 left, - Vector128 above, - Vector128 upperLeft) + public static Vector128 Invoke(Vector128 scan, Vector128 left, Vector128 above, Vector128 upperLeft) => scan - left; /// [MethodImpl(InliningOptions.AlwaysInline)] - public static Vector256 Invoke( - Vector256 scan, - Vector256 left, - Vector256 above, - Vector256 upperLeft) + public static Vector256 Invoke(Vector256 scan, Vector256 left, Vector256 above, Vector256 upperLeft) => scan - left; /// [MethodImpl(InliningOptions.AlwaysInline)] - public static Vector512 Invoke( - Vector512 scan, - Vector512 left, - Vector512 above, - Vector512 upperLeft) + public static Vector512 Invoke(Vector512 scan, Vector512 left, Vector512 above, Vector512 upperLeft) => scan - left; } @@ -158,29 +134,17 @@ internal readonly struct UpFilterOperator : IPngFilterOperator /// [MethodImpl(InliningOptions.AlwaysInline)] - public static Vector128 Invoke( - Vector128 scan, - Vector128 left, - Vector128 above, - Vector128 upperLeft) + public static Vector128 Invoke(Vector128 scan, Vector128 left, Vector128 above, Vector128 upperLeft) => scan - above; /// [MethodImpl(InliningOptions.AlwaysInline)] - public static Vector256 Invoke( - Vector256 scan, - Vector256 left, - Vector256 above, - Vector256 upperLeft) + public static Vector256 Invoke(Vector256 scan, Vector256 left, Vector256 above, Vector256 upperLeft) => scan - above; /// [MethodImpl(InliningOptions.AlwaysInline)] - public static Vector512 Invoke( - Vector512 scan, - Vector512 left, - Vector512 above, - Vector512 upperLeft) + public static Vector512 Invoke(Vector512 scan, Vector512 left, Vector512 above, Vector512 upperLeft) => scan - above; } @@ -208,11 +172,7 @@ internal readonly struct AverageFilterOperator : IPngFilterOperator /// [MethodImpl(InliningOptions.AlwaysInline)] - public static Vector128 Invoke( - Vector128 scan, - Vector128 left, - Vector128 above, - Vector128 upperLeft) + public static Vector128 Invoke(Vector128 scan, Vector128 left, Vector128 above, Vector128 upperLeft) { Vector128 average; @@ -239,20 +199,18 @@ internal readonly struct AverageFilterOperator : IPngFilterOperator /// [MethodImpl(InliningOptions.AlwaysInline)] - public static Vector256 Invoke( - Vector256 scan, - Vector256 left, - Vector256 above, - Vector256 upperLeft) + public static Vector256 Invoke(Vector256 scan, Vector256 left, Vector256 above, Vector256 upperLeft) + + // VPAVGB rounds (left + above) / 2 upward. Complementing both inputs and + // the result changes that to the truncated average required by PNG. => scan - ~Avx2.Average(~left, ~above); /// [MethodImpl(InliningOptions.AlwaysInline)] - public static Vector512 Invoke( - Vector512 scan, - Vector512 left, - Vector512 above, - Vector512 upperLeft) + public static Vector512 Invoke(Vector512 scan, Vector512 left, Vector512 above, Vector512 upperLeft) + + // AVX-512BW retains VPAVGB's upward rounding, so use the same complement + // identity as AVX2 to obtain floor((left + above) / 2) in every byte lane. => scan - ~Avx512BW.Average(~left, ~above); } @@ -283,20 +241,14 @@ internal readonly struct PaethFilterOperator : IPngFilterOperator int distanceUpperLeft = Numerics.Abs(p - upperLeft); // PNG resolves equal distances in left, above, upper-left order. - byte predictor = distanceLeft <= distanceAbove && distanceLeft <= distanceUpperLeft - ? left - : distanceAbove <= distanceUpperLeft ? above : upperLeft; + byte predictor = distanceLeft <= distanceAbove && distanceLeft <= distanceUpperLeft ? left : distanceAbove <= distanceUpperLeft ? above : upperLeft; return (byte)(scan - predictor); } /// [MethodImpl(InliningOptions.AlwaysInline)] - public static Vector128 Invoke( - Vector128 scan, - Vector128 left, - Vector128 above, - Vector128 upperLeft) + public static Vector128 Invoke(Vector128 scan, Vector128 left, Vector128 above, Vector128 upperLeft) { Vector128 predictor = Predict(left, above, upperLeft); return scan - predictor; @@ -304,11 +256,7 @@ internal readonly struct PaethFilterOperator : IPngFilterOperator /// [MethodImpl(InliningOptions.AlwaysInline)] - public static Vector256 Invoke( - Vector256 scan, - Vector256 left, - Vector256 above, - Vector256 upperLeft) + public static Vector256 Invoke(Vector256 scan, Vector256 left, Vector256 above, Vector256 upperLeft) { Vector256 predictor = Predict(left, above, upperLeft); return scan - predictor; @@ -316,11 +264,7 @@ internal readonly struct PaethFilterOperator : IPngFilterOperator /// [MethodImpl(InliningOptions.AlwaysInline)] - public static Vector512 Invoke( - Vector512 scan, - Vector512 left, - Vector512 above, - Vector512 upperLeft) + public static Vector512 Invoke(Vector512 scan, Vector512 left, Vector512 above, Vector512 upperLeft) { Vector512 predictor = Predict(left, above, upperLeft); return scan - predictor; @@ -329,196 +273,151 @@ internal readonly struct PaethFilterOperator : IPngFilterOperator /// /// Selects the nearest Paeth neighbor for sixteen independent byte lanes. /// + /// The reconstructed component immediately before each current component. + /// The reconstructed component immediately above each current component. + /// The reconstructed component diagonally above and before each current component. + /// The selected Paeth predictor for each byte lane. [MethodImpl(InliningOptions.AlwaysInline)] - private static Vector128 Predict( - Vector128 left, - Vector128 above, - Vector128 upperLeft) + private static Vector128 Predict(Vector128 left, Vector128 above, Vector128 upperLeft) { - Vector128 aboveMinusUpper = SubtractSaturate(above, upperLeft); - Vector128 leftMinusUpper = SubtractSaturate(left, upperLeft); - Vector128 distanceLeft = SubtractSaturate(upperLeft, above) | aboveMinusUpper; - Vector128 distanceAbove = SubtractSaturate(upperLeft, left) | leftMinusUpper; - - return SelectPredictor( - left, - above, - upperLeft, - aboveMinusUpper, - leftMinusUpper, - distanceLeft, - distanceAbove); + // For p = left + above - upperLeft, the Paeth distances simplify to: + // distanceLeft = |above - upperLeft| + // distanceAbove = |left - upperLeft| + // Computing both unsigned subtraction directions and OR-ing them obtains + // each absolute difference without widening the byte lanes. + Vector128 aboveMinusUpper = Vector128_.SubtractSaturate(above, upperLeft); + Vector128 leftMinusUpper = Vector128_.SubtractSaturate(left, upperLeft); + Vector128 distanceLeft = Vector128_.SubtractSaturate(upperLeft, above) | aboveMinusUpper; + Vector128 distanceAbove = Vector128_.SubtractSaturate(upperLeft, left) | leftMinusUpper; + + return SelectPredictor(left, above, upperLeft, aboveMinusUpper, leftMinusUpper, distanceLeft, distanceAbove); } /// /// Selects the nearest Paeth neighbor for thirty-two independent byte lanes. /// + /// The reconstructed component immediately before each current component. + /// The reconstructed component immediately above each current component. + /// The reconstructed component diagonally above and before each current component. + /// The selected Paeth predictor for each byte lane. [MethodImpl(InliningOptions.AlwaysInline)] - private static Vector256 Predict( - Vector256 left, - Vector256 above, - Vector256 upperLeft) + private static Vector256 Predict(Vector256 left, Vector256 above, Vector256 upperLeft) { - Vector256 aboveMinusUpper = Avx2.SubtractSaturate(above, upperLeft); - Vector256 leftMinusUpper = Avx2.SubtractSaturate(left, upperLeft); - Vector256 distanceLeft = Avx2.SubtractSaturate(upperLeft, above) | aboveMinusUpper; - Vector256 distanceAbove = Avx2.SubtractSaturate(upperLeft, left) | leftMinusUpper; - - return SelectPredictor( - left, - above, - upperLeft, - aboveMinusUpper, - leftMinusUpper, - distanceLeft, - distanceAbove); + // Apply the same Paeth identities as the 128-bit path to thirty-two lanes. + // Saturating subtraction in both directions forms the absolute differences + // without widening, preserving one predictor result per source byte. + Vector256 aboveMinusUpper = Vector256_.SubtractSaturate(above, upperLeft); + Vector256 leftMinusUpper = Vector256_.SubtractSaturate(left, upperLeft); + Vector256 distanceLeft = Vector256_.SubtractSaturate(upperLeft, above) | aboveMinusUpper; + Vector256 distanceAbove = Vector256_.SubtractSaturate(upperLeft, left) | leftMinusUpper; + + return SelectPredictor(left, above, upperLeft, aboveMinusUpper, leftMinusUpper, distanceLeft, distanceAbove); } /// /// Selects the nearest Paeth neighbor for sixty-four independent byte lanes. /// + /// The reconstructed component immediately before each current component. + /// The reconstructed component immediately above each current component. + /// The reconstructed component diagonally above and before each current component. + /// The selected Paeth predictor for each byte lane. [MethodImpl(InliningOptions.AlwaysInline)] - private static Vector512 Predict( - Vector512 left, - Vector512 above, - Vector512 upperLeft) + private static Vector512 Predict(Vector512 left, Vector512 above, Vector512 upperLeft) { - Vector512 aboveMinusUpper = Avx512BW.SubtractSaturate(above, upperLeft); - Vector512 leftMinusUpper = Avx512BW.SubtractSaturate(left, upperLeft); - Vector512 distanceLeft = Avx512BW.SubtractSaturate(upperLeft, above) | aboveMinusUpper; - Vector512 distanceAbove = Avx512BW.SubtractSaturate(upperLeft, left) | leftMinusUpper; - - return SelectPredictor( - left, - above, - upperLeft, - aboveMinusUpper, - leftMinusUpper, - distanceLeft, - distanceAbove); + // Apply the same byte-lane Paeth identities to sixty-four AVX-512BW lanes. + // No cross-lane operation is required because every component has its own + // left, above, and upper-left inputs at the matching vector index. + Vector512 aboveMinusUpper = Vector512_.SubtractSaturate(above, upperLeft); + Vector512 leftMinusUpper = Vector512_.SubtractSaturate(left, upperLeft); + Vector512 distanceLeft = Vector512_.SubtractSaturate(upperLeft, above) | aboveMinusUpper; + Vector512 distanceAbove = Vector512_.SubtractSaturate(upperLeft, left) | leftMinusUpper; + + return SelectPredictor(left, above, upperLeft, aboveMinusUpper, leftMinusUpper, distanceLeft, distanceAbove); } /// /// Applies Paeth distance and tie-breaking rules to sixteen lanes. /// + /// The left-neighbor candidates. + /// The above-neighbor candidates. + /// The upper-left-neighbor candidates. + /// The saturated differences from above to upper-left. + /// The saturated differences from left to upper-left. + /// The Paeth distances for the left candidates. + /// The Paeth distances for the above candidates. + /// The selected Paeth predictor for each byte lane. [MethodImpl(InliningOptions.AlwaysInline)] - private static Vector128 SelectPredictor( - Vector128 left, - Vector128 above, - Vector128 upperLeft, - Vector128 aboveMinusUpper, - Vector128 leftMinusUpper, - Vector128 distanceLeft, - Vector128 distanceAbove) + private static Vector128 SelectPredictor(Vector128 left, Vector128 above, Vector128 upperLeft, Vector128 aboveMinusUpper, Vector128 leftMinusUpper, Vector128 distanceLeft, Vector128 distanceAbove) { - Vector128 sameDirection = Vector128.Equals( - Vector128.Equals(aboveMinusUpper, Vector128.Zero), - Vector128.Equals(leftMinusUpper, Vector128.Zero)); + Vector128 sameDirection = Vector128.Equals(Vector128.Equals(aboveMinusUpper, Vector128.Zero), Vector128.Equals(leftMinusUpper, Vector128.Zero)); - Vector128 distanceUpper = sameDirection - | SubtractSaturate(distanceAbove, distanceLeft) - | SubtractSaturate(distanceLeft, distanceAbove); + // If left and above lie on the same side of upper-left, distanceUpper is + // their summed distance and cannot beat either neighbor; the all-bits mask + // excludes upper-left. On opposite sides, that distance is the absolute + // difference between distanceLeft and distanceAbove. + Vector128 distanceUpper = sameDirection | Vector128_.SubtractSaturate(distanceAbove, distanceLeft) | Vector128_.SubtractSaturate(distanceLeft, distanceAbove); + // Equality selects above before upper-left, implementing PNG's second tie rule. Vector128 minimumAboveUpper = Vector128.Min(distanceUpper, distanceAbove); - Vector128 aboveOrUpper = Vector128.ConditionalSelect( - Vector128.Equals(minimumAboveUpper, distanceAbove), - above, - upperLeft); + Vector128 aboveOrUpper = Vector128.ConditionalSelect(Vector128.Equals(minimumAboveUpper, distanceAbove), above, upperLeft); // Applying the left comparison last preserves PNG's left-first tie rule. - return Vector128.ConditionalSelect( - Vector128.Equals(Vector128.Min(minimumAboveUpper, distanceLeft), distanceLeft), - left, - aboveOrUpper); + return Vector128.ConditionalSelect(Vector128.Equals(Vector128.Min(minimumAboveUpper, distanceLeft), distanceLeft), left, aboveOrUpper); } /// /// Applies Paeth distance and tie-breaking rules to thirty-two lanes. /// + /// The left-neighbor candidates. + /// The above-neighbor candidates. + /// The upper-left-neighbor candidates. + /// The saturated differences from above to upper-left. + /// The saturated differences from left to upper-left. + /// The Paeth distances for the left candidates. + /// The Paeth distances for the above candidates. + /// The selected Paeth predictor for each byte lane. [MethodImpl(InliningOptions.AlwaysInline)] - private static Vector256 SelectPredictor( - Vector256 left, - Vector256 above, - Vector256 upperLeft, - Vector256 aboveMinusUpper, - Vector256 leftMinusUpper, - Vector256 distanceLeft, - Vector256 distanceAbove) + private static Vector256 SelectPredictor(Vector256 left, Vector256 above, Vector256 upperLeft, Vector256 aboveMinusUpper, Vector256 leftMinusUpper, Vector256 distanceLeft, Vector256 distanceAbove) { - Vector256 sameDirection = Vector256.Equals( - Vector256.Equals(aboveMinusUpper, Vector256.Zero), - Vector256.Equals(leftMinusUpper, Vector256.Zero)); + Vector256 sameDirection = Vector256.Equals(Vector256.Equals(aboveMinusUpper, Vector256.Zero), Vector256.Equals(leftMinusUpper, Vector256.Zero)); - Vector256 distanceUpper = sameDirection - | Avx2.SubtractSaturate(distanceAbove, distanceLeft) - | Avx2.SubtractSaturate(distanceLeft, distanceAbove); + // Exclude upper-left when its distance is the non-minimal sum; otherwise + // compute its distance as the absolute difference of the two known distances. + Vector256 distanceUpper = sameDirection | Vector256_.SubtractSaturate(distanceAbove, distanceLeft) | Vector256_.SubtractSaturate(distanceLeft, distanceAbove); + // Select above on equality, then select left on equality to preserve PNG's + // required left, above, upper-left tie order in every byte lane. Vector256 minimumAboveUpper = Vector256.Min(distanceUpper, distanceAbove); - Vector256 aboveOrUpper = Vector256.ConditionalSelect( - Vector256.Equals(minimumAboveUpper, distanceAbove), - above, - upperLeft); - - return Vector256.ConditionalSelect( - Vector256.Equals(Vector256.Min(minimumAboveUpper, distanceLeft), distanceLeft), - left, - aboveOrUpper); + Vector256 aboveOrUpper = Vector256.ConditionalSelect(Vector256.Equals(minimumAboveUpper, distanceAbove), above, upperLeft); + + return Vector256.ConditionalSelect(Vector256.Equals(Vector256.Min(minimumAboveUpper, distanceLeft), distanceLeft), left, aboveOrUpper); } /// /// Applies Paeth distance and tie-breaking rules to sixty-four lanes. /// + /// The left-neighbor candidates. + /// The above-neighbor candidates. + /// The upper-left-neighbor candidates. + /// The saturated differences from above to upper-left. + /// The saturated differences from left to upper-left. + /// The Paeth distances for the left candidates. + /// The Paeth distances for the above candidates. + /// The selected Paeth predictor for each byte lane. [MethodImpl(InliningOptions.AlwaysInline)] - private static Vector512 SelectPredictor( - Vector512 left, - Vector512 above, - Vector512 upperLeft, - Vector512 aboveMinusUpper, - Vector512 leftMinusUpper, - Vector512 distanceLeft, - Vector512 distanceAbove) + private static Vector512 SelectPredictor(Vector512 left, Vector512 above, Vector512 upperLeft, Vector512 aboveMinusUpper, Vector512 leftMinusUpper, Vector512 distanceLeft, Vector512 distanceAbove) { - Vector512 sameDirection = Vector512.Equals( - Vector512.Equals(aboveMinusUpper, Vector512.Zero), - Vector512.Equals(leftMinusUpper, Vector512.Zero)); + Vector512 sameDirection = Vector512.Equals(Vector512.Equals(aboveMinusUpper, Vector512.Zero), Vector512.Equals(leftMinusUpper, Vector512.Zero)); - Vector512 distanceUpper = sameDirection - | Avx512BW.SubtractSaturate(distanceAbove, distanceLeft) - | Avx512BW.SubtractSaturate(distanceLeft, distanceAbove); + // Exclude upper-left when its distance is the non-minimal sum; otherwise + // compute its distance as the absolute difference of the two known distances. + Vector512 distanceUpper = sameDirection | Vector512_.SubtractSaturate(distanceAbove, distanceLeft) | Vector512_.SubtractSaturate(distanceLeft, distanceAbove); + // Select above on equality, then select left on equality to preserve PNG's + // required left, above, upper-left tie order in every byte lane. Vector512 minimumAboveUpper = Vector512.Min(distanceUpper, distanceAbove); - Vector512 aboveOrUpper = Vector512.ConditionalSelect( - Vector512.Equals(minimumAboveUpper, distanceAbove), - above, - upperLeft); - - return Vector512.ConditionalSelect( - Vector512.Equals(Vector512.Min(minimumAboveUpper, distanceLeft), distanceLeft), - left, - aboveOrUpper); - } - - /// - /// Performs an unsigned saturating subtraction using the active 128-bit instruction set. - /// - /// The minuend lanes. - /// The subtrahend lanes. - /// The saturated lane-wise differences. - [MethodImpl(InliningOptions.AlwaysInline)] - private static Vector128 SubtractSaturate(Vector128 left, Vector128 right) - { - if (Sse2.IsSupported) - { - return Sse2.SubtractSaturate(left, right); - } - - if (AdvSimd.IsSupported) - { - return AdvSimd.SubtractSaturate(left, right); - } + Vector512 aboveOrUpper = Vector512.ConditionalSelect(Vector512.Equals(minimumAboveUpper, distanceAbove), above, upperLeft); - // Subtracting the smaller operand produces max(left - right, 0) without - // requiring a backend-specific saturating-subtract instruction. - return left - Vector128.Min(left, right); + return Vector512.ConditionalSelect(Vector512.Equals(Vector512.Min(minimumAboveUpper, distanceLeft), distanceLeft), left, aboveOrUpper); } } diff --git a/src/ImageSharp/Formats/Png/Filters/PaethFilter.cs b/src/ImageSharp/Formats/Png/Filters/PaethFilter.cs index 0216a2627..eaeaaf173 100644 --- a/src/ImageSharp/Formats/Png/Filters/PaethFilter.cs +++ b/src/ImageSharp/Formats/Png/Filters/PaethFilter.cs @@ -192,12 +192,7 @@ internal static class PaethFilter /// The sum of the total variance of the filtered row. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Encode(ReadOnlySpan scanline, ReadOnlySpan previousScanline, Span result, int bytesPerPixel, out int sum) - => PngFilterEncoder.Encode( - scanline, - previousScanline, - result, - (uint)bytesPerPixel, - out sum); + => PngFilterEncoder.Encode(scanline, previousScanline, result, (uint)bytesPerPixel, out sum); /// /// Computes a simple linear function of the three neighboring pixels (left, above, upper left), then chooses diff --git a/src/ImageSharp/Formats/Png/Filters/PngFilterEncoder.cs b/src/ImageSharp/Formats/Png/Filters/PngFilterEncoder.cs index 4c298e0fc..3e4386d93 100644 --- a/src/ImageSharp/Formats/Png/Filters/PngFilterEncoder.cs +++ b/src/ImageSharp/Formats/Png/Filters/PngFilterEncoder.cs @@ -25,12 +25,7 @@ internal static class PngFilterEncoder // Inlining closes every static interface call over TOperator. The JIT can then remove // source loads ignored by simpler predictors and specialize the active register widths. [MethodImpl(InliningOptions.AlwaysInline)] - public static void Encode( - ReadOnlySpan scanline, - ReadOnlySpan previousScanline, - Span result, - uint bytesPerPixel, - out int sum) + public static void Encode(ReadOnlySpan scanline, ReadOnlySpan previousScanline, Span result, uint bytesPerPixel, out int sum) where TOperator : struct, IPngFilterOperator { DebugGuard.MustBeSameSized(scanline, previousScanline, nameof(scanline)); @@ -51,11 +46,7 @@ internal static class PngFilterEncoder { byte above = TOperator.UsesAbove ? Unsafe.Add(ref previousBaseRef, x) : (byte)0; - byte filtered = TOperator.Invoke( - Unsafe.Add(ref scanBaseRef, x), - 0, - above, - 0); + byte filtered = TOperator.Invoke(Unsafe.Add(ref scanBaseRef, x), 0, above, 0); Unsafe.Add(ref resultBaseRef, x + 1) = filtered; sum += Numerics.Abs(unchecked((sbyte)filtered)); @@ -76,28 +67,19 @@ internal static class PngFilterEncoder // four input vectors retain the scan/left/above/upper-left PNG layout. // Operator usage flags are constants after generic specialization, so // unused predictors do not retain even fault-preserving probe loads. - Vector512 left = TOperator.UsesLeft - ? Unsafe.As>(ref Unsafe.Add(ref scanBaseRef, xLeft)) - : default; - Vector512 above = TOperator.UsesAbove - ? Unsafe.As>(ref Unsafe.Add(ref previousBaseRef, x)) - : default; - Vector512 upperLeft = TOperator.UsesUpperLeft - ? Unsafe.As>(ref Unsafe.Add(ref previousBaseRef, xLeft)) - : default; - - Vector512 filtered = TOperator.Invoke( - Unsafe.As>(ref Unsafe.Add(ref scanBaseRef, x)), - left, - above, - upperLeft); + Vector512 left = TOperator.UsesLeft ? Unsafe.As>(ref Unsafe.Add(ref scanBaseRef, xLeft)) : default; + Vector512 above = TOperator.UsesAbove ? Unsafe.As>(ref Unsafe.Add(ref previousBaseRef, x)) : default; + Vector512 upperLeft = TOperator.UsesUpperLeft ? Unsafe.As>(ref Unsafe.Add(ref previousBaseRef, xLeft)) : default; + + Vector512 filtered = TOperator.Invoke(Unsafe.As>(ref Unsafe.Add(ref scanBaseRef, x)), left, above, upperLeft); Unsafe.As>(ref Unsafe.Add(ref resultBaseRef, x + 1)) = filtered; x += (uint)Vector512.Count; - // PNG scores each residual as abs((sbyte)residual). VPSADBW sums eight - // byte lanes into every other 32-bit lane without widening each byte. - Vector512 absolute = Avx512BW.Abs(filtered.AsSByte()); + // Vector512.Abs lowers to VPABSB under the surrounding AVX-512BW guard. + // Reinterpreting the signed result preserves -128's 0x80 bit pattern as + // the unsigned magnitude 128 consumed by VPSADBW. + Vector512 absolute = Vector512.Abs(filtered.AsSByte()).AsByte(); sum512 += Avx512BW.SumAbsoluteDifferences(absolute, Vector512.Zero).AsUInt32(); } @@ -114,29 +96,26 @@ internal static class PngFilterEncoder for (nuint xLeft = x - bytesPerPixel; (int)x <= oneRegisterFromEnd; xLeft += (uint)Vector256.Count) { - Vector256 left = TOperator.UsesLeft - ? Unsafe.As>(ref Unsafe.Add(ref scanBaseRef, xLeft)) - : default; - Vector256 above = TOperator.UsesAbove - ? Unsafe.As>(ref Unsafe.Add(ref previousBaseRef, x)) - : default; - Vector256 upperLeft = TOperator.UsesUpperLeft - ? Unsafe.As>(ref Unsafe.Add(ref previousBaseRef, xLeft)) - : default; - - Vector256 filtered = TOperator.Invoke( - Unsafe.As>(ref Unsafe.Add(ref scanBaseRef, x)), - left, - above, - upperLeft); + // Thirty-two byte lanes preserve the same scan/left/above/upper-left + // correspondence as the 512-bit path. Closed operator flags remove + // unused loads when the predictor does not consume that neighbor. + Vector256 left = TOperator.UsesLeft ? Unsafe.As>(ref Unsafe.Add(ref scanBaseRef, xLeft)) : default; + Vector256 above = TOperator.UsesAbove ? Unsafe.As>(ref Unsafe.Add(ref previousBaseRef, x)) : default; + Vector256 upperLeft = TOperator.UsesUpperLeft ? Unsafe.As>(ref Unsafe.Add(ref previousBaseRef, xLeft)) : default; + + Vector256 filtered = TOperator.Invoke(Unsafe.As>(ref Unsafe.Add(ref scanBaseRef, x)), left, above, upperLeft); Unsafe.As>(ref Unsafe.Add(ref resultBaseRef, x + 1)) = filtered; x += (uint)Vector256.Count; - Vector256 absolute = Avx2.Abs(filtered.AsSByte()); + // Vector256.Abs lowers to VPABSB under the surrounding AVX2 guard. + // Reinterpreting the signed result preserves -128's 0x80 bit pattern as + // the unsigned magnitude 128 consumed by VPSADBW. + Vector256 absolute = Vector256.Abs(filtered.AsSByte()).AsByte(); sum256 += Avx2.SumAbsoluteDifferences(absolute, Vector256.Zero).AsUInt32(); } + // Fold both 128-bit halves into the shared four-lane accumulator. sum128 += sum256.GetLower() + sum256.GetUpper(); } @@ -146,29 +125,24 @@ internal static class PngFilterEncoder for (nuint xLeft = x - bytesPerPixel; (int)x <= oneRegisterFromEnd; xLeft += (uint)Vector128.Count) { - Vector128 left = TOperator.UsesLeft - ? Unsafe.As>(ref Unsafe.Add(ref scanBaseRef, xLeft)) - : default; - Vector128 above = TOperator.UsesAbove - ? Unsafe.As>(ref Unsafe.Add(ref previousBaseRef, x)) - : default; - Vector128 upperLeft = TOperator.UsesUpperLeft - ? Unsafe.As>(ref Unsafe.Add(ref previousBaseRef, xLeft)) - : default; - - Vector128 filtered = TOperator.Invoke( - Unsafe.As>(ref Unsafe.Add(ref scanBaseRef, x)), - left, - above, - upperLeft); + // The final vector width handles sixteen more components with the + // same lane-wise neighborhood layout before the scalar remainder. + Vector128 left = TOperator.UsesLeft ? Unsafe.As>(ref Unsafe.Add(ref scanBaseRef, xLeft)) : default; + Vector128 above = TOperator.UsesAbove ? Unsafe.As>(ref Unsafe.Add(ref previousBaseRef, x)) : default; + Vector128 upperLeft = TOperator.UsesUpperLeft ? Unsafe.As>(ref Unsafe.Add(ref previousBaseRef, xLeft)) : default; + + Vector128 filtered = TOperator.Invoke(Unsafe.As>(ref Unsafe.Add(ref scanBaseRef, x)), left, above, upperLeft); Unsafe.As>(ref Unsafe.Add(ref resultBaseRef, x + 1)) = filtered; x += (uint)Vector128.Count; + // AccumulateAbsolute selects the available x86 or portable widening + // reduction while preserving the same unsigned 32-bit partial sums. sum128 = AccumulateAbsolute(sum128, filtered); } } + // Reduce the four partial lanes before adding individually scored tail bytes. sum += unchecked((int)Vector128.Sum(sum128)); for (nuint xLeft = x - bytesPerPixel; x < (uint)scanline.Length; xLeft++, x++) @@ -177,11 +151,7 @@ internal static class PngFilterEncoder byte above = TOperator.UsesAbove ? Unsafe.Add(ref previousBaseRef, x) : (byte)0; byte upperLeft = TOperator.UsesUpperLeft ? Unsafe.Add(ref previousBaseRef, xLeft) : (byte)0; - byte filtered = TOperator.Invoke( - Unsafe.Add(ref scanBaseRef, x), - left, - above, - upperLeft); + byte filtered = TOperator.Invoke(Unsafe.Add(ref scanBaseRef, x), left, above, upperLeft); Unsafe.Add(ref resultBaseRef, x + 1) = filtered; sum += Numerics.Abs(unchecked((sbyte)filtered)); @@ -197,27 +167,16 @@ internal static class PngFilterEncoder [MethodImpl(InliningOptions.AlwaysInline)] private static Vector128 AccumulateAbsolute(Vector128 accumulator, Vector128 residuals) { + // The generic absolute-value intrinsic selects PABSB where available and + // preserves -128's 0x80 bit pattern as the unsigned magnitude 128. + Vector128 absolute = Vector128.Abs(residuals.AsSByte()).AsByte(); + if (Sse2.IsSupported) { - Vector128 absolute; - - if (Ssse3.IsSupported) - { - absolute = Ssse3.Abs(residuals.AsSByte()); - } - else - { - // SSE2 has no packed signed-byte absolute instruction. The sign mask - // implements (value + mask) XOR mask, including -128 -> 128. - Vector128 mask = Sse2.CompareGreaterThan(Vector128.Zero, residuals.AsSByte()); - absolute = Sse2.Xor(Sse2.Add(residuals.AsSByte(), mask), mask).AsByte(); - } - return accumulator + Sse2.SumAbsoluteDifferences(absolute, Vector128.Zero).AsUInt32(); } - Vector128 absoluteArm = Vector128.Abs(residuals.AsSByte()).AsByte(); - (Vector128 lower16, Vector128 upper16) = Vector128.Widen(absoluteArm); + (Vector128 lower16, Vector128 upper16) = Vector128.Widen(absolute); (Vector128 lower0, Vector128 lower1) = Vector128.Widen(lower16); (Vector128 upper0, Vector128 upper1) = Vector128.Widen(upper16); diff --git a/src/ImageSharp/Formats/Png/Filters/SubFilter.cs b/src/ImageSharp/Formats/Png/Filters/SubFilter.cs index 957fb670f..946b59022 100644 --- a/src/ImageSharp/Formats/Png/Filters/SubFilter.cs +++ b/src/ImageSharp/Formats/Png/Filters/SubFilter.cs @@ -102,7 +102,7 @@ internal static class SubFilter } /// - /// Encodes a scanline with the sup filter applied. + /// Encodes a scanline with the sub filter applied. /// /// The scanline to encode. /// The filtered scanline result. @@ -110,10 +110,8 @@ internal static class SubFilter /// The sum of the total variance of the filtered row. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Encode(ReadOnlySpan scanline, Span result, int bytesPerPixel, out int sum) - => PngFilterEncoder.Encode( - scanline, - scanline, - result, - (uint)bytesPerPixel, - out sum); + + // Sub does not consume an above neighbor, so the shared traversal may alias + // the unused previous-row argument to the current row without an extra buffer. + => PngFilterEncoder.Encode(scanline, scanline, result, (uint)bytesPerPixel, out sum); } diff --git a/src/ImageSharp/Formats/Png/Filters/UpFilter.cs b/src/ImageSharp/Formats/Png/Filters/UpFilter.cs index 5f78833cd..d64a1ea51 100644 --- a/src/ImageSharp/Formats/Png/Filters/UpFilter.cs +++ b/src/ImageSharp/Formats/Png/Filters/UpFilter.cs @@ -36,10 +36,8 @@ internal static class UpFilter /// 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) - => PngFilterEncoder.Encode( - scanline, - previousScanline, - result, - 0, - out sum); + + // Up never reads a left neighbor, so bytesPerPixel is deliberately zero in + // the shared traversal and no unsigned left offset is evaluated. + => PngFilterEncoder.Encode(scanline, previousScanline, result, 0, out sum); } diff --git a/src/ImageSharp/Formats/Webp/AlphaDecoder.cs b/src/ImageSharp/Formats/Webp/AlphaDecoder.cs index 7c3562cb2..bbe9748fc 100644 --- a/src/ImageSharp/Formats/Webp/AlphaDecoder.cs +++ b/src/ImageSharp/Formats/Webp/AlphaDecoder.cs @@ -363,6 +363,7 @@ internal class AlphaDecoder : IDisposable } else { + // Byte addition intentionally wraps modulo 256, matching the WebP alpha predictor. TensorPrimitives_.Add(input[..width], prev[..width], dst[..width]); } } diff --git a/src/ImageSharp/Formats/Webp/Lossless/Vp8LHistogram.cs b/src/ImageSharp/Formats/Webp/Lossless/Vp8LHistogram.cs index fc3ecdd94..c59235e70 100644 --- a/src/ImageSharp/Formats/Webp/Lossless/Vp8LHistogram.cs +++ b/src/ImageSharp/Formats/Webp/Lossless/Vp8LHistogram.cs @@ -331,7 +331,7 @@ internal abstract unsafe class Vp8LHistogram { if (b.IsUsed(0)) { - AddVector(this.Literal, b.Literal, output.Literal, literalSize); + TensorPrimitives_.Add(this.Literal[..literalSize], b.Literal[..literalSize], output.Literal[..literalSize]); } else { @@ -354,7 +354,7 @@ internal abstract unsafe class Vp8LHistogram { if (b.IsUsed(1)) { - AddVector(this.Red, b.Red, output.Red, size); + TensorPrimitives_.Add(this.Red[..size], b.Red[..size], output.Red[..size]); } else { @@ -377,7 +377,7 @@ internal abstract unsafe class Vp8LHistogram { if (b.IsUsed(2)) { - AddVector(this.Blue, b.Blue, output.Blue, size); + TensorPrimitives_.Add(this.Blue[..size], b.Blue[..size], output.Blue[..size]); } else { @@ -400,7 +400,7 @@ internal abstract unsafe class Vp8LHistogram { if (b.IsUsed(3)) { - AddVector(this.Alpha, b.Alpha, output.Alpha, size); + TensorPrimitives_.Add(this.Alpha[..size], b.Alpha[..size], output.Alpha[..size]); } else { @@ -423,7 +423,7 @@ internal abstract unsafe class Vp8LHistogram { if (b.IsUsed(4)) { - AddVector(this.Distance, b.Distance, output.Distance, size); + TensorPrimitives_.Add(this.Distance[..size], b.Distance[..size], output.Distance[..size]); } else { @@ -534,14 +534,6 @@ internal abstract unsafe class Vp8LHistogram return cost; } - private static void AddVector(Span a, Span b, Span output, int count) - { - DebugGuard.MustBeGreaterThanOrEqualTo(a.Length, count, nameof(a.Length)); - DebugGuard.MustBeGreaterThanOrEqualTo(b.Length, count, nameof(b.Length)); - DebugGuard.MustBeGreaterThanOrEqualTo(output.Length, count, nameof(output.Length)); - - TensorPrimitives_.Add(a[..count], b[..count], output[..count]); - } } internal sealed unsafe class OwnedVp8LHistogram : Vp8LHistogram, IDisposable diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/AssociatedAlphaPixelBlenders.Generated.cs b/src/ImageSharp/PixelFormats/PixelBlenders/AssociatedAlphaPixelBlenders.Generated.cs index 85313dc20..d31e07c62 100644 --- a/src/ImageSharp/PixelFormats/PixelBlenders/AssociatedAlphaPixelBlenders.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelBlenders/AssociatedAlphaPixelBlenders.Generated.cs @@ -22,17 +22,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.NormalSrc(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.NormalSrc(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.NormalSrc(background, source, amount); } @@ -46,17 +40,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.MultiplySrc(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.MultiplySrc(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.MultiplySrc(background, source, amount); } @@ -70,17 +58,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.AddSrc(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.AddSrc(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.AddSrc(background, source, amount); } @@ -94,17 +76,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.SubtractSrc(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.SubtractSrc(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.SubtractSrc(background, source, amount); } @@ -118,17 +94,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.ScreenSrc(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.ScreenSrc(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.ScreenSrc(background, source, amount); } @@ -142,17 +112,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.DarkenSrc(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.DarkenSrc(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.DarkenSrc(background, source, amount); } @@ -166,17 +130,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.LightenSrc(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.LightenSrc(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.LightenSrc(background, source, amount); } @@ -190,17 +148,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.OverlaySrc(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.OverlaySrc(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.OverlaySrc(background, source, amount); } @@ -214,17 +166,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.HardLightSrc(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.HardLightSrc(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.HardLightSrc(background, source, amount); } @@ -238,17 +184,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.NormalSrcAtop(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.NormalSrcAtop(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.NormalSrcAtop(background, source, amount); } @@ -262,17 +202,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.MultiplySrcAtop(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.MultiplySrcAtop(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.MultiplySrcAtop(background, source, amount); } @@ -286,17 +220,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.AddSrcAtop(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.AddSrcAtop(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.AddSrcAtop(background, source, amount); } @@ -310,17 +238,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.SubtractSrcAtop(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.SubtractSrcAtop(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.SubtractSrcAtop(background, source, amount); } @@ -334,17 +256,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.ScreenSrcAtop(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.ScreenSrcAtop(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.ScreenSrcAtop(background, source, amount); } @@ -358,17 +274,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.DarkenSrcAtop(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.DarkenSrcAtop(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.DarkenSrcAtop(background, source, amount); } @@ -382,17 +292,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.LightenSrcAtop(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.LightenSrcAtop(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.LightenSrcAtop(background, source, amount); } @@ -406,17 +310,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.OverlaySrcAtop(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.OverlaySrcAtop(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.OverlaySrcAtop(background, source, amount); } @@ -430,17 +328,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.HardLightSrcAtop(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.HardLightSrcAtop(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.HardLightSrcAtop(background, source, amount); } @@ -454,17 +346,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.NormalSrcOver(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.NormalSrcOver(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.NormalSrcOver(background, source, amount); } @@ -478,17 +364,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.MultiplySrcOver(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.MultiplySrcOver(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.MultiplySrcOver(background, source, amount); } @@ -502,17 +382,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.AddSrcOver(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.AddSrcOver(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.AddSrcOver(background, source, amount); } @@ -526,17 +400,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.SubtractSrcOver(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.SubtractSrcOver(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.SubtractSrcOver(background, source, amount); } @@ -550,17 +418,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.ScreenSrcOver(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.ScreenSrcOver(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.ScreenSrcOver(background, source, amount); } @@ -574,17 +436,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.DarkenSrcOver(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.DarkenSrcOver(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.DarkenSrcOver(background, source, amount); } @@ -598,17 +454,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.LightenSrcOver(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.LightenSrcOver(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.LightenSrcOver(background, source, amount); } @@ -622,17 +472,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.OverlaySrcOver(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.OverlaySrcOver(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.OverlaySrcOver(background, source, amount); } @@ -646,17 +490,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.HardLightSrcOver(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.HardLightSrcOver(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.HardLightSrcOver(background, source, amount); } @@ -670,17 +508,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.NormalSrcIn(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.NormalSrcIn(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.NormalSrcIn(background, source, amount); } @@ -694,17 +526,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.MultiplySrcIn(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.MultiplySrcIn(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.MultiplySrcIn(background, source, amount); } @@ -718,17 +544,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.AddSrcIn(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.AddSrcIn(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.AddSrcIn(background, source, amount); } @@ -742,17 +562,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.SubtractSrcIn(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.SubtractSrcIn(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.SubtractSrcIn(background, source, amount); } @@ -766,17 +580,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.ScreenSrcIn(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.ScreenSrcIn(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.ScreenSrcIn(background, source, amount); } @@ -790,17 +598,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.DarkenSrcIn(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.DarkenSrcIn(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.DarkenSrcIn(background, source, amount); } @@ -814,17 +616,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.LightenSrcIn(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.LightenSrcIn(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.LightenSrcIn(background, source, amount); } @@ -838,17 +634,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.OverlaySrcIn(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.OverlaySrcIn(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.OverlaySrcIn(background, source, amount); } @@ -862,17 +652,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.HardLightSrcIn(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.HardLightSrcIn(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.HardLightSrcIn(background, source, amount); } @@ -886,17 +670,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.NormalSrcOut(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.NormalSrcOut(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.NormalSrcOut(background, source, amount); } @@ -910,17 +688,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.MultiplySrcOut(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.MultiplySrcOut(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.MultiplySrcOut(background, source, amount); } @@ -934,17 +706,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.AddSrcOut(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.AddSrcOut(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.AddSrcOut(background, source, amount); } @@ -958,17 +724,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.SubtractSrcOut(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.SubtractSrcOut(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.SubtractSrcOut(background, source, amount); } @@ -982,17 +742,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.ScreenSrcOut(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.ScreenSrcOut(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.ScreenSrcOut(background, source, amount); } @@ -1006,17 +760,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.DarkenSrcOut(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.DarkenSrcOut(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.DarkenSrcOut(background, source, amount); } @@ -1030,17 +778,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.LightenSrcOut(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.LightenSrcOut(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.LightenSrcOut(background, source, amount); } @@ -1054,17 +796,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.OverlaySrcOut(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.OverlaySrcOut(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.OverlaySrcOut(background, source, amount); } @@ -1078,17 +814,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.HardLightSrcOut(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.HardLightSrcOut(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.HardLightSrcOut(background, source, amount); } @@ -1102,17 +832,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.NormalDest(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.NormalDest(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.NormalDest(background, source, amount); } @@ -1126,17 +850,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.MultiplyDest(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.MultiplyDest(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.MultiplyDest(background, source, amount); } @@ -1150,17 +868,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.AddDest(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.AddDest(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.AddDest(background, source, amount); } @@ -1174,17 +886,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.SubtractDest(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.SubtractDest(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.SubtractDest(background, source, amount); } @@ -1198,17 +904,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.ScreenDest(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.ScreenDest(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.ScreenDest(background, source, amount); } @@ -1222,17 +922,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.DarkenDest(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.DarkenDest(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.DarkenDest(background, source, amount); } @@ -1246,17 +940,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.LightenDest(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.LightenDest(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.LightenDest(background, source, amount); } @@ -1270,17 +958,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.OverlayDest(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.OverlayDest(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.OverlayDest(background, source, amount); } @@ -1294,17 +976,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.HardLightDest(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.HardLightDest(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.HardLightDest(background, source, amount); } @@ -1318,17 +994,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.NormalDestAtop(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.NormalDestAtop(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.NormalDestAtop(background, source, amount); } @@ -1342,17 +1012,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.MultiplyDestAtop(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.MultiplyDestAtop(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.MultiplyDestAtop(background, source, amount); } @@ -1366,17 +1030,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.AddDestAtop(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.AddDestAtop(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.AddDestAtop(background, source, amount); } @@ -1390,17 +1048,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.SubtractDestAtop(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.SubtractDestAtop(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.SubtractDestAtop(background, source, amount); } @@ -1414,17 +1066,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.ScreenDestAtop(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.ScreenDestAtop(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.ScreenDestAtop(background, source, amount); } @@ -1438,17 +1084,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.DarkenDestAtop(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.DarkenDestAtop(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.DarkenDestAtop(background, source, amount); } @@ -1462,17 +1102,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.LightenDestAtop(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.LightenDestAtop(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.LightenDestAtop(background, source, amount); } @@ -1486,17 +1120,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.OverlayDestAtop(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.OverlayDestAtop(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.OverlayDestAtop(background, source, amount); } @@ -1510,17 +1138,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.HardLightDestAtop(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.HardLightDestAtop(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.HardLightDestAtop(background, source, amount); } @@ -1534,17 +1156,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.NormalDestOver(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.NormalDestOver(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.NormalDestOver(background, source, amount); } @@ -1558,17 +1174,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.MultiplyDestOver(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.MultiplyDestOver(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.MultiplyDestOver(background, source, amount); } @@ -1582,17 +1192,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.AddDestOver(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.AddDestOver(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.AddDestOver(background, source, amount); } @@ -1606,17 +1210,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.SubtractDestOver(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.SubtractDestOver(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.SubtractDestOver(background, source, amount); } @@ -1630,17 +1228,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.ScreenDestOver(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.ScreenDestOver(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.ScreenDestOver(background, source, amount); } @@ -1654,17 +1246,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.DarkenDestOver(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.DarkenDestOver(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.DarkenDestOver(background, source, amount); } @@ -1678,17 +1264,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.LightenDestOver(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.LightenDestOver(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.LightenDestOver(background, source, amount); } @@ -1702,17 +1282,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.OverlayDestOver(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.OverlayDestOver(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.OverlayDestOver(background, source, amount); } @@ -1726,17 +1300,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.HardLightDestOver(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.HardLightDestOver(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.HardLightDestOver(background, source, amount); } @@ -1750,17 +1318,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.NormalDestIn(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.NormalDestIn(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.NormalDestIn(background, source, amount); } @@ -1774,17 +1336,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.MultiplyDestIn(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.MultiplyDestIn(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.MultiplyDestIn(background, source, amount); } @@ -1798,17 +1354,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.AddDestIn(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.AddDestIn(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.AddDestIn(background, source, amount); } @@ -1822,17 +1372,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.SubtractDestIn(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.SubtractDestIn(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.SubtractDestIn(background, source, amount); } @@ -1846,17 +1390,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.ScreenDestIn(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.ScreenDestIn(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.ScreenDestIn(background, source, amount); } @@ -1870,17 +1408,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.DarkenDestIn(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.DarkenDestIn(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.DarkenDestIn(background, source, amount); } @@ -1894,17 +1426,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.LightenDestIn(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.LightenDestIn(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.LightenDestIn(background, source, amount); } @@ -1918,17 +1444,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.OverlayDestIn(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.OverlayDestIn(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.OverlayDestIn(background, source, amount); } @@ -1942,17 +1462,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.HardLightDestIn(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.HardLightDestIn(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.HardLightDestIn(background, source, amount); } @@ -1966,17 +1480,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.NormalDestOut(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.NormalDestOut(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.NormalDestOut(background, source, amount); } @@ -1990,17 +1498,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.MultiplyDestOut(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.MultiplyDestOut(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.MultiplyDestOut(background, source, amount); } @@ -2014,17 +1516,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.AddDestOut(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.AddDestOut(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.AddDestOut(background, source, amount); } @@ -2038,17 +1534,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.SubtractDestOut(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.SubtractDestOut(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.SubtractDestOut(background, source, amount); } @@ -2062,17 +1552,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.ScreenDestOut(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.ScreenDestOut(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.ScreenDestOut(background, source, amount); } @@ -2086,17 +1570,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.DarkenDestOut(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.DarkenDestOut(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.DarkenDestOut(background, source, amount); } @@ -2110,17 +1588,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.LightenDestOut(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.LightenDestOut(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.LightenDestOut(background, source, amount); } @@ -2134,17 +1606,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.OverlayDestOut(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.OverlayDestOut(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.OverlayDestOut(background, source, amount); } @@ -2158,17 +1624,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.HardLightDestOut(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.HardLightDestOut(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.HardLightDestOut(background, source, amount); } @@ -2182,17 +1642,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.NormalClear(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.NormalClear(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.NormalClear(background, source, amount); } @@ -2206,17 +1660,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.MultiplyClear(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.MultiplyClear(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.MultiplyClear(background, source, amount); } @@ -2230,17 +1678,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.AddClear(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.AddClear(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.AddClear(background, source, amount); } @@ -2254,17 +1696,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.SubtractClear(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.SubtractClear(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.SubtractClear(background, source, amount); } @@ -2278,17 +1714,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.ScreenClear(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.ScreenClear(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.ScreenClear(background, source, amount); } @@ -2302,17 +1732,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.DarkenClear(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.DarkenClear(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.DarkenClear(background, source, amount); } @@ -2326,17 +1750,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.LightenClear(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.LightenClear(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.LightenClear(background, source, amount); } @@ -2350,17 +1768,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.OverlayClear(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.OverlayClear(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.OverlayClear(background, source, amount); } @@ -2374,17 +1786,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.HardLightClear(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.HardLightClear(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.HardLightClear(background, source, amount); } @@ -2398,17 +1804,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.NormalXor(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.NormalXor(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.NormalXor(background, source, amount); } @@ -2422,17 +1822,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.MultiplyXor(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.MultiplyXor(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.MultiplyXor(background, source, amount); } @@ -2446,17 +1840,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.AddXor(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.AddXor(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.AddXor(background, source, amount); } @@ -2470,17 +1858,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.SubtractXor(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.SubtractXor(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.SubtractXor(background, source, amount); } @@ -2494,17 +1876,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.ScreenXor(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.ScreenXor(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.ScreenXor(background, source, amount); } @@ -2518,17 +1894,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.DarkenXor(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.DarkenXor(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.DarkenXor(background, source, amount); } @@ -2542,17 +1912,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.LightenXor(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.LightenXor(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.LightenXor(background, source, amount); } @@ -2566,17 +1930,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.OverlayXor(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.OverlayXor(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.OverlayXor(background, source, amount); } @@ -2590,17 +1948,11 @@ internal static class AssociatedAlphaPixelBlenderOperators => AssociatedAlphaPorterDuffFunctions.HardLightXor(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.HardLightXor(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.HardLightXor(background, source, amount); } diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/AssociatedAlphaPixelBlenders.Generated.tt b/src/ImageSharp/PixelFormats/PixelBlenders/AssociatedAlphaPixelBlenders.Generated.tt index 70607feb1..801d76328 100644 --- a/src/ImageSharp/PixelFormats/PixelBlenders/AssociatedAlphaPixelBlenders.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelBlenders/AssociatedAlphaPixelBlenders.Generated.tt @@ -66,17 +66,11 @@ foreach (var composer in composers) => AssociatedAlphaPorterDuffFunctions.<#= blenderComposer #>(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => AssociatedAlphaPorterDuffFunctions.<#= blenderComposer #>(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => AssociatedAlphaPorterDuffFunctions.<#= blenderComposer #>(background, source, amount); } diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/AssociatedAlphaPixelBlender{TPixel,TOperator}.cs b/src/ImageSharp/PixelFormats/PixelBlenders/AssociatedAlphaPixelBlender{TPixel,TOperator}.cs index 00427308c..81a3f24a8 100644 --- a/src/ImageSharp/PixelFormats/PixelBlenders/AssociatedAlphaPixelBlender{TPixel,TOperator}.cs +++ b/src/ImageSharp/PixelFormats/PixelBlenders/AssociatedAlphaPixelBlender{TPixel,TOperator}.cs @@ -20,10 +20,7 @@ internal abstract class AssociatedAlphaPixelBlender : PixelBl public sealed override TPixel Blend(TPixel background, TPixel source, float amount) { // Associated RGB and alpha must remain in their stored representation throughout composition. - Vector4 result = TOperator.Invoke( - background.ToAssociatedScaledVector4(), - source.ToAssociatedScaledVector4(), - Numerics.Clamp(amount, 0, 1F)); + Vector4 result = TOperator.Invoke(background.ToAssociatedScaledVector4(), source.ToAssociatedScaledVector4(), Numerics.Clamp(amount, 0, 1F)); return TPixel.FromAssociatedScaledVector4(result); } diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs index 250d789dd..2ff4660b7 100644 --- a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs @@ -22,17 +22,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.NormalSrc(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.NormalSrc(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.NormalSrc(background, source, amount); } @@ -46,17 +40,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.MultiplySrc(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.MultiplySrc(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.MultiplySrc(background, source, amount); } @@ -70,17 +58,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.AddSrc(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.AddSrc(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.AddSrc(background, source, amount); } @@ -94,17 +76,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.SubtractSrc(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.SubtractSrc(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.SubtractSrc(background, source, amount); } @@ -118,17 +94,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.ScreenSrc(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.ScreenSrc(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.ScreenSrc(background, source, amount); } @@ -142,17 +112,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.DarkenSrc(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.DarkenSrc(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.DarkenSrc(background, source, amount); } @@ -166,17 +130,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.LightenSrc(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.LightenSrc(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.LightenSrc(background, source, amount); } @@ -190,17 +148,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.OverlaySrc(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.OverlaySrc(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.OverlaySrc(background, source, amount); } @@ -214,17 +166,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.HardLightSrc(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.HardLightSrc(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.HardLightSrc(background, source, amount); } @@ -238,17 +184,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.NormalSrcAtop(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.NormalSrcAtop(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.NormalSrcAtop(background, source, amount); } @@ -262,17 +202,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.MultiplySrcAtop(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.MultiplySrcAtop(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.MultiplySrcAtop(background, source, amount); } @@ -286,17 +220,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.AddSrcAtop(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.AddSrcAtop(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.AddSrcAtop(background, source, amount); } @@ -310,17 +238,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.SubtractSrcAtop(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.SubtractSrcAtop(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.SubtractSrcAtop(background, source, amount); } @@ -334,17 +256,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.ScreenSrcAtop(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.ScreenSrcAtop(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.ScreenSrcAtop(background, source, amount); } @@ -358,17 +274,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.DarkenSrcAtop(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.DarkenSrcAtop(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.DarkenSrcAtop(background, source, amount); } @@ -382,17 +292,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.LightenSrcAtop(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.LightenSrcAtop(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.LightenSrcAtop(background, source, amount); } @@ -406,17 +310,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.OverlaySrcAtop(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.OverlaySrcAtop(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.OverlaySrcAtop(background, source, amount); } @@ -430,17 +328,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.HardLightSrcAtop(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.HardLightSrcAtop(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.HardLightSrcAtop(background, source, amount); } @@ -454,17 +346,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.NormalSrcOver(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.NormalSrcOver(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.NormalSrcOver(background, source, amount); } @@ -478,17 +364,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.MultiplySrcOver(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.MultiplySrcOver(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.MultiplySrcOver(background, source, amount); } @@ -502,17 +382,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.AddSrcOver(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.AddSrcOver(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.AddSrcOver(background, source, amount); } @@ -526,17 +400,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.SubtractSrcOver(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.SubtractSrcOver(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.SubtractSrcOver(background, source, amount); } @@ -550,17 +418,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.ScreenSrcOver(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.ScreenSrcOver(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.ScreenSrcOver(background, source, amount); } @@ -574,17 +436,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.DarkenSrcOver(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.DarkenSrcOver(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.DarkenSrcOver(background, source, amount); } @@ -598,17 +454,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.LightenSrcOver(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.LightenSrcOver(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.LightenSrcOver(background, source, amount); } @@ -622,17 +472,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.OverlaySrcOver(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.OverlaySrcOver(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.OverlaySrcOver(background, source, amount); } @@ -646,17 +490,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.HardLightSrcOver(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.HardLightSrcOver(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.HardLightSrcOver(background, source, amount); } @@ -670,17 +508,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.NormalSrcIn(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.NormalSrcIn(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.NormalSrcIn(background, source, amount); } @@ -694,17 +526,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.MultiplySrcIn(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.MultiplySrcIn(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.MultiplySrcIn(background, source, amount); } @@ -718,17 +544,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.AddSrcIn(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.AddSrcIn(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.AddSrcIn(background, source, amount); } @@ -742,17 +562,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.SubtractSrcIn(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.SubtractSrcIn(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.SubtractSrcIn(background, source, amount); } @@ -766,17 +580,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.ScreenSrcIn(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.ScreenSrcIn(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.ScreenSrcIn(background, source, amount); } @@ -790,17 +598,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.DarkenSrcIn(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.DarkenSrcIn(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.DarkenSrcIn(background, source, amount); } @@ -814,17 +616,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.LightenSrcIn(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.LightenSrcIn(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.LightenSrcIn(background, source, amount); } @@ -838,17 +634,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.OverlaySrcIn(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.OverlaySrcIn(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.OverlaySrcIn(background, source, amount); } @@ -862,17 +652,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.HardLightSrcIn(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.HardLightSrcIn(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.HardLightSrcIn(background, source, amount); } @@ -886,17 +670,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.NormalSrcOut(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.NormalSrcOut(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.NormalSrcOut(background, source, amount); } @@ -910,17 +688,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.MultiplySrcOut(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.MultiplySrcOut(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.MultiplySrcOut(background, source, amount); } @@ -934,17 +706,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.AddSrcOut(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.AddSrcOut(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.AddSrcOut(background, source, amount); } @@ -958,17 +724,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.SubtractSrcOut(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.SubtractSrcOut(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.SubtractSrcOut(background, source, amount); } @@ -982,17 +742,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.ScreenSrcOut(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.ScreenSrcOut(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.ScreenSrcOut(background, source, amount); } @@ -1006,17 +760,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.DarkenSrcOut(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.DarkenSrcOut(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.DarkenSrcOut(background, source, amount); } @@ -1030,17 +778,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.LightenSrcOut(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.LightenSrcOut(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.LightenSrcOut(background, source, amount); } @@ -1054,17 +796,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.OverlaySrcOut(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.OverlaySrcOut(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.OverlaySrcOut(background, source, amount); } @@ -1078,17 +814,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.HardLightSrcOut(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.HardLightSrcOut(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.HardLightSrcOut(background, source, amount); } @@ -1102,17 +832,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.NormalDest(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.NormalDest(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.NormalDest(background, source, amount); } @@ -1126,17 +850,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.MultiplyDest(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.MultiplyDest(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.MultiplyDest(background, source, amount); } @@ -1150,17 +868,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.AddDest(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.AddDest(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.AddDest(background, source, amount); } @@ -1174,17 +886,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.SubtractDest(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.SubtractDest(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.SubtractDest(background, source, amount); } @@ -1198,17 +904,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.ScreenDest(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.ScreenDest(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.ScreenDest(background, source, amount); } @@ -1222,17 +922,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.DarkenDest(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.DarkenDest(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.DarkenDest(background, source, amount); } @@ -1246,17 +940,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.LightenDest(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.LightenDest(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.LightenDest(background, source, amount); } @@ -1270,17 +958,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.OverlayDest(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.OverlayDest(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.OverlayDest(background, source, amount); } @@ -1294,17 +976,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.HardLightDest(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.HardLightDest(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.HardLightDest(background, source, amount); } @@ -1318,17 +994,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.NormalDestAtop(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.NormalDestAtop(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.NormalDestAtop(background, source, amount); } @@ -1342,17 +1012,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.MultiplyDestAtop(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.MultiplyDestAtop(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.MultiplyDestAtop(background, source, amount); } @@ -1366,17 +1030,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.AddDestAtop(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.AddDestAtop(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.AddDestAtop(background, source, amount); } @@ -1390,17 +1048,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.SubtractDestAtop(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.SubtractDestAtop(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.SubtractDestAtop(background, source, amount); } @@ -1414,17 +1066,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.ScreenDestAtop(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.ScreenDestAtop(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.ScreenDestAtop(background, source, amount); } @@ -1438,17 +1084,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.DarkenDestAtop(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.DarkenDestAtop(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.DarkenDestAtop(background, source, amount); } @@ -1462,17 +1102,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.LightenDestAtop(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.LightenDestAtop(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.LightenDestAtop(background, source, amount); } @@ -1486,17 +1120,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.OverlayDestAtop(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.OverlayDestAtop(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.OverlayDestAtop(background, source, amount); } @@ -1510,17 +1138,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.HardLightDestAtop(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.HardLightDestAtop(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.HardLightDestAtop(background, source, amount); } @@ -1534,17 +1156,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.NormalDestOver(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.NormalDestOver(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.NormalDestOver(background, source, amount); } @@ -1558,17 +1174,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.MultiplyDestOver(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.MultiplyDestOver(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.MultiplyDestOver(background, source, amount); } @@ -1582,17 +1192,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.AddDestOver(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.AddDestOver(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.AddDestOver(background, source, amount); } @@ -1606,17 +1210,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.SubtractDestOver(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.SubtractDestOver(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.SubtractDestOver(background, source, amount); } @@ -1630,17 +1228,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.ScreenDestOver(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.ScreenDestOver(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.ScreenDestOver(background, source, amount); } @@ -1654,17 +1246,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.DarkenDestOver(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.DarkenDestOver(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.DarkenDestOver(background, source, amount); } @@ -1678,17 +1264,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.LightenDestOver(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.LightenDestOver(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.LightenDestOver(background, source, amount); } @@ -1702,17 +1282,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.OverlayDestOver(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.OverlayDestOver(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.OverlayDestOver(background, source, amount); } @@ -1726,17 +1300,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.HardLightDestOver(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.HardLightDestOver(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.HardLightDestOver(background, source, amount); } @@ -1750,17 +1318,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.NormalDestIn(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.NormalDestIn(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.NormalDestIn(background, source, amount); } @@ -1774,17 +1336,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.MultiplyDestIn(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.MultiplyDestIn(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.MultiplyDestIn(background, source, amount); } @@ -1798,17 +1354,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.AddDestIn(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.AddDestIn(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.AddDestIn(background, source, amount); } @@ -1822,17 +1372,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.SubtractDestIn(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.SubtractDestIn(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.SubtractDestIn(background, source, amount); } @@ -1846,17 +1390,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.ScreenDestIn(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.ScreenDestIn(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.ScreenDestIn(background, source, amount); } @@ -1870,17 +1408,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.DarkenDestIn(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.DarkenDestIn(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.DarkenDestIn(background, source, amount); } @@ -1894,17 +1426,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.LightenDestIn(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.LightenDestIn(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.LightenDestIn(background, source, amount); } @@ -1918,17 +1444,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.OverlayDestIn(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.OverlayDestIn(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.OverlayDestIn(background, source, amount); } @@ -1942,17 +1462,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.HardLightDestIn(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.HardLightDestIn(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.HardLightDestIn(background, source, amount); } @@ -1966,17 +1480,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.NormalDestOut(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.NormalDestOut(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.NormalDestOut(background, source, amount); } @@ -1990,17 +1498,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.MultiplyDestOut(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.MultiplyDestOut(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.MultiplyDestOut(background, source, amount); } @@ -2014,17 +1516,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.AddDestOut(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.AddDestOut(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.AddDestOut(background, source, amount); } @@ -2038,17 +1534,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.SubtractDestOut(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.SubtractDestOut(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.SubtractDestOut(background, source, amount); } @@ -2062,17 +1552,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.ScreenDestOut(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.ScreenDestOut(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.ScreenDestOut(background, source, amount); } @@ -2086,17 +1570,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.DarkenDestOut(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.DarkenDestOut(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.DarkenDestOut(background, source, amount); } @@ -2110,17 +1588,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.LightenDestOut(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.LightenDestOut(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.LightenDestOut(background, source, amount); } @@ -2134,17 +1606,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.OverlayDestOut(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.OverlayDestOut(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.OverlayDestOut(background, source, amount); } @@ -2158,17 +1624,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.HardLightDestOut(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.HardLightDestOut(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.HardLightDestOut(background, source, amount); } @@ -2182,17 +1642,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.NormalClear(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.NormalClear(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.NormalClear(background, source, amount); } @@ -2206,17 +1660,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.MultiplyClear(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.MultiplyClear(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.MultiplyClear(background, source, amount); } @@ -2230,17 +1678,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.AddClear(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.AddClear(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.AddClear(background, source, amount); } @@ -2254,17 +1696,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.SubtractClear(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.SubtractClear(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.SubtractClear(background, source, amount); } @@ -2278,17 +1714,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.ScreenClear(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.ScreenClear(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.ScreenClear(background, source, amount); } @@ -2302,17 +1732,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.DarkenClear(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.DarkenClear(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.DarkenClear(background, source, amount); } @@ -2326,17 +1750,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.LightenClear(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.LightenClear(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.LightenClear(background, source, amount); } @@ -2350,17 +1768,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.OverlayClear(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.OverlayClear(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.OverlayClear(background, source, amount); } @@ -2374,17 +1786,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.HardLightClear(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.HardLightClear(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.HardLightClear(background, source, amount); } @@ -2398,17 +1804,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.NormalXor(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.NormalXor(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.NormalXor(background, source, amount); } @@ -2422,17 +1822,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.MultiplyXor(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.MultiplyXor(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.MultiplyXor(background, source, amount); } @@ -2446,17 +1840,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.AddXor(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.AddXor(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.AddXor(background, source, amount); } @@ -2470,17 +1858,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.SubtractXor(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.SubtractXor(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.SubtractXor(background, source, amount); } @@ -2494,17 +1876,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.ScreenXor(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.ScreenXor(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.ScreenXor(background, source, amount); } @@ -2518,17 +1894,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.DarkenXor(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.DarkenXor(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.DarkenXor(background, source, amount); } @@ -2542,17 +1912,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.LightenXor(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.LightenXor(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.LightenXor(background, source, amount); } @@ -2566,17 +1930,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.OverlayXor(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.OverlayXor(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.OverlayXor(background, source, amount); } @@ -2590,17 +1948,11 @@ internal static class DefaultPixelBlenderOperators => PorterDuffFunctions.HardLightXor(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.HardLightXor(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.HardLightXor(background, source, amount); } diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt index 99610b7d8..ae0e0700d 100644 --- a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt @@ -66,17 +66,11 @@ foreach (var composer in composers) => PorterDuffFunctions.<#= blenderComposer #>(background, source, amount); /// - public static Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount) + public static Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount) => PorterDuffFunctions.<#= blenderComposer #>(background, source, amount); /// - public static Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount) + public static Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount) => PorterDuffFunctions.<#= blenderComposer #>(background, source, amount); } diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/IPixelBlenderOperator.cs b/src/ImageSharp/PixelFormats/PixelBlenders/IPixelBlenderOperator.cs index 902ba9e25..10b588666 100644 --- a/src/ImageSharp/PixelFormats/PixelBlenders/IPixelBlenderOperator.cs +++ b/src/ImageSharp/PixelFormats/PixelBlenders/IPixelBlenderOperator.cs @@ -27,10 +27,7 @@ internal interface IPixelBlenderOperator /// The source RGBA lanes. /// The source opacity repeated across each pixel's four lanes. /// The blended RGBA lanes. - public static abstract Vector256 Invoke( - Vector256 background, - Vector256 source, - Vector256 amount); + public static abstract Vector256 Invoke(Vector256 background, Vector256 source, Vector256 amount); /// /// Blends four pixels represented by four consecutive groups of four RGBA lanes. @@ -39,8 +36,5 @@ internal interface IPixelBlenderOperator /// The source RGBA lanes. /// The source opacity repeated across each pixel's four lanes. /// The blended RGBA lanes. - public static abstract Vector512 Invoke( - Vector512 background, - Vector512 source, - Vector512 amount); + public static abstract Vector512 Invoke(Vector512 background, Vector512 source, Vector512 amount); } diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/PixelBlender{TPixel,TOperator}.cs b/src/ImageSharp/PixelFormats/PixelBlenders/PixelBlender{TPixel,TOperator}.cs index f50151256..17282e388 100644 --- a/src/ImageSharp/PixelFormats/PixelBlenders/PixelBlender{TPixel,TOperator}.cs +++ b/src/ImageSharp/PixelFormats/PixelBlenders/PixelBlender{TPixel,TOperator}.cs @@ -5,7 +5,6 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.X86; namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders; @@ -19,11 +18,7 @@ internal abstract class PixelBlender : PixelBlender where TOperator : struct, IPixelBlenderOperator { /// - protected sealed override void BlendFunction( - Span destination, - ReadOnlySpan background, - ReadOnlySpan source, - float amount) + protected sealed override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { // Public entry points validate the row lengths, so all three references can advance in lockstep. int scalarStart = 0; @@ -33,7 +28,7 @@ internal abstract class PixelBlender : PixelBlender ref Vector4 backgroundRef = ref MemoryMarshal.GetReference(background); ref Vector4 sourceRef = ref MemoryMarshal.GetReference(source); - if (Avx512F.IsSupported && destination.Length >= 4) + if (Vector512.IsHardwareAccelerated && destination.Length >= 4) { // A 512-bit register holds four complete RGBA pixels in [R,G,B,A] groups. ref Vector512 destinationBase = ref Unsafe.As>(ref destinationRef); @@ -44,15 +39,12 @@ internal abstract class PixelBlender : PixelBlender for (nuint i = 0; i < (uint)vectorCount; i++) { - Unsafe.Add(ref destinationBase, i) = TOperator.Invoke( - Unsafe.Add(ref backgroundBase, i), - Unsafe.Add(ref sourceBase, i), - amountVector); + Unsafe.Add(ref destinationBase, i) = TOperator.Invoke(Unsafe.Add(ref backgroundBase, i), Unsafe.Add(ref sourceBase, i), amountVector); } scalarStart = vectorCount * 4; } - else if (Avx2.IsSupported && destination.Length >= 2) + else if (Vector256.IsHardwareAccelerated && destination.Length >= 2) { // A 256-bit register holds two complete RGBA pixels in [R,G,B,A] groups. ref Vector256 destinationBase = ref Unsafe.As>(ref destinationRef); @@ -63,10 +55,7 @@ internal abstract class PixelBlender : PixelBlender for (nuint i = 0; i < (uint)vectorCount; i++) { - Unsafe.Add(ref destinationBase, i) = TOperator.Invoke( - Unsafe.Add(ref backgroundBase, i), - Unsafe.Add(ref sourceBase, i), - amountVector); + Unsafe.Add(ref destinationBase, i) = TOperator.Invoke(Unsafe.Add(ref backgroundBase, i), Unsafe.Add(ref sourceBase, i), amountVector); } scalarStart = vectorCount * 2; @@ -75,19 +64,12 @@ internal abstract class PixelBlender : PixelBlender // Vector4 is both the scalar pixel representation and the portable SIMD fallback. for (int i = scalarStart; i < destination.Length; i++) { - Unsafe.Add(ref destinationRef, (uint)i) = TOperator.Invoke( - Unsafe.Add(ref backgroundRef, (uint)i), - Unsafe.Add(ref sourceRef, (uint)i), - amount); + Unsafe.Add(ref destinationRef, (uint)i) = TOperator.Invoke(Unsafe.Add(ref backgroundRef, (uint)i), Unsafe.Add(ref sourceRef, (uint)i), amount); } } /// - protected sealed override void BlendFunction( - Span destination, - ReadOnlySpan background, - Vector4 source, - float amount) + protected sealed override void BlendFunction(Span destination, ReadOnlySpan background, Vector4 source, float amount) { // Public entry points validate the row lengths, so the destination and background advance together. int scalarStart = 0; @@ -96,7 +78,7 @@ internal abstract class PixelBlender : PixelBlender ref Vector4 destinationRef = ref MemoryMarshal.GetReference(destination); ref Vector4 backgroundRef = ref MemoryMarshal.GetReference(background); - if (Avx512F.IsSupported && destination.Length >= 4) + if (Vector512.IsHardwareAccelerated && destination.Length >= 4) { // Repeat one [R,G,B,A] source group four times to match the four background pixels. ref Vector512 destinationBase = ref Unsafe.As>(ref destinationRef); @@ -107,15 +89,12 @@ internal abstract class PixelBlender : PixelBlender for (nuint i = 0; i < (uint)vectorCount; i++) { - Unsafe.Add(ref destinationBase, i) = TOperator.Invoke( - Unsafe.Add(ref backgroundBase, i), - sourceVector, - amountVector); + Unsafe.Add(ref destinationBase, i) = TOperator.Invoke(Unsafe.Add(ref backgroundBase, i), sourceVector, amountVector); } scalarStart = vectorCount * 4; } - else if (Avx2.IsSupported && destination.Length >= 2) + else if (Vector256.IsHardwareAccelerated && destination.Length >= 2) { // Repeat one [R,G,B,A] source group twice to match the two background pixels. ref Vector256 destinationBase = ref Unsafe.As>(ref destinationRef); @@ -126,10 +105,7 @@ internal abstract class PixelBlender : PixelBlender for (nuint i = 0; i < (uint)vectorCount; i++) { - Unsafe.Add(ref destinationBase, i) = TOperator.Invoke( - Unsafe.Add(ref backgroundBase, i), - sourceVector, - amountVector); + Unsafe.Add(ref destinationBase, i) = TOperator.Invoke(Unsafe.Add(ref backgroundBase, i), sourceVector, amountVector); } scalarStart = vectorCount * 2; @@ -138,19 +114,12 @@ internal abstract class PixelBlender : PixelBlender // The remaining pixel count is at most three after AVX-512 or one after AVX2. for (int i = scalarStart; i < destination.Length; i++) { - Unsafe.Add(ref destinationRef, (uint)i) = TOperator.Invoke( - Unsafe.Add(ref backgroundRef, (uint)i), - source, - amount); + Unsafe.Add(ref destinationRef, (uint)i) = TOperator.Invoke(Unsafe.Add(ref backgroundRef, (uint)i), source, amount); } } /// - protected sealed override void BlendFunction( - Span destination, - ReadOnlySpan background, - ReadOnlySpan source, - ReadOnlySpan amount) + protected sealed override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) { // Each amount belongs to one pixel and must be repeated across that pixel's four RGBA lanes. int scalarStart = 0; @@ -160,7 +129,7 @@ internal abstract class PixelBlender : PixelBlender ref Vector4 sourceRef = ref MemoryMarshal.GetReference(source); ref float amountRef = ref MemoryMarshal.GetReference(amount); - if (Avx512F.IsSupported && destination.Length >= 4) + if (Vector512.IsHardwareAccelerated && destination.Length >= 4) { ref Vector512 destinationBase = ref Unsafe.As>(ref destinationRef); ref Vector512 backgroundBase = ref Unsafe.As>(ref backgroundRef); @@ -173,15 +142,12 @@ internal abstract class PixelBlender : PixelBlender ref float amountBase = ref Unsafe.Add(ref amountRef, i * 4); Vector512 amountVector = CreateClampedVector512(ref amountBase); - Unsafe.Add(ref destinationBase, i) = TOperator.Invoke( - Unsafe.Add(ref backgroundBase, i), - Unsafe.Add(ref sourceBase, i), - amountVector); + Unsafe.Add(ref destinationBase, i) = TOperator.Invoke(Unsafe.Add(ref backgroundBase, i), Unsafe.Add(ref sourceBase, i), amountVector); } scalarStart = vectorCount * 4; } - else if (Avx2.IsSupported && destination.Length >= 2) + else if (Vector256.IsHardwareAccelerated && destination.Length >= 2) { ref Vector256 destinationBase = ref Unsafe.As>(ref destinationRef); ref Vector256 backgroundBase = ref Unsafe.As>(ref backgroundRef); @@ -194,10 +160,7 @@ internal abstract class PixelBlender : PixelBlender ref float amountBase = ref Unsafe.Add(ref amountRef, i * 2); Vector256 amountVector = CreateClampedVector256(ref amountBase); - Unsafe.Add(ref destinationBase, i) = TOperator.Invoke( - Unsafe.Add(ref backgroundBase, i), - Unsafe.Add(ref sourceBase, i), - amountVector); + Unsafe.Add(ref destinationBase, i) = TOperator.Invoke(Unsafe.Add(ref backgroundBase, i), Unsafe.Add(ref sourceBase, i), amountVector); } scalarStart = vectorCount * 2; @@ -205,19 +168,12 @@ internal abstract class PixelBlender : PixelBlender for (int i = scalarStart; i < destination.Length; i++) { - Unsafe.Add(ref destinationRef, (uint)i) = TOperator.Invoke( - Unsafe.Add(ref backgroundRef, (uint)i), - Unsafe.Add(ref sourceRef, (uint)i), - Numerics.Clamp(Unsafe.Add(ref amountRef, (uint)i), 0, 1F)); + Unsafe.Add(ref destinationRef, (uint)i) = TOperator.Invoke(Unsafe.Add(ref backgroundRef, (uint)i), Unsafe.Add(ref sourceRef, (uint)i), Numerics.Clamp(Unsafe.Add(ref amountRef, (uint)i), 0, 1F)); } } /// - protected sealed override void BlendFunction( - Span destination, - ReadOnlySpan background, - Vector4 source, - ReadOnlySpan amount) + protected sealed override void BlendFunction(Span destination, ReadOnlySpan background, Vector4 source, ReadOnlySpan amount) { // The source is invariant, while each background pixel has its own independently clamped amount. int scalarStart = 0; @@ -226,7 +182,7 @@ internal abstract class PixelBlender : PixelBlender ref Vector4 backgroundRef = ref MemoryMarshal.GetReference(background); ref float amountRef = ref MemoryMarshal.GetReference(amount); - if (Avx512F.IsSupported && destination.Length >= 4) + if (Vector512.IsHardwareAccelerated && destination.Length >= 4) { ref Vector512 destinationBase = ref Unsafe.As>(ref destinationRef); ref Vector512 backgroundBase = ref Unsafe.As>(ref backgroundRef); @@ -238,15 +194,12 @@ internal abstract class PixelBlender : PixelBlender ref float amountBase = ref Unsafe.Add(ref amountRef, i * 4); Vector512 amountVector = CreateClampedVector512(ref amountBase); - Unsafe.Add(ref destinationBase, i) = TOperator.Invoke( - Unsafe.Add(ref backgroundBase, i), - sourceVector, - amountVector); + Unsafe.Add(ref destinationBase, i) = TOperator.Invoke(Unsafe.Add(ref backgroundBase, i), sourceVector, amountVector); } scalarStart = vectorCount * 4; } - else if (Avx2.IsSupported && destination.Length >= 2) + else if (Vector256.IsHardwareAccelerated && destination.Length >= 2) { ref Vector256 destinationBase = ref Unsafe.As>(ref destinationRef); ref Vector256 backgroundBase = ref Unsafe.As>(ref backgroundRef); @@ -258,10 +211,7 @@ internal abstract class PixelBlender : PixelBlender ref float amountBase = ref Unsafe.Add(ref amountRef, i * 2); Vector256 amountVector = CreateClampedVector256(ref amountBase); - Unsafe.Add(ref destinationBase, i) = TOperator.Invoke( - Unsafe.Add(ref backgroundBase, i), - sourceVector, - amountVector); + Unsafe.Add(ref destinationBase, i) = TOperator.Invoke(Unsafe.Add(ref backgroundBase, i), sourceVector, amountVector); } scalarStart = vectorCount * 2; @@ -269,20 +219,12 @@ internal abstract class PixelBlender : PixelBlender for (int i = scalarStart; i < destination.Length; i++) { - Unsafe.Add(ref destinationRef, (uint)i) = TOperator.Invoke( - Unsafe.Add(ref backgroundRef, (uint)i), - source, - Numerics.Clamp(Unsafe.Add(ref amountRef, (uint)i), 0, 1F)); + Unsafe.Add(ref destinationRef, (uint)i) = TOperator.Invoke(Unsafe.Add(ref backgroundRef, (uint)i), source, Numerics.Clamp(Unsafe.Add(ref amountRef, (uint)i), 0, 1F)); } } /// - protected sealed override void BlendWithCoverageFunction( - Span destination, - ReadOnlySpan background, - ReadOnlySpan source, - float amount, - ReadOnlySpan coverage) + protected sealed override void BlendWithCoverageFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount, ReadOnlySpan coverage) { // Coverage mixes the composed result back toward the original background, so it is fused into this pass. int scalarStart = 0; @@ -293,7 +235,7 @@ internal abstract class PixelBlender : PixelBlender ref Vector4 sourceRef = ref MemoryMarshal.GetReference(source); ref float coverageRef = ref MemoryMarshal.GetReference(coverage); - if (Avx512F.IsSupported && destination.Length >= 4) + if (Vector512.IsHardwareAccelerated && destination.Length >= 4) { ref Vector512 destinationBase = ref Unsafe.As>(ref destinationRef); ref Vector512 backgroundBase = ref Unsafe.As>(ref backgroundRef); @@ -306,20 +248,14 @@ internal abstract class PixelBlender : PixelBlender ref Vector512 backgroundVector = ref Unsafe.Add(ref backgroundBase, i); ref float coverageBase = ref Unsafe.Add(ref coverageRef, i * 4); Vector512 coverageVector = CreateClampedVector512(ref coverageBase); - Vector512 blended = TOperator.Invoke( - backgroundVector, - Unsafe.Add(ref sourceBase, i), - amountVector); - - Unsafe.Add(ref destinationBase, i) = PorterDuffFunctions.BlendWithCoverage( - backgroundVector, - blended, - coverageVector); + Vector512 blended = TOperator.Invoke(backgroundVector, Unsafe.Add(ref sourceBase, i), amountVector); + + Unsafe.Add(ref destinationBase, i) = PorterDuffFunctions.BlendWithCoverage(backgroundVector, blended, coverageVector); } scalarStart = vectorCount * 4; } - else if (Avx2.IsSupported && destination.Length >= 2) + else if (Vector256.IsHardwareAccelerated && destination.Length >= 2) { ref Vector256 destinationBase = ref Unsafe.As>(ref destinationRef); ref Vector256 backgroundBase = ref Unsafe.As>(ref backgroundRef); @@ -332,15 +268,9 @@ internal abstract class PixelBlender : PixelBlender ref Vector256 backgroundVector = ref Unsafe.Add(ref backgroundBase, i); ref float coverageBase = ref Unsafe.Add(ref coverageRef, i * 2); Vector256 coverageVector = CreateClampedVector256(ref coverageBase); - Vector256 blended = TOperator.Invoke( - backgroundVector, - Unsafe.Add(ref sourceBase, i), - amountVector); - - Unsafe.Add(ref destinationBase, i) = PorterDuffFunctions.BlendWithCoverage( - backgroundVector, - blended, - coverageVector); + Vector256 blended = TOperator.Invoke(backgroundVector, Unsafe.Add(ref sourceBase, i), amountVector); + + Unsafe.Add(ref destinationBase, i) = PorterDuffFunctions.BlendWithCoverage(backgroundVector, blended, coverageVector); } scalarStart = vectorCount * 2; @@ -349,25 +279,14 @@ internal abstract class PixelBlender : PixelBlender for (int i = scalarStart; i < destination.Length; i++) { Vector4 backgroundPixel = Unsafe.Add(ref backgroundRef, (uint)i); - Vector4 blended = TOperator.Invoke( - backgroundPixel, - Unsafe.Add(ref sourceRef, (uint)i), - amount); - - Unsafe.Add(ref destinationRef, (uint)i) = PorterDuffFunctions.BlendWithCoverage( - backgroundPixel, - blended, - Numerics.Clamp(Unsafe.Add(ref coverageRef, (uint)i), 0, 1F)); + Vector4 blended = TOperator.Invoke(backgroundPixel, Unsafe.Add(ref sourceRef, (uint)i), amount); + + Unsafe.Add(ref destinationRef, (uint)i) = PorterDuffFunctions.BlendWithCoverage(backgroundPixel, blended, Numerics.Clamp(Unsafe.Add(ref coverageRef, (uint)i), 0, 1F)); } } /// - protected sealed override void BlendWithCoverageFunction( - Span destination, - ReadOnlySpan background, - Vector4 source, - float amount, - ReadOnlySpan coverage) + protected sealed override void BlendWithCoverageFunction(Span destination, ReadOnlySpan background, Vector4 source, float amount, ReadOnlySpan coverage) { // The constant source is expanded once per selected width and reused for the complete row. int scalarStart = 0; @@ -377,7 +296,7 @@ internal abstract class PixelBlender : PixelBlender ref Vector4 backgroundRef = ref MemoryMarshal.GetReference(background); ref float coverageRef = ref MemoryMarshal.GetReference(coverage); - if (Avx512F.IsSupported && destination.Length >= 4) + if (Vector512.IsHardwareAccelerated && destination.Length >= 4) { ref Vector512 destinationBase = ref Unsafe.As>(ref destinationRef); ref Vector512 backgroundBase = ref Unsafe.As>(ref backgroundRef); @@ -392,15 +311,12 @@ internal abstract class PixelBlender : PixelBlender Vector512 coverageVector = CreateClampedVector512(ref coverageBase); Vector512 blended = TOperator.Invoke(backgroundVector, sourceVector, amountVector); - Unsafe.Add(ref destinationBase, i) = PorterDuffFunctions.BlendWithCoverage( - backgroundVector, - blended, - coverageVector); + Unsafe.Add(ref destinationBase, i) = PorterDuffFunctions.BlendWithCoverage(backgroundVector, blended, coverageVector); } scalarStart = vectorCount * 4; } - else if (Avx2.IsSupported && destination.Length >= 2) + else if (Vector256.IsHardwareAccelerated && destination.Length >= 2) { ref Vector256 destinationBase = ref Unsafe.As>(ref destinationRef); ref Vector256 backgroundBase = ref Unsafe.As>(ref backgroundRef); @@ -415,10 +331,7 @@ internal abstract class PixelBlender : PixelBlender Vector256 coverageVector = CreateClampedVector256(ref coverageBase); Vector256 blended = TOperator.Invoke(backgroundVector, sourceVector, amountVector); - Unsafe.Add(ref destinationBase, i) = PorterDuffFunctions.BlendWithCoverage( - backgroundVector, - blended, - coverageVector); + Unsafe.Add(ref destinationBase, i) = PorterDuffFunctions.BlendWithCoverage(backgroundVector, blended, coverageVector); } scalarStart = vectorCount * 2; @@ -429,20 +342,12 @@ internal abstract class PixelBlender : PixelBlender Vector4 backgroundPixel = Unsafe.Add(ref backgroundRef, (uint)i); Vector4 blended = TOperator.Invoke(backgroundPixel, source, amount); - Unsafe.Add(ref destinationRef, (uint)i) = PorterDuffFunctions.BlendWithCoverage( - backgroundPixel, - blended, - Numerics.Clamp(Unsafe.Add(ref coverageRef, (uint)i), 0, 1F)); + Unsafe.Add(ref destinationRef, (uint)i) = PorterDuffFunctions.BlendWithCoverage(backgroundPixel, blended, Numerics.Clamp(Unsafe.Add(ref coverageRef, (uint)i), 0, 1F)); } } /// - protected sealed override void BlendWithCoverageFunction( - Span destination, - ReadOnlySpan background, - ReadOnlySpan source, - ReadOnlySpan amount, - ReadOnlySpan coverage) + protected sealed override void BlendWithCoverageFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount, ReadOnlySpan coverage) { // Amount controls composition while coverage controls the final mix with the untouched background. int scalarStart = 0; @@ -453,7 +358,7 @@ internal abstract class PixelBlender : PixelBlender ref float amountRef = ref MemoryMarshal.GetReference(amount); ref float coverageRef = ref MemoryMarshal.GetReference(coverage); - if (Avx512F.IsSupported && destination.Length >= 4) + if (Vector512.IsHardwareAccelerated && destination.Length >= 4) { ref Vector512 destinationBase = ref Unsafe.As>(ref destinationRef); ref Vector512 backgroundBase = ref Unsafe.As>(ref backgroundRef); @@ -467,20 +372,14 @@ internal abstract class PixelBlender : PixelBlender ref float coverageBase = ref Unsafe.Add(ref coverageRef, i * 4); Vector512 amountVector = CreateClampedVector512(ref amountBase); Vector512 coverageVector = CreateClampedVector512(ref coverageBase); - Vector512 blended = TOperator.Invoke( - backgroundVector, - Unsafe.Add(ref sourceBase, i), - amountVector); - - Unsafe.Add(ref destinationBase, i) = PorterDuffFunctions.BlendWithCoverage( - backgroundVector, - blended, - coverageVector); + Vector512 blended = TOperator.Invoke(backgroundVector, Unsafe.Add(ref sourceBase, i), amountVector); + + Unsafe.Add(ref destinationBase, i) = PorterDuffFunctions.BlendWithCoverage(backgroundVector, blended, coverageVector); } scalarStart = vectorCount * 4; } - else if (Avx2.IsSupported && destination.Length >= 2) + else if (Vector256.IsHardwareAccelerated && destination.Length >= 2) { ref Vector256 destinationBase = ref Unsafe.As>(ref destinationRef); ref Vector256 backgroundBase = ref Unsafe.As>(ref backgroundRef); @@ -494,15 +393,9 @@ internal abstract class PixelBlender : PixelBlender ref float coverageBase = ref Unsafe.Add(ref coverageRef, i * 2); Vector256 amountVector = CreateClampedVector256(ref amountBase); Vector256 coverageVector = CreateClampedVector256(ref coverageBase); - Vector256 blended = TOperator.Invoke( - backgroundVector, - Unsafe.Add(ref sourceBase, i), - amountVector); - - Unsafe.Add(ref destinationBase, i) = PorterDuffFunctions.BlendWithCoverage( - backgroundVector, - blended, - coverageVector); + Vector256 blended = TOperator.Invoke(backgroundVector, Unsafe.Add(ref sourceBase, i), amountVector); + + Unsafe.Add(ref destinationBase, i) = PorterDuffFunctions.BlendWithCoverage(backgroundVector, blended, coverageVector); } scalarStart = vectorCount * 2; @@ -511,25 +404,14 @@ internal abstract class PixelBlender : PixelBlender for (int i = scalarStart; i < destination.Length; i++) { Vector4 backgroundPixel = Unsafe.Add(ref backgroundRef, (uint)i); - Vector4 blended = TOperator.Invoke( - backgroundPixel, - Unsafe.Add(ref sourceRef, (uint)i), - Numerics.Clamp(Unsafe.Add(ref amountRef, (uint)i), 0, 1F)); - - Unsafe.Add(ref destinationRef, (uint)i) = PorterDuffFunctions.BlendWithCoverage( - backgroundPixel, - blended, - Numerics.Clamp(Unsafe.Add(ref coverageRef, (uint)i), 0, 1F)); + Vector4 blended = TOperator.Invoke(backgroundPixel, Unsafe.Add(ref sourceRef, (uint)i), Numerics.Clamp(Unsafe.Add(ref amountRef, (uint)i), 0, 1F)); + + Unsafe.Add(ref destinationRef, (uint)i) = PorterDuffFunctions.BlendWithCoverage(backgroundPixel, blended, Numerics.Clamp(Unsafe.Add(ref coverageRef, (uint)i), 0, 1F)); } } /// - protected sealed override void BlendWithCoverageFunction( - Span destination, - ReadOnlySpan background, - Vector4 source, - ReadOnlySpan amount, - ReadOnlySpan coverage) + protected sealed override void BlendWithCoverageFunction(Span destination, ReadOnlySpan background, Vector4 source, ReadOnlySpan amount, ReadOnlySpan coverage) { // The invariant source is expanded once; only amount and coverage are gathered for each vector batch. int scalarStart = 0; @@ -539,7 +421,7 @@ internal abstract class PixelBlender : PixelBlender ref float amountRef = ref MemoryMarshal.GetReference(amount); ref float coverageRef = ref MemoryMarshal.GetReference(coverage); - if (Avx512F.IsSupported && destination.Length >= 4) + if (Vector512.IsHardwareAccelerated && destination.Length >= 4) { ref Vector512 destinationBase = ref Unsafe.As>(ref destinationRef); ref Vector512 backgroundBase = ref Unsafe.As>(ref backgroundRef); @@ -555,15 +437,12 @@ internal abstract class PixelBlender : PixelBlender Vector512 coverageVector = CreateClampedVector512(ref coverageBase); Vector512 blended = TOperator.Invoke(backgroundVector, sourceVector, amountVector); - Unsafe.Add(ref destinationBase, i) = PorterDuffFunctions.BlendWithCoverage( - backgroundVector, - blended, - coverageVector); + Unsafe.Add(ref destinationBase, i) = PorterDuffFunctions.BlendWithCoverage(backgroundVector, blended, coverageVector); } scalarStart = vectorCount * 4; } - else if (Avx2.IsSupported && destination.Length >= 2) + else if (Vector256.IsHardwareAccelerated && destination.Length >= 2) { ref Vector256 destinationBase = ref Unsafe.As>(ref destinationRef); ref Vector256 backgroundBase = ref Unsafe.As>(ref backgroundRef); @@ -579,10 +458,7 @@ internal abstract class PixelBlender : PixelBlender Vector256 coverageVector = CreateClampedVector256(ref coverageBase); Vector256 blended = TOperator.Invoke(backgroundVector, sourceVector, amountVector); - Unsafe.Add(ref destinationBase, i) = PorterDuffFunctions.BlendWithCoverage( - backgroundVector, - blended, - coverageVector); + Unsafe.Add(ref destinationBase, i) = PorterDuffFunctions.BlendWithCoverage(backgroundVector, blended, coverageVector); } scalarStart = vectorCount * 2; @@ -591,15 +467,9 @@ internal abstract class PixelBlender : PixelBlender for (int i = scalarStart; i < destination.Length; i++) { Vector4 backgroundPixel = Unsafe.Add(ref backgroundRef, (uint)i); - Vector4 blended = TOperator.Invoke( - backgroundPixel, - source, - Numerics.Clamp(Unsafe.Add(ref amountRef, (uint)i), 0, 1F)); - - Unsafe.Add(ref destinationRef, (uint)i) = PorterDuffFunctions.BlendWithCoverage( - backgroundPixel, - blended, - Numerics.Clamp(Unsafe.Add(ref coverageRef, (uint)i), 0, 1F)); + Vector4 blended = TOperator.Invoke(backgroundPixel, source, Numerics.Clamp(Unsafe.Add(ref amountRef, (uint)i), 0, 1F)); + + Unsafe.Add(ref destinationRef, (uint)i) = PorterDuffFunctions.BlendWithCoverage(backgroundPixel, blended, Numerics.Clamp(Unsafe.Add(ref coverageRef, (uint)i), 0, 1F)); } } @@ -619,23 +489,7 @@ internal abstract class PixelBlender : PixelBlender /// Four consecutive copies of the pixel. [MethodImpl(MethodImplOptions.AggressiveInlining)] private static Vector512 CreateVector512(Vector4 pixel) - => Vector512.Create( - pixel.X, - pixel.Y, - pixel.Z, - pixel.W, - pixel.X, - pixel.Y, - pixel.Z, - pixel.W, - pixel.X, - pixel.Y, - pixel.Z, - pixel.W, - pixel.X, - pixel.Y, - pixel.Z, - pixel.W); + => Vector512.Create(pixel.X, pixel.Y, pixel.Z, pixel.W, pixel.X, pixel.Y, pixel.Z, pixel.W, pixel.X, pixel.Y, pixel.Z, pixel.W, pixel.X, pixel.Y, pixel.Z, pixel.W); /// /// Expands and clamps two per-pixel scalar values for two packed RGBA pixels. @@ -645,12 +499,10 @@ internal abstract class PixelBlender : PixelBlender [MethodImpl(MethodImplOptions.AggressiveInlining)] private static Vector256 CreateClampedVector256(ref float values) { - Vector256 result = Vector256.Create( - Vector128.Create(values), - Vector128.Create(Unsafe.Add(ref values, 1))); + Vector256 result = Vector256.Create(Vector128.Create(values), Vector128.Create(Unsafe.Add(ref values, 1))); // Amount and coverage share the same public 0..1 contract and therefore the same packed clamp. - return Avx.Min(Avx.Max(Vector256.Zero, result), Vector256.Create(1F)); + return Vector256.Min(Vector256.Max(Vector256.Zero, result), Vector256.Create(1F)); } /// @@ -661,24 +513,9 @@ internal abstract class PixelBlender : PixelBlender [MethodImpl(MethodImplOptions.AggressiveInlining)] private static Vector512 CreateClampedVector512(ref float values) { - Vector512 result = Vector512.Create( - values, - values, - values, - values, - Unsafe.Add(ref values, 1), - Unsafe.Add(ref values, 1), - Unsafe.Add(ref values, 1), - Unsafe.Add(ref values, 1), - Unsafe.Add(ref values, 2), - Unsafe.Add(ref values, 2), - Unsafe.Add(ref values, 2), - Unsafe.Add(ref values, 2), - Unsafe.Add(ref values, 3), - Unsafe.Add(ref values, 3), - Unsafe.Add(ref values, 3), - Unsafe.Add(ref values, 3)); + Vector512 result = Vector512.Create(values, values, values, values, Unsafe.Add(ref values, 1), Unsafe.Add(ref values, 1), Unsafe.Add(ref values, 1), Unsafe.Add(ref values, 1), Unsafe.Add(ref values, 2), Unsafe.Add(ref values, 2), Unsafe.Add(ref values, 2), Unsafe.Add(ref values, 2), Unsafe.Add(ref values, 3), Unsafe.Add(ref values, 3), Unsafe.Add(ref values, 3), Unsafe.Add(ref values, 3)); + // Amount and coverage share the same public 0..1 contract and therefore the same packed clamp. return Vector512.Min(Vector512.Max(Vector512.Zero, result), Vector512.Create(1F)); } } @@ -696,10 +533,7 @@ internal abstract class DefaultPixelBlender : PixelBlender vector = ref Unsafe.As>( - ref Unsafe.Add(ref vectorBase, (uint)index)); + ref Vector512 vector = ref Unsafe.As>(ref Unsafe.Add(ref vectorBase, (uint)index)); vector = transform.Invoke(vector); } @@ -66,8 +65,7 @@ internal static partial class Vector4Converters for (; index <= oneRegisterFromEnd; index += vectorsPerRegister) { - ref Vector256 vector = ref Unsafe.As>( - ref Unsafe.Add(ref vectorBase, (uint)index)); + ref Vector256 vector = ref Unsafe.As>(ref Unsafe.Add(ref vectorBase, (uint)index)); vector = transform.Invoke(vector); } @@ -79,8 +77,7 @@ internal static partial class Vector4Converters // consumes every remaining complete pixel and leaves no scalar remainder. for (; index < vectors.Length; index++) { - ref Vector128 vector = ref Unsafe.As>( - ref Unsafe.Add(ref vectorBase, (uint)index)); + ref Vector128 vector = ref Unsafe.As>(ref Unsafe.Add(ref vectorBase, (uint)index)); vector = transform.Invoke(vector); } diff --git a/src/ImageSharp/PixelFormats/Utils/Vector4Converters.AffineOperators.cs b/src/ImageSharp/PixelFormats/Utils/Vector4Converters.AffineOperators.cs index 0b08061bc..96d81617b 100644 --- a/src/ImageSharp/PixelFormats/Utils/Vector4Converters.AffineOperators.cs +++ b/src/ImageSharp/PixelFormats/Utils/Vector4Converters.AffineOperators.cs @@ -73,9 +73,7 @@ internal static partial class Vector4Converters [MethodImpl(MethodImplOptions.AggressiveInlining)] public Vector4 Invoke(Vector4 source) { - Vector128 result = - (source.AsVector128() * this.multiplier.GetLower().GetLower()) - + this.offset.GetLower().GetLower(); + Vector128 result = (source.AsVector128() * this.multiplier.GetLower().GetLower()) + this.offset.GetLower().GetLower(); return result.AsVector4(); } @@ -126,9 +124,7 @@ internal static partial class Vector4Converters [MethodImpl(MethodImplOptions.AggressiveInlining)] public Vector4 Invoke(Vector4 source) { - Vector128 result = - (source.AsVector128() + this.offset.GetLower().GetLower()) - / this.divisor.GetLower().GetLower(); + Vector128 result = (source.AsVector128() + this.offset.GetLower().GetLower()) / this.divisor.GetLower().GetLower(); return result.AsVector4(); } diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/CmykColorConversion.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/CmykColorConversion.cs index 9f9dfe433..ae4229807 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/CmykColorConversion.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/CmykColorConversion.cs @@ -9,8 +9,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg; [Config(typeof(Config.Short))] public class CmykColorConversion : ColorConversionBenchmark { - private readonly JpegColorConverterBase converter = - JpegColorConverterBase.GetConverter(JpegColorSpace.Cmyk, 8); + private readonly JpegColorConverterBase converter = JpegColorConverterBase.GetConverter(JpegColorSpace.Cmyk, 8); /// /// Initializes a new instance of the class. diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/GrayscaleColorConversion.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/GrayscaleColorConversion.cs index 5776f4720..9e5bfed12 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/GrayscaleColorConversion.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/GrayscaleColorConversion.cs @@ -9,8 +9,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg; [Config(typeof(Config.Short))] public class GrayScaleColorConversion : ColorConversionBenchmark { - private readonly JpegColorConverterBase converter = - JpegColorConverterBase.GetConverter(JpegColorSpace.Grayscale, 8); + private readonly JpegColorConverterBase converter = JpegColorConverterBase.GetConverter(JpegColorSpace.Grayscale, 8); /// /// Initializes a new instance of the class. diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/JpegColorPacking.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/JpegColorPacking.cs new file mode 100644 index 000000000..5c36ae59f --- /dev/null +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/JpegColorPacking.cs @@ -0,0 +1,178 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Numerics; +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Columns; +using BenchmarkDotNet.Configs; +using SixLabors.ImageSharp.Formats.Jpeg.Components; + +namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg; + +/// +/// Compares the previous scalar JPEG packing loops with the SIMD register-transpose implementation. +/// +[Config(typeof(Config.Short))] +[GroupBenchmarksBy(BenchmarkLogicalGroupRule.ByCategory)] +[CategoriesColumn] +public class JpegColorPacking +{ + private const float MaximumValue = 255F; + private const float Scale = 1F / MaximumValue; + + private float[] x = null!; + private float[] y = null!; + private float[] z = null!; + private float[] w = null!; + private Vector3[] packed3 = null!; + private float[] destination3 = null!; + private float[] destination4 = null!; + + /// + /// Gets or sets the number of pixels transformed by each benchmark invocation. + /// + [Params(128, 1024, 4096)] + public int Length { get; set; } + + /// + /// Creates deterministic source and destination buffers outside the measured operations. + /// + [GlobalSetup] + public void Setup() + { + this.x = CreateSamples(this.Length, 1); + this.y = CreateSamples(this.Length, 2); + this.z = CreateSamples(this.Length, 3); + this.w = CreateSamples(this.Length, 4); + this.packed3 = new Vector3[this.Length]; + this.destination3 = new float[this.Length * 3]; + this.destination4 = new float[this.Length * 4]; + + for (int i = 0; i < this.packed3.Length; i++) + { + this.packed3[i] = new Vector3(this.x[i], this.y[i], this.z[i]); + } + } + + /// + /// Measures the previous scalar three-plane normalization and interleave loop. + /// + /// The last destination value, keeping the writes observable. + [Benchmark(Baseline = true)] + [BenchmarkCategory("Pack3")] + public float PackedNormalizeInterleave3Scalar() + { + JpegColorPackingScalar.PackedNormalizeInterleave3(this.x, this.y, this.z, this.destination3, Scale); + + return this.destination3[^1]; + } + + /// + /// Measures the SIMD three-plane normalization and interleave implementation. + /// + /// The last destination value, keeping the writes observable. + [Benchmark] + [BenchmarkCategory("Pack3")] + public float PackedNormalizeInterleave3Simd() + { + JpegColorConverterBase.PackedNormalizeInterleave3(this.x, this.y, this.z, this.destination3, Scale); + + return this.destination3[^1]; + } + + /// + /// Measures the previous scalar packed-three-channel deinterleave loop. + /// + /// A checksum containing the last value written to every destination plane. + [Benchmark(Baseline = true)] + [BenchmarkCategory("Unpack3")] + public float UnpackDeinterleave3Scalar() + { + JpegColorPackingScalar.UnpackDeinterleave3(this.packed3, this.x, this.y, this.z); + + return this.x[^1] + this.y[^1] + this.z[^1]; + } + + /// + /// Measures the SIMD packed-three-channel deinterleave implementation. + /// + /// A checksum containing the last value written to every destination plane. + [Benchmark] + [BenchmarkCategory("Unpack3")] + public float UnpackDeinterleave3Simd() + { + JpegColorConverterBase.UnpackDeinterleave3(this.packed3, this.x, this.y, this.z); + + return this.x[^1] + this.y[^1] + this.z[^1]; + } + + /// + /// Measures the previous scalar four-plane normalization and interleave loop. + /// + /// The last destination value, keeping the writes observable. + [Benchmark(Baseline = true)] + [BenchmarkCategory("Pack4")] + public float PackedNormalizeInterleave4Scalar() + { + JpegColorPackingScalar.PackedNormalizeInterleave4(this.x, this.y, this.z, this.w, this.destination4, MaximumValue); + + return this.destination4[^1]; + } + + /// + /// Measures the SIMD four-plane normalization and interleave implementation. + /// + /// The last destination value, keeping the writes observable. + [Benchmark] + [BenchmarkCategory("Pack4")] + public float PackedNormalizeInterleave4Simd() + { + JpegColorConverterBase.PackedNormalizeInterleave4(this.x, this.y, this.z, this.w, this.destination4, MaximumValue); + + return this.destination4[^1]; + } + + /// + /// Measures the previous scalar inverted four-plane normalization and interleave loop. + /// + /// The last destination value, keeping the writes observable. + [Benchmark(Baseline = true)] + [BenchmarkCategory("InvertPack4")] + public float PackedInvertNormalizeInterleave4Scalar() + { + JpegColorPackingScalar.PackedInvertNormalizeInterleave4(this.x, this.y, this.z, this.w, this.destination4, MaximumValue); + + return this.destination4[^1]; + } + + /// + /// Measures the SIMD inverted four-plane normalization and interleave implementation. + /// + /// The last destination value, keeping the writes observable. + [Benchmark] + [BenchmarkCategory("InvertPack4")] + public float PackedInvertNormalizeInterleave4Simd() + { + JpegColorConverterBase.PackedInvertNormalizeInterleave4(this.x, this.y, this.z, this.w, this.destination4, MaximumValue); + + return this.destination4[^1]; + } + + /// + /// Creates deterministic, non-integral samples for one component plane. + /// + /// The number of samples to create. + /// The one-based component number used to distinguish the plane. + /// The generated samples. + private static float[] CreateSamples(int length, int component) + { + float[] samples = new float[length]; + + for (int i = 0; i < samples.Length; i++) + { + samples[i] = (((i * 37) + (component * 53)) % 251) + (component * 0.125F); + } + + return samples; + } +} diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/JpegColorPackingScalar.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/JpegColorPackingScalar.cs new file mode 100644 index 000000000..511abc0db --- /dev/null +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/JpegColorPackingScalar.cs @@ -0,0 +1,117 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg; + +/// +/// Preserves the scalar JPEG packing loops that preceded the SIMD investigation. +/// +internal static class JpegColorPackingScalar +{ + /// + /// Normalizes and interleaves three planar component lanes using the previous scalar implementation. + /// + /// The planar X components. + /// The planar Y components. + /// The planar Z components. + /// The destination ordered as consecutive XYZ triples. + /// The normalization factor applied to every component. + public static void PackedNormalizeInterleave3(ReadOnlySpan xLane, ReadOnlySpan yLane, ReadOnlySpan zLane, Span packed, float scale) + { + ref float xLaneRef = ref MemoryMarshal.GetReference(xLane); + ref float yLaneRef = ref MemoryMarshal.GetReference(yLane); + ref float zLaneRef = ref MemoryMarshal.GetReference(zLane); + ref float packedRef = ref MemoryMarshal.GetReference(packed); + + for (nuint i = 0; i < (nuint)xLane.Length; i++) + { + nuint packedOffset = i * 3; + Unsafe.Add(ref packedRef, packedOffset) = Unsafe.Add(ref xLaneRef, i) * scale; + Unsafe.Add(ref packedRef, packedOffset + 1) = Unsafe.Add(ref yLaneRef, i) * scale; + Unsafe.Add(ref packedRef, packedOffset + 2) = Unsafe.Add(ref zLaneRef, i) * scale; + } + } + + /// + /// Deinterleaves packed XYZ values using the previous scalar implementation. + /// + /// The source ordered as consecutive XYZ triples. + /// The destination X components. + /// The destination Y components. + /// The destination Z components. + public static void UnpackDeinterleave3(ReadOnlySpan packed, Span xLane, Span yLane, Span zLane) + { + ref float packedRef = ref MemoryMarshal.GetReference(MemoryMarshal.Cast(packed)); + ref float xLaneRef = ref MemoryMarshal.GetReference(xLane); + ref float yLaneRef = ref MemoryMarshal.GetReference(yLane); + ref float zLaneRef = ref MemoryMarshal.GetReference(zLane); + + for (nuint i = 0; i < (nuint)packed.Length; i++) + { + nuint packedOffset = i * 3; + Unsafe.Add(ref xLaneRef, i) = Unsafe.Add(ref packedRef, packedOffset); + Unsafe.Add(ref yLaneRef, i) = Unsafe.Add(ref packedRef, packedOffset + 1); + Unsafe.Add(ref zLaneRef, i) = Unsafe.Add(ref packedRef, packedOffset + 2); + } + } + + /// + /// Normalizes and interleaves four planar component lanes using the previous scalar implementation. + /// + /// The planar X components. + /// The planar Y components. + /// The planar Z components. + /// The planar W components. + /// The destination ordered as consecutive XYZW groups. + /// The maximum component value used to normalize each component. + public static void PackedNormalizeInterleave4(ReadOnlySpan xLane, ReadOnlySpan yLane, ReadOnlySpan zLane, ReadOnlySpan wLane, Span packed, float maximumValue) + { + float scale = 1F / maximumValue; + ref float xLaneRef = ref MemoryMarshal.GetReference(xLane); + ref float yLaneRef = ref MemoryMarshal.GetReference(yLane); + ref float zLaneRef = ref MemoryMarshal.GetReference(zLane); + ref float wLaneRef = ref MemoryMarshal.GetReference(wLane); + ref float packedRef = ref MemoryMarshal.GetReference(packed); + + for (nuint i = 0; i < (nuint)xLane.Length; i++) + { + nuint packedOffset = i * 4; + Unsafe.Add(ref packedRef, packedOffset) = Unsafe.Add(ref xLaneRef, i) * scale; + Unsafe.Add(ref packedRef, packedOffset + 1) = Unsafe.Add(ref yLaneRef, i) * scale; + Unsafe.Add(ref packedRef, packedOffset + 2) = Unsafe.Add(ref zLaneRef, i) * scale; + Unsafe.Add(ref packedRef, packedOffset + 3) = Unsafe.Add(ref wLaneRef, i) * scale; + } + } + + /// + /// Inverts, normalizes, and interleaves four planar lanes using the previous scalar implementation. + /// + /// The inverted planar X components. + /// The inverted planar Y components. + /// The inverted planar Z components. + /// The inverted planar W components. + /// The destination ordered as consecutive conventional XYZW groups. + /// The maximum component value used for inversion and normalization. + public static void PackedInvertNormalizeInterleave4(ReadOnlySpan xLane, ReadOnlySpan yLane, ReadOnlySpan zLane, ReadOnlySpan wLane, Span packed, float maximumValue) + { + float scale = 1F / maximumValue; + ref float xLaneRef = ref MemoryMarshal.GetReference(xLane); + ref float yLaneRef = ref MemoryMarshal.GetReference(yLane); + ref float zLaneRef = ref MemoryMarshal.GetReference(zLane); + ref float wLaneRef = ref MemoryMarshal.GetReference(wLane); + ref float packedRef = ref MemoryMarshal.GetReference(packed); + + for (nuint i = 0; i < (nuint)xLane.Length; i++) + { + nuint packedOffset = i * 4; + Unsafe.Add(ref packedRef, packedOffset) = (maximumValue - Unsafe.Add(ref xLaneRef, i)) * scale; + Unsafe.Add(ref packedRef, packedOffset + 1) = (maximumValue - Unsafe.Add(ref yLaneRef, i)) * scale; + Unsafe.Add(ref packedRef, packedOffset + 2) = (maximumValue - Unsafe.Add(ref zLaneRef, i)) * scale; + Unsafe.Add(ref packedRef, packedOffset + 3) = (maximumValue - Unsafe.Add(ref wLaneRef, i)) * scale; + } + } +} diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/RgbColorConversion.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/RgbColorConversion.cs index d72bbb40b..b1d72e3ca 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/RgbColorConversion.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/RgbColorConversion.cs @@ -9,8 +9,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg; [Config(typeof(Config.Short))] public class RgbColorConversion : ColorConversionBenchmark { - private readonly JpegColorConverterBase converter = - JpegColorConverterBase.GetConverter(JpegColorSpace.RGB, 8); + private readonly JpegColorConverterBase converter = JpegColorConverterBase.GetConverter(JpegColorSpace.RGB, 8); /// /// Initializes a new instance of the class. diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YCbCrColorConversion.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YCbCrColorConversion.cs index 70936153a..1355aecd1 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YCbCrColorConversion.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YCbCrColorConversion.cs @@ -9,8 +9,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg; [Config(typeof(Config.Short))] public class YCbCrColorConversion : ColorConversionBenchmark { - private readonly JpegColorConverterBase converter = - JpegColorConverterBase.GetConverter(JpegColorSpace.YCbCr, 8); + private readonly JpegColorConverterBase converter = JpegColorConverterBase.GetConverter(JpegColorSpace.YCbCr, 8); /// /// Initializes a new instance of the class. diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YCbCrOperatorAssembly.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YCbCrOperatorAssembly.cs deleted file mode 100644 index b67ee76df..000000000 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YCbCrOperatorAssembly.cs +++ /dev/null @@ -1,244 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Runtime.Intrinsics; -using BenchmarkDotNet.Attributes; -using BenchmarkDotNet.Columns; -using BenchmarkDotNet.Configs; -using SixLabors.ImageSharp.Formats.Jpeg.Components; - -namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg; - -/// -/// Exposes every YCbCr operator overload directly to the disassembly diagnoser. -/// -[Config(typeof(Config.Analysis))] -[GroupBenchmarksBy(BenchmarkLogicalGroupRule.ByCategory)] -[CategoriesColumn] -public class YCbCrOperatorAssembly -{ - private const float MaximumValue = 255F; - private const float HalfValue = 128F; - private const float Scale = 1F / MaximumValue; - - private float scalarC0 = 64F; - private float scalarC1 = 96F; - private float scalarC2 = 160F; - - private readonly Vector128 vector128C0 = Vector128.Create(64F); - private readonly Vector128 vector128C1 = Vector128.Create(96F); - private readonly Vector128 vector128C2 = Vector128.Create(160F); - private readonly Vector128 vector128Maximum = Vector128.Create(MaximumValue); - private readonly Vector128 vector128Half = Vector128.Create(HalfValue); - private readonly Vector128 vector128Scale = Vector128.Create(Scale); - - private readonly Vector256 vector256C0 = Vector256.Create(64F); - private readonly Vector256 vector256C1 = Vector256.Create(96F); - private readonly Vector256 vector256C2 = Vector256.Create(160F); - private readonly Vector256 vector256Maximum = Vector256.Create(MaximumValue); - private readonly Vector256 vector256Half = Vector256.Create(HalfValue); - private readonly Vector256 vector256Scale = Vector256.Create(Scale); - - private readonly Vector512 vector512C0 = Vector512.Create(64F); - private readonly Vector512 vector512C1 = Vector512.Create(96F); - private readonly Vector512 vector512C2 = Vector512.Create(160F); - private readonly Vector512 vector512Maximum = Vector512.Create(MaximumValue); - private readonly Vector512 vector512Half = Vector512.Create(HalfValue); - private readonly Vector512 vector512Scale = Vector512.Create(Scale); - - /// - /// Invokes the scalar JPEG-to-RGB operator. - /// - /// A checksum containing all three converted channels. - [Benchmark] - [BenchmarkCategory("ToRgb")] - public float ToRgbScalar() - { - float c0 = this.scalarC0; - float c1 = this.scalarC1; - float c2 = this.scalarC2; - - JpegColorConverterBase.YCbCrOperator.ConvertToRgb( - ref c0, - ref c1, - ref c2, - 0, - MaximumValue, - HalfValue, - Scale); - - // Returning the channel sum keeps every output live in the generated assembly. - return c0 + c1 + c2; - } - - /// - /// Invokes the Vector128 JPEG-to-RGB operator. - /// - /// A checksum containing all three converted channel vectors. - [Benchmark] - [BenchmarkCategory("ToRgb")] - public Vector128 ToRgbVector128() - { - Vector128 c0 = this.vector128C0; - Vector128 c1 = this.vector128C1; - Vector128 c2 = this.vector128C2; - - JpegColorConverterBase.YCbCrOperator.ConvertToRgb( - ref c0, - ref c1, - ref c2, - default, - this.vector128Maximum, - this.vector128Half, - this.vector128Scale); - - // The vector sum makes all RGB results observable without adding stores to the measured body. - return c0 + c1 + c2; - } - - /// - /// Invokes the Vector256 JPEG-to-RGB operator. - /// - /// A checksum containing all three converted channel vectors. - [Benchmark] - [BenchmarkCategory("ToRgb")] - public Vector256 ToRgbVector256() - { - Vector256 c0 = this.vector256C0; - Vector256 c1 = this.vector256C1; - Vector256 c2 = this.vector256C2; - - JpegColorConverterBase.YCbCrOperator.ConvertToRgb( - ref c0, - ref c1, - ref c2, - default, - this.vector256Maximum, - this.vector256Half, - this.vector256Scale); - - // The vector sum makes all RGB results observable without adding stores to the measured body. - return c0 + c1 + c2; - } - - /// - /// Invokes the Vector512 JPEG-to-RGB operator. - /// - /// A checksum containing all three converted channel vectors. - [Benchmark] - [BenchmarkCategory("ToRgb")] - public Vector512 ToRgbVector512() - { - Vector512 c0 = this.vector512C0; - Vector512 c1 = this.vector512C1; - Vector512 c2 = this.vector512C2; - - JpegColorConverterBase.YCbCrOperator.ConvertToRgb( - ref c0, - ref c1, - ref c2, - default, - this.vector512Maximum, - this.vector512Half, - this.vector512Scale); - - // The vector sum makes all RGB results observable without adding stores to the measured body. - return c0 + c1 + c2; - } - - /// - /// Invokes the scalar RGB-to-JPEG operator. - /// - /// A checksum containing all converted components. - [Benchmark] - [BenchmarkCategory("FromRgb")] - public float FromRgbScalar() - { - JpegColorConverterBase.YCbCrOperator.ConvertFromRgb( - this.scalarC0, - this.scalarC1, - this.scalarC2, - MaximumValue, - HalfValue, - Scale, - out float c0, - out float c1, - out float c2, - out float c3); - - // c3 is deliberately included so a future four-component implementation remains observable. - return c0 + c1 + c2 + c3; - } - - /// - /// Invokes the Vector128 RGB-to-JPEG operator. - /// - /// A checksum containing all converted component vectors. - [Benchmark] - [BenchmarkCategory("FromRgb")] - public Vector128 FromRgbVector128() - { - JpegColorConverterBase.YCbCrOperator.ConvertFromRgb( - this.vector128C0, - this.vector128C1, - this.vector128C2, - this.vector128Maximum, - this.vector128Half, - this.vector128Scale, - out Vector128 c0, - out Vector128 c1, - out Vector128 c2, - out Vector128 c3); - - // Include all planar results in the returned vector so the JIT retains every calculation. - return c0 + c1 + c2 + c3; - } - - /// - /// Invokes the Vector256 RGB-to-JPEG operator. - /// - /// A checksum containing all converted component vectors. - [Benchmark] - [BenchmarkCategory("FromRgb")] - public Vector256 FromRgbVector256() - { - JpegColorConverterBase.YCbCrOperator.ConvertFromRgb( - this.vector256C0, - this.vector256C1, - this.vector256C2, - this.vector256Maximum, - this.vector256Half, - this.vector256Scale, - out Vector256 c0, - out Vector256 c1, - out Vector256 c2, - out Vector256 c3); - - // Include all planar results in the returned vector so the JIT retains every calculation. - return c0 + c1 + c2 + c3; - } - - /// - /// Invokes the Vector512 RGB-to-JPEG operator. - /// - /// A checksum containing all converted component vectors. - [Benchmark] - [BenchmarkCategory("FromRgb")] - public Vector512 FromRgbVector512() - { - JpegColorConverterBase.YCbCrOperator.ConvertFromRgb( - this.vector512C0, - this.vector512C1, - this.vector512C2, - this.vector512Maximum, - this.vector512Half, - this.vector512Scale, - out Vector512 c0, - out Vector512 c1, - out Vector512 c2, - out Vector512 c3); - - // Include all planar results in the returned vector so the JIT retains every calculation. - return c0 + c1 + c2 + c3; - } -} diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YccKColorConverter.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YccKColorConverter.cs index 80adff5cc..261711d0b 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YccKColorConverter.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YccKColorConverter.cs @@ -9,8 +9,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg; [Config(typeof(Config.Short))] public class YccKColorConverter : ColorConversionBenchmark { - private readonly JpegColorConverterBase converter = - JpegColorConverterBase.GetConverter(JpegColorSpace.Ycck, 8); + private readonly JpegColorConverterBase converter = JpegColorConverterBase.GetConverter(JpegColorSpace.Ycck, 8); /// /// Initializes a new instance of the class. diff --git a/tests/ImageSharp.Benchmarks/Codecs/Png/PngFilterEncodeAssembly.cs b/tests/ImageSharp.Benchmarks/Codecs/Png/PngFilterEncodeAssembly.cs deleted file mode 100644 index 5461cb149..000000000 --- a/tests/ImageSharp.Benchmarks/Codecs/Png/PngFilterEncodeAssembly.cs +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using BenchmarkDotNet.Attributes; -using SixLabors.ImageSharp.Formats.Png.Filters; - -namespace SixLabors.ImageSharp.Benchmarks.Codecs.Png; - -/// -/// Exposes every normalized PNG filter for assembly inspection. -/// -[Config(typeof(Config.Analysis))] -public class PngFilterEncodeAssembly -{ - private const int BytesPerPixel = 4; - private const int Count = 180; - - private byte[] scanline; - private byte[] previousScanline; - private byte[] result; - - /// - /// Creates inputs whose suffix exercises 512-, 256-, and 128-bit register widths. - /// - [GlobalSetup] - public void Setup() - { - this.scanline = new byte[Count]; - this.previousScanline = new byte[Count]; - this.result = new byte[Count + 1]; - - Random random = new(12345678); - random.NextBytes(this.scanline); - random.NextBytes(this.previousScanline); - } - - /// - /// Executes the normalized Sub encoder. - /// - [Benchmark] - public void Sub() - => SubFilter.Encode(this.scanline, this.result, BytesPerPixel, out _); - - /// - /// Executes the normalized Up encoder. - /// - [Benchmark] - public void Up() - => UpFilter.Encode(this.scanline, this.previousScanline, this.result, out _); - - /// - /// Executes the normalized Average encoder. - /// - [Benchmark] - public void Average() - => AverageFilter.Encode(this.scanline, this.previousScanline, this.result, BytesPerPixel, out _); - - /// - /// Executes the normalized Paeth encoder. - /// - [Benchmark] - public void Paeth() - => PaethFilter.Encode(this.scanline, this.previousScanline, this.result, BytesPerPixel, out _); -} diff --git a/tests/ImageSharp.Benchmarks/General/BasicMath/TensorPrimitivesAssembly.cs b/tests/ImageSharp.Benchmarks/General/BasicMath/TensorPrimitivesAssembly.cs deleted file mode 100644 index 855d5644c..000000000 --- a/tests/ImageSharp.Benchmarks/General/BasicMath/TensorPrimitivesAssembly.cs +++ /dev/null @@ -1,175 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Numerics; -using BenchmarkDotNet.Attributes; -using SixLabors.ImageSharp.Common.Helpers; - -namespace SixLabors.ImageSharp.Benchmarks.General.BasicMath; - -/// -/// Exposes every floating-point tensor compatibility operation for assembly inspection. -/// -[Config(typeof(Config.Analysis))] -public class TensorPrimitivesAssembly -{ - private const int Count = 2048; - - private readonly float[] x = new float[Count]; - private readonly float[] y = new float[Count]; - private readonly float[] destination = new float[Count]; - - /// - /// Populates the input spans with deterministic non-uniform values. - /// - [GlobalSetup] - public void Setup() - { - for (int i = 0; i < Count; i++) - { - this.x[i] = ((i * 17) % 251) + 1; - this.y[i] = ((i * 29) % 251) + 1; - } - } - - /// - /// Adds two floating-point spans. - /// - /// The first result, which keeps the destination observable. - [Benchmark] - public float Add() - { - TensorPrimitives_.Add(this.x, this.y, this.destination); - return this.destination[0]; - } - - /// - /// Clamps a floating-point span between scalar bounds. - /// - /// The first result, which keeps the destination observable. - [Benchmark] - public float Clamp() - { - TensorPrimitives_.Clamp(this.x, 64F, 128F, this.destination); - return this.destination[0]; - } - - /// - /// Divides a floating-point span by a scalar. - /// - /// The first result, which keeps the destination observable. - [Benchmark] - public float Divide() - { - TensorPrimitives_.Divide(this.x, 4096F, this.destination); - return this.destination[0]; - } - - /// - /// Computes the element-wise maximum of a floating-point span and a scalar. - /// - /// The first result, which keeps the destination observable. - [Benchmark] - public float Max() - { - TensorPrimitives_.Max(this.x, 64F, this.destination); - return this.destination[0]; - } - - /// - /// Multiplies a floating-point span by a scalar. - /// - /// The first result, which keeps the destination observable. - [Benchmark] - public float Multiply() - { - TensorPrimitives_.Multiply(this.x, 0.5F, this.destination); - return this.destination[0]; - } -} - -/// -/// Exposes integral addition specializations for assembly inspection. -/// -/// The integral element type. -[Config(typeof(Config.Analysis))] -[GenericTypeArguments(typeof(byte))] -[GenericTypeArguments(typeof(uint))] -public class TensorPrimitivesIntegralAddAssembly - where T : unmanaged, INumber -{ - private const int Count = 2048; - - private readonly T[] x = new T[Count]; - private readonly T[] y = new T[Count]; - private readonly T[] destination = new T[Count]; - - /// - /// Populates the input spans with deterministic non-uniform values. - /// - [GlobalSetup] - public void Setup() - { - for (int i = 0; i < Count; i++) - { - this.x[i] = T.CreateTruncating((i * 17) + 31); - this.y[i] = T.CreateTruncating((i * 29) + 7); - } - } - - /// - /// Adds two integral spans. - /// - /// The first result, which keeps the destination observable. - [Benchmark] - public T Add() - { - TensorPrimitives_.Add(this.x, this.y, this.destination); - return this.destination[0]; - } -} - -/// -/// Exposes integral clamp specializations for assembly inspection. -/// -/// The integral element type. -[Config(typeof(Config.Analysis))] -[GenericTypeArguments(typeof(byte))] -[GenericTypeArguments(typeof(uint))] -[GenericTypeArguments(typeof(int))] -public class TensorPrimitivesIntegralClampAssembly - where T : unmanaged, INumber -{ - private const int Count = 2048; - - private readonly T[] source = new T[Count]; - private readonly T[] destination = new T[Count]; - private T min; - private T max; - - /// - /// Populates the input span and scalar bounds with deterministic values. - /// - [GlobalSetup] - public void Setup() - { - this.min = T.CreateTruncating(64); - this.max = T.CreateTruncating(128); - - for (int i = 0; i < Count; i++) - { - this.source[i] = T.CreateTruncating((i * 31) % 257); - } - } - - /// - /// Clamps an integral span between scalar bounds. - /// - /// The first result, which keeps the destination observable. - [Benchmark] - public T Clamp() - { - TensorPrimitives_.Clamp(this.source, this.min, this.max, this.destination); - return this.destination[0]; - } -} diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PackedPixelConversionAssembly.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PackedPixelConversionAssembly.cs deleted file mode 100644 index b93e40e19..000000000 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion/PackedPixelConversionAssembly.cs +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using BenchmarkDotNet.Attributes; - -namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion; - -/// -/// Exposes every stateless packed-pixel shuffle operator for assembly inspection. -/// -/// -/// Seven pixels expose the short-input and vector-tail paths. Seventeen pixels execute one -/// full intrinsic group and leave one complete pixel for the scalar remainder, making every -/// part of each generated traversal observable. -/// -[Config(typeof(Config.Analysis))] -public class PackedPixelConversionAssembly -{ - private byte[] source3; - private byte[] source4; - private byte[] destination3; - private byte[] destination4; - - /// - /// Gets or sets the number of pixels converted by each invocation. - /// - [Params(7, 17)] - public int Count { get; set; } - - /// - /// Populates the source buffers with deterministic non-uniform channel values. - /// - [GlobalSetup] - public void Setup() - { - this.source3 = new byte[this.Count * 3]; - this.source4 = new byte[this.Count * 4]; - this.destination3 = new byte[this.Count * 3]; - this.destination4 = new byte[this.Count * 4]; - - new Random(42).NextBytes(this.source3); - new Random(42).NextBytes(this.source4); - } - - /// - /// Executes the WXYZ four-to-four operator. - /// - [Benchmark] - public void Shuffle4Wxyz() => SimdUtils.Shuffle4(this.source4, this.destination4); - - /// - /// Executes the WZYX four-to-four operator. - /// - [Benchmark] - public void Shuffle4Wzyx() => SimdUtils.Shuffle4(this.source4, this.destination4); - - /// - /// Executes the YZWX four-to-four operator. - /// - [Benchmark] - public void Shuffle4Yzwx() => SimdUtils.Shuffle4(this.source4, this.destination4); - - /// - /// Executes the ZYXW four-to-four operator. - /// - [Benchmark] - public void Shuffle4Zyxw() => SimdUtils.Shuffle4(this.source4, this.destination4); - - /// - /// Executes the XWZY four-to-four operator. - /// - [Benchmark] - public void Shuffle4Xwzy() => SimdUtils.Shuffle4(this.source4, this.destination4); - - /// - /// Executes the XYZ four-to-three operator. - /// - [Benchmark] - public void Slice3Xyz() => SimdUtils.Shuffle4Slice3(this.source4, this.destination3); - - /// - /// Executes the YZW four-to-three operator. - /// - [Benchmark] - public void Slice3Yzw() => SimdUtils.Shuffle4Slice3(this.source4, this.destination3); - - /// - /// Executes the WZY four-to-three operator. - /// - [Benchmark] - public void Slice3Wzy() => SimdUtils.Shuffle4Slice3(this.source4, this.destination3); - - /// - /// Executes the ZYX four-to-three operator. - /// - [Benchmark] - public void Slice3Zyx() => SimdUtils.Shuffle4Slice3(this.source4, this.destination3); - - /// - /// Executes the XYZW three-to-four operator. - /// - [Benchmark] - public void Pad4Xyzw() => SimdUtils.Pad3Shuffle4(this.source3, this.destination4); - - /// - /// Executes the WXYZ three-to-four operator. - /// - [Benchmark] - public void Pad4Wxyz() => SimdUtils.Pad3Shuffle4(this.source3, this.destination4); - - /// - /// Executes the WZYX three-to-four operator. - /// - [Benchmark] - public void Pad4Wzyx() => SimdUtils.Pad3Shuffle4(this.source3, this.destination4); - - /// - /// Executes the ZYXW three-to-four operator. - /// - [Benchmark] - public void Pad4Zyxw() => SimdUtils.Pad3Shuffle4(this.source3, this.destination4); - - /// - /// Executes the ZYX three-to-three operator. - /// - [Benchmark] - public void Shuffle3Zyx() => SimdUtils.Shuffle3(this.source3, this.destination3); -} diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/Vector4AffineTransformAssembly.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/Vector4AffineTransformAssembly.cs deleted file mode 100644 index 1b5767ebd..000000000 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion/Vector4AffineTransformAssembly.cs +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Numerics; -using BenchmarkDotNet.Attributes; -using SixLabors.ImageSharp.PixelFormats.Utils; - -namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion; - -/// -/// Exposes every stateful affine operator and traversal remainder for assembly inspection. -/// -[Config(typeof(Config.Analysis))] -public class Vector4AffineTransformAssembly -{ - private static readonly Vector4 Multiplier = new(255F, 2F, 65535F, .5F); - private static readonly Vector4 Offset = new(17F, -1F, 32768F, 3F); - private static readonly Vector4 Divisor = new(255F, 2F, 65535F, .5F); - - private Vector4[] vectors; - - /// - /// Gets or sets the number of vectors transformed by each invocation. - /// - /// - /// Three vectors exercise the 256- and 128-bit stages. Seventeen vectors exercise - /// the 512-bit loop and leave one vector for the 128-bit remainder. - /// - [Params(3, 17)] - public int Count { get; set; } - - /// - /// Creates a non-uniform input buffer. - /// - [GlobalSetup] - public void Setup() - { - this.vectors = new Vector4[this.Count]; - - for (int i = 0; i < this.vectors.Length; i++) - { - this.vectors[i] = new Vector4(i + .25F, i + .5F, i + .75F, i + 1F); - } - } - - /// - /// Executes the multiply-then-add stateful operator. - /// - [Benchmark] - public void MultiplyThenAdd() - => Vector4Converters.MultiplyThenAdd(this.vectors, Multiplier, Offset); - - /// - /// Executes the add-then-divide stateful operator. - /// - [Benchmark] - public void AddThenDivide() - => Vector4Converters.AddThenDivide(this.vectors, Offset, Divisor); -} diff --git a/tests/ImageSharp.Benchmarks/PixelBlenders/PixelBlenderTraversalAssembly.cs b/tests/ImageSharp.Benchmarks/PixelBlenders/PixelBlenderTraversalAssembly.cs deleted file mode 100644 index a8d6095c7..000000000 --- a/tests/ImageSharp.Benchmarks/PixelBlenders/PixelBlenderTraversalAssembly.cs +++ /dev/null @@ -1,327 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Numerics; -using System.Runtime.CompilerServices; -using BenchmarkDotNet.Attributes; -using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.PixelFormats.PixelBlenders; - -namespace SixLabors.ImageSharp.Benchmarks.PixelBlenders; - -/// -/// Exposes every shared pixel-blender traversal shape for assembly inspection. -/// -/// -/// Seven pixels leave three scalar pixels after AVX-512 or one scalar pixel after AVX2, so each -/// hardware job contains both its widest supported loop and the portable Vector4 remainder. -/// -[Config(typeof(Config.Analysis))] -public class PixelBlenderTraversalAssembly -{ - private const int Count = 7; - private const float Amount = .625F; - - private readonly ExposedNormalSrcOverBlender blender = new(); - private readonly Vector4[] destination = new Vector4[Count]; - private readonly Vector4[] background = new Vector4[Count]; - private readonly Vector4[] source = new Vector4[Count]; - private readonly float[] amounts = new float[Count]; - private readonly float[] coverage = new float[Count]; - private Vector4 constantSource; - - /// - /// Populates all lanes with deterministic, non-constant values. - /// - [GlobalSetup] - public void Setup() - { - Random random = new(42); - - for (int i = 0; i < Count; i++) - { - // Distinct RGBA lanes make incorrect pixel grouping visible in both results and assembly. - this.background[i] = CreatePixel(random); - this.source[i] = CreatePixel(random); - this.amounts[i] = random.NextSingle(); - this.coverage[i] = random.NextSingle(); - } - - this.constantSource = CreatePixel(random); - } - - /// - /// Blends a source row with one shared amount. - /// - /// The final destination pixel. - [Benchmark] - public Vector4 SourceSpanScalarAmount() - { - this.blender.BlendSourceSpanScalarAmount( - this.destination, - this.background, - this.source, - Amount); - - return this.destination[^1]; - } - - /// - /// Blends a constant source with one shared amount. - /// - /// The final destination pixel. - [Benchmark] - public Vector4 ConstantSourceScalarAmount() - { - this.blender.BlendConstantSourceScalarAmount( - this.destination, - this.background, - this.constantSource, - Amount); - - return this.destination[^1]; - } - - /// - /// Blends a source row with per-pixel amounts. - /// - /// The final destination pixel. - [Benchmark] - public Vector4 SourceSpanAmountSpan() - { - this.blender.BlendSourceSpanAmountSpan( - this.destination, - this.background, - this.source, - this.amounts); - - return this.destination[^1]; - } - - /// - /// Blends a constant source with per-pixel amounts. - /// - /// The final destination pixel. - [Benchmark] - public Vector4 ConstantSourceAmountSpan() - { - this.blender.BlendConstantSourceAmountSpan( - this.destination, - this.background, - this.constantSource, - this.amounts); - - return this.destination[^1]; - } - - /// - /// Blends a source row with one shared amount and per-pixel coverage. - /// - /// The final destination pixel. - [Benchmark] - public Vector4 SourceSpanScalarAmountCoverage() - { - this.blender.BlendSourceSpanScalarAmountCoverage( - this.destination, - this.background, - this.source, - Amount, - this.coverage); - - return this.destination[^1]; - } - - /// - /// Blends a constant source with one shared amount and per-pixel coverage. - /// - /// The final destination pixel. - [Benchmark] - public Vector4 ConstantSourceScalarAmountCoverage() - { - this.blender.BlendConstantSourceScalarAmountCoverage( - this.destination, - this.background, - this.constantSource, - Amount, - this.coverage); - - return this.destination[^1]; - } - - /// - /// Blends a source row with per-pixel amounts and coverage. - /// - /// The final destination pixel. - [Benchmark] - public Vector4 SourceSpanAmountSpanCoverage() - { - this.blender.BlendSourceSpanAmountSpanCoverage( - this.destination, - this.background, - this.source, - this.amounts, - this.coverage); - - return this.destination[^1]; - } - - /// - /// Blends a constant source with per-pixel amounts and coverage. - /// - /// The final destination pixel. - [Benchmark] - public Vector4 ConstantSourceAmountSpanCoverage() - { - this.blender.BlendConstantSourceAmountSpanCoverage( - this.destination, - this.background, - this.constantSource, - this.amounts, - this.coverage); - - return this.destination[^1]; - } - - /// - /// Creates one non-constant RGBA sample. - /// - /// The deterministic value source. - /// The sample pixel. - private static Vector4 CreatePixel(Random random) - => new(random.NextSingle(), random.NextSingle(), random.NextSingle(), random.NextSingle()); - - /// - /// Exposes the protected shared traversal overloads without adding benchmark hooks to production APIs. - /// - private sealed class ExposedNormalSrcOverBlender : - DefaultPixelBlender - { - /// - /// Invokes the source-span, scalar-amount traversal. - /// - /// The destination vectors. - /// The background vectors. - /// The source vectors. - /// The shared source amount. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void BlendSourceSpanScalarAmount( - Span destination, - ReadOnlySpan background, - ReadOnlySpan source, - float amount) - => this.BlendFunction(destination, background, source, amount); - - /// - /// Invokes the constant-source, scalar-amount traversal. - /// - /// The destination vectors. - /// The background vectors. - /// The constant source vector. - /// The shared source amount. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void BlendConstantSourceScalarAmount( - Span destination, - ReadOnlySpan background, - Vector4 source, - float amount) - => this.BlendFunction(destination, background, source, amount); - - /// - /// Invokes the source-span, amount-span traversal. - /// - /// The destination vectors. - /// The background vectors. - /// The source vectors. - /// The per-pixel source amounts. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void BlendSourceSpanAmountSpan( - Span destination, - ReadOnlySpan background, - ReadOnlySpan source, - ReadOnlySpan amount) - => this.BlendFunction(destination, background, source, amount); - - /// - /// Invokes the constant-source, amount-span traversal. - /// - /// The destination vectors. - /// The background vectors. - /// The constant source vector. - /// The per-pixel source amounts. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void BlendConstantSourceAmountSpan( - Span destination, - ReadOnlySpan background, - Vector4 source, - ReadOnlySpan amount) - => this.BlendFunction(destination, background, source, amount); - - /// - /// Invokes the source-span, scalar-amount traversal with coverage. - /// - /// The destination vectors. - /// The background vectors. - /// The source vectors. - /// The shared source amount. - /// The per-pixel coverage values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void BlendSourceSpanScalarAmountCoverage( - Span destination, - ReadOnlySpan background, - ReadOnlySpan source, - float amount, - ReadOnlySpan coverage) - => this.BlendWithCoverageFunction(destination, background, source, amount, coverage); - - /// - /// Invokes the constant-source, scalar-amount traversal with coverage. - /// - /// The destination vectors. - /// The background vectors. - /// The constant source vector. - /// The shared source amount. - /// The per-pixel coverage values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void BlendConstantSourceScalarAmountCoverage( - Span destination, - ReadOnlySpan background, - Vector4 source, - float amount, - ReadOnlySpan coverage) - => this.BlendWithCoverageFunction(destination, background, source, amount, coverage); - - /// - /// Invokes the source-span, amount-span traversal with coverage. - /// - /// The destination vectors. - /// The background vectors. - /// The source vectors. - /// The per-pixel source amounts. - /// The per-pixel coverage values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void BlendSourceSpanAmountSpanCoverage( - Span destination, - ReadOnlySpan background, - ReadOnlySpan source, - ReadOnlySpan amount, - ReadOnlySpan coverage) - => this.BlendWithCoverageFunction(destination, background, source, amount, coverage); - - /// - /// Invokes the constant-source, amount-span traversal with coverage. - /// - /// The destination vectors. - /// The background vectors. - /// The constant source vector. - /// The per-pixel source amounts. - /// The per-pixel coverage values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void BlendConstantSourceAmountSpanCoverage( - Span destination, - ReadOnlySpan background, - Vector4 source, - ReadOnlySpan amount, - ReadOnlySpan coverage) - => this.BlendWithCoverageFunction(destination, background, source, amount, coverage); - } -} diff --git a/tests/ImageSharp.Tests/Common/SimdUtilsTests.Shuffle.cs b/tests/ImageSharp.Tests/Common/SimdUtilsTests.Shuffle.cs index 4bf1a0b66..cbe2e4066 100644 --- a/tests/ImageSharp.Tests/Common/SimdUtilsTests.Shuffle.cs +++ b/tests/ImageSharp.Tests/Common/SimdUtilsTests.Shuffle.cs @@ -303,30 +303,15 @@ public partial class SimdUtilsTests { int size = FeatureTestRunner.Deserialize(serialized); - TestShuffleByte4Channel( - size, - (s, d) => SimdUtils.Shuffle4(s.Span, d.Span), - SimdUtils.Shuffle.MMShuffle2103); + TestShuffleByte4Channel(size, (s, d) => SimdUtils.Shuffle4(s.Span, d.Span), SimdUtils.Shuffle.MMShuffle2103); - TestShuffleByte4Channel( - size, - (s, d) => SimdUtils.Shuffle4(s.Span, d.Span), - SimdUtils.Shuffle.MMShuffle0123); + TestShuffleByte4Channel(size, (s, d) => SimdUtils.Shuffle4(s.Span, d.Span), SimdUtils.Shuffle.MMShuffle0123); - TestShuffleByte4Channel( - size, - (s, d) => SimdUtils.Shuffle4(s.Span, d.Span), - SimdUtils.Shuffle.MMShuffle0321); + TestShuffleByte4Channel(size, (s, d) => SimdUtils.Shuffle4(s.Span, d.Span), SimdUtils.Shuffle.MMShuffle0321); - TestShuffleByte4Channel( - size, - (s, d) => SimdUtils.Shuffle4(s.Span, d.Span), - SimdUtils.Shuffle.MMShuffle3012); + TestShuffleByte4Channel(size, (s, d) => SimdUtils.Shuffle4(s.Span, d.Span), SimdUtils.Shuffle.MMShuffle3012); - TestShuffleByte4Channel( - size, - (s, d) => SimdUtils.Shuffle4(s.Span, d.Span), - SimdUtils.Shuffle.MMShuffle1230); + TestShuffleByte4Channel(size, (s, d) => SimdUtils.Shuffle4(s.Span, d.Span), SimdUtils.Shuffle.MMShuffle1230); } FeatureTestRunner.RunWithHwIntrinsicsFeature( @@ -343,10 +328,7 @@ public partial class SimdUtilsTests { int size = FeatureTestRunner.Deserialize(serialized); - TestShuffleByte3Channel( - size, - (s, d) => SimdUtils.Shuffle3(s.Span, d.Span), - SimdUtils.Shuffle.MMShuffle3012); + TestShuffleByte3Channel(size, (s, d) => SimdUtils.Shuffle3(s.Span, d.Span), SimdUtils.Shuffle.MMShuffle3012); } FeatureTestRunner.RunWithHwIntrinsicsFeature( @@ -363,25 +345,13 @@ public partial class SimdUtilsTests { int size = FeatureTestRunner.Deserialize(serialized); - TestPad3Shuffle4Channel( - size, - (s, d) => SimdUtils.Pad3Shuffle4(s.Span, d.Span), - SimdUtils.Shuffle.MMShuffle3210); + TestPad3Shuffle4Channel(size, (s, d) => SimdUtils.Pad3Shuffle4(s.Span, d.Span), SimdUtils.Shuffle.MMShuffle3210); - TestPad3Shuffle4Channel( - size, - (s, d) => SimdUtils.Pad3Shuffle4(s.Span, d.Span), - SimdUtils.Shuffle.MMShuffle2103); + TestPad3Shuffle4Channel(size, (s, d) => SimdUtils.Pad3Shuffle4(s.Span, d.Span), SimdUtils.Shuffle.MMShuffle2103); - TestPad3Shuffle4Channel( - size, - (s, d) => SimdUtils.Pad3Shuffle4(s.Span, d.Span), - SimdUtils.Shuffle.MMShuffle0123); + TestPad3Shuffle4Channel(size, (s, d) => SimdUtils.Pad3Shuffle4(s.Span, d.Span), SimdUtils.Shuffle.MMShuffle0123); - TestPad3Shuffle4Channel( - size, - (s, d) => SimdUtils.Pad3Shuffle4(s.Span, d.Span), - SimdUtils.Shuffle.MMShuffle3012); + TestPad3Shuffle4Channel(size, (s, d) => SimdUtils.Pad3Shuffle4(s.Span, d.Span), SimdUtils.Shuffle.MMShuffle3012); } FeatureTestRunner.RunWithHwIntrinsicsFeature( @@ -398,25 +368,13 @@ public partial class SimdUtilsTests { int size = FeatureTestRunner.Deserialize(serialized); - TestShuffle4Slice3Channel( - size, - (s, d) => SimdUtils.Shuffle4Slice3(s.Span, d.Span), - SimdUtils.Shuffle.MMShuffle3210); + TestShuffle4Slice3Channel(size, (s, d) => SimdUtils.Shuffle4Slice3(s.Span, d.Span), SimdUtils.Shuffle.MMShuffle3210); - TestShuffle4Slice3Channel( - size, - (s, d) => SimdUtils.Shuffle4Slice3(s.Span, d.Span), - SimdUtils.Shuffle.MMShuffle0321); + TestShuffle4Slice3Channel(size, (s, d) => SimdUtils.Shuffle4Slice3(s.Span, d.Span), SimdUtils.Shuffle.MMShuffle0321); - TestShuffle4Slice3Channel( - size, - (s, d) => SimdUtils.Shuffle4Slice3(s.Span, d.Span), - SimdUtils.Shuffle.MMShuffle0123); + TestShuffle4Slice3Channel(size, (s, d) => SimdUtils.Shuffle4Slice3(s.Span, d.Span), SimdUtils.Shuffle.MMShuffle0123); - TestShuffle4Slice3Channel( - size, - (s, d) => SimdUtils.Shuffle4Slice3(s.Span, d.Span), - SimdUtils.Shuffle.MMShuffle3012); + TestShuffle4Slice3Channel(size, (s, d) => SimdUtils.Shuffle4Slice3(s.Span, d.Span), SimdUtils.Shuffle.MMShuffle3012); } FeatureTestRunner.RunWithHwIntrinsicsFeature( diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs index dae2d3c3f..76cd2a794 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs @@ -17,8 +17,7 @@ public class JpegColorConverterTests private const float FromRgbTolerance = 0.01F; // Independent model checks compare normalized colors at one tenth of a byte-domain sample. - private static readonly ApproximateColorProfileComparer ColorSpaceComparer = - new(epsilon: ColorProfileTolerance); + private static readonly ApproximateColorProfileComparer ColorSpaceComparer = new(epsilon: ColorProfileTolerance); /// /// Verifies that unsupported color spaces are rejected by the converter factory. @@ -77,27 +76,13 @@ public class JpegColorConverterTests /// The JPEG color space. /// The expected closed converter type. [Theory] - [InlineData( - JpegColorSpace.Grayscale, - typeof(JpegColorConverterBase.JpegColorConverter))] - [InlineData( - JpegColorSpace.RGB, - typeof(JpegColorConverterBase.JpegColorConverter))] - [InlineData( - JpegColorSpace.Cmyk, - typeof(JpegColorConverterBase.JpegColorConverter))] - [InlineData( - JpegColorSpace.YCbCr, - typeof(JpegColorConverterBase.JpegColorConverter))] - [InlineData( - JpegColorSpace.Ycck, - typeof(JpegColorConverterBase.JpegColorConverter))] - [InlineData( - JpegColorSpace.TiffCmyk, - typeof(JpegColorConverterBase.JpegColorConverter))] - [InlineData( - JpegColorSpace.TiffYccK, - typeof(JpegColorConverterBase.JpegColorConverter))] + [InlineData(JpegColorSpace.Grayscale, typeof(JpegColorConverterBase.JpegColorConverter))] + [InlineData(JpegColorSpace.RGB, typeof(JpegColorConverterBase.JpegColorConverter))] + [InlineData(JpegColorSpace.Cmyk, typeof(JpegColorConverterBase.JpegColorConverter))] + [InlineData(JpegColorSpace.YCbCr, typeof(JpegColorConverterBase.JpegColorConverter))] + [InlineData(JpegColorSpace.Ycck, typeof(JpegColorConverterBase.JpegColorConverter))] + [InlineData(JpegColorSpace.TiffCmyk, typeof(JpegColorConverterBase.JpegColorConverter))] + [InlineData(JpegColorSpace.TiffYccK, typeof(JpegColorConverterBase.JpegColorConverter))] internal void GetConverterReturnsClosedOperatorConverter(JpegColorSpace colorSpace, Type expectedType) { JpegColorConverterBase converter = JpegColorConverterBase.GetConverter(colorSpace, 8); @@ -152,10 +137,7 @@ public class JpegColorConverterTests [InlineData(JpegColorSpace.TiffCmyk, 4, 12)] [InlineData(JpegColorSpace.TiffYccK, 4, 8)] [InlineData(JpegColorSpace.TiffYccK, 4, 12)] - internal void OperatorTraversalMatchesScalarDefinition( - JpegColorSpace colorSpace, - int componentCount, - int precision) + internal void OperatorTraversalMatchesScalarDefinition(JpegColorSpace colorSpace, int componentCount, int precision) { switch (colorSpace) { @@ -191,9 +173,7 @@ public class JpegColorConverterTests /// [Fact] public void OperatorTraversalMatchesScalarWithoutHardwareIntrinsics() - => FeatureTestRunner.RunWithHwIntrinsicsFeature( - RunWithoutHardwareIntrinsics, - HwIntrinsics.DisableHWIntrinsic); + => FeatureTestRunner.RunWithHwIntrinsicsFeature(RunWithoutHardwareIntrinsics, HwIntrinsics.DisableHWIntrinsic); /// /// Verifies TIFF YccK encoding against the canonical normalized color-profile conversion. @@ -264,8 +244,7 @@ public class JpegColorConverterTests private static void ValidateOperator(int componentCount, int precision) where TOperator : struct, JpegColorConverterBase.IJpegColorConverterOperator { - JpegColorConverterBase converter = - new JpegColorConverterBase.JpegColorConverter(precision); + JpegColorConverterBase converter = new JpegColorConverterBase.JpegColorConverter(precision); int[] lengths = [1, 3, 4, 7, 8, 15, 16, 31, 32, 40, 64, 128]; // Adjacent values around 4/8/16 lanes verify every prefix, mixed-width tail, and scalar remainder. @@ -284,11 +263,7 @@ public class JpegColorConverterTests /// The number of samples to convert. /// The number of source component planes. /// The JPEG sample precision. - private static void ValidateConversionToRgb( - JpegColorConverterBase converter, - int length, - int componentCount, - int precision) + private static void ValidateConversionToRgb(JpegColorConverterBase converter, int length, int componentCount, int precision) where TOperator : struct, JpegColorConverterBase.IJpegColorConverterOperator { JpegColorConverterBase.ComponentValues expected = CreateRandomValues(length, componentCount, precision); @@ -326,11 +301,7 @@ public class JpegColorConverterTests /// The number of samples to convert. /// The number of destination component planes. /// The JPEG sample precision. - private static void ValidateConversionFromRgb( - JpegColorConverterBase converter, - int length, - int componentCount, - int precision) + private static void ValidateConversionFromRgb(JpegColorConverterBase converter, int length, int componentCount, int precision) where TOperator : struct, JpegColorConverterBase.IJpegColorConverterOperator { JpegColorConverterBase.ComponentValues expected = CreateRandomValues(length, componentCount, precision); @@ -345,17 +316,7 @@ public class JpegColorConverterTests for (int i = 0; i < length; i++) { - TOperator.ConvertFromRgb( - r[i], - g[i], - b[i], - maximumValue, - halfValue, - scale, - out expected.Component0[i], - out float c1, - out float c2, - out float c3); + TOperator.ConvertFromRgb(r[i], g[i], b[i], maximumValue, halfValue, scale, out expected.Component0[i], out float c1, out float c2, out float c3); if (componentCount >= 2) { @@ -399,10 +360,7 @@ public class JpegColorConverterTests /// The number of independent component planes. /// The JPEG sample precision and deterministic random seed. /// The generated component planes. - private static JpegColorConverterBase.ComponentValues CreateRandomValues( - int length, - int componentCount, - int precision) + private static JpegColorConverterBase.ComponentValues CreateRandomValues(int length, int componentCount, int precision) { Random random = new(precision); float maximumValue = MathF.Pow(2, precision) - 1; @@ -449,11 +407,7 @@ public class JpegColorConverterTests /// The unmodified source component planes. /// The converted RGB planes. /// The sample index. - private static void AssertColorModelDefinition( - JpegColorSpace colorSpace, - in JpegColorConverterBase.ComponentValues source, - in JpegColorConverterBase.ComponentValues actual, - int index) + private static void AssertColorModelDefinition(JpegColorSpace colorSpace, in JpegColorConverterBase.ComponentValues source, in JpegColorConverterBase.ComponentValues actual, int index) { float c0 = source.Component0[index]; float c1 = source.Component1[index]; @@ -468,18 +422,12 @@ public class JpegColorConverterTests expected = new Rgb(luminance, luminance, luminance); break; case JpegColorSpace.RGB: - expected = new Rgb( - c0 / MaxColorChannelValue, - c1 / MaxColorChannelValue, - c2 / MaxColorChannelValue); + expected = new Rgb(c0 / MaxColorChannelValue, c1 / MaxColorChannelValue, c2 / MaxColorChannelValue); break; case JpegColorSpace.Cmyk: c3 = source.Component3[index] / MaxColorChannelValue; - expected = new Rgb( - c0 * c3 / MaxColorChannelValue, - c1 * c3 / MaxColorChannelValue, - c2 * c3 / MaxColorChannelValue); + expected = new Rgb(c0 * c3 / MaxColorChannelValue, c1 * c3 / MaxColorChannelValue, c2 * c3 / MaxColorChannelValue); break; case JpegColorSpace.YCbCr: @@ -487,10 +435,7 @@ public class JpegColorConverterTests c2 -= 128F; // JPEG applies the BT.601 matrix in the integer sample domain and rounds before normalization. - expected = new Rgb( - MathF.Round(c0 + (1.402F * c2), MidpointRounding.AwayFromZero) / MaxColorChannelValue, - MathF.Round(c0 - (0.344136F * c1) - (0.714136F * c2), MidpointRounding.AwayFromZero) / MaxColorChannelValue, - MathF.Round(c0 + (1.772F * c1), MidpointRounding.AwayFromZero) / MaxColorChannelValue); + expected = new Rgb(MathF.Round(c0 + (1.402F * c2), MidpointRounding.AwayFromZero) / MaxColorChannelValue, MathF.Round(c0 - (0.344136F * c1) - (0.714136F * c2), MidpointRounding.AwayFromZero) / MaxColorChannelValue, MathF.Round(c0 + (1.772F * c1), MidpointRounding.AwayFromZero) / MaxColorChannelValue); break; case JpegColorSpace.Ycck: @@ -499,10 +444,7 @@ public class JpegColorConverterTests c3 = source.Component3[index] / MaxColorChannelValue; // Adobe YccK reconstructs inverted RGB first, then applies the normalized black component. - expected = new Rgb( - (MaxColorChannelValue - MathF.Round(c0 + (1.402F * c2), MidpointRounding.AwayFromZero)) * c3 / MaxColorChannelValue, - (MaxColorChannelValue - MathF.Round(c0 - (0.344136F * c1) - (0.714136F * c2), MidpointRounding.AwayFromZero)) * c3 / MaxColorChannelValue, - (MaxColorChannelValue - MathF.Round(c0 + (1.772F * c1), MidpointRounding.AwayFromZero)) * c3 / MaxColorChannelValue); + expected = new Rgb((MaxColorChannelValue - MathF.Round(c0 + (1.402F * c2), MidpointRounding.AwayFromZero)) * c3 / MaxColorChannelValue, (MaxColorChannelValue - MathF.Round(c0 - (0.344136F * c1) - (0.714136F * c2), MidpointRounding.AwayFromZero)) * c3 / MaxColorChannelValue, (MaxColorChannelValue - MathF.Round(c0 + (1.772F * c1), MidpointRounding.AwayFromZero)) * c3 / MaxColorChannelValue); break; default: @@ -513,12 +455,9 @@ public class JpegColorConverterTests // Color-space comparison intentionally clamps both sides because JPEG reconstruction can overshoot // the normalized RGB gamut and saturation belongs to the eventual pixel conversion. Rgb clampedExpected = Rgb.Clamp(expected); - Rgb clampedActual = Rgb.Clamp( - new Rgb(actual.Component0[index], actual.Component1[index], actual.Component2[index])); + Rgb clampedActual = Rgb.Clamp(new Rgb(actual.Component0[index], actual.Component1[index], actual.Component2[index])); - Assert.True( - ColorSpaceComparer.Equals(clampedExpected, clampedActual), - $"Colors {clampedExpected} and {clampedActual} are not equal at index {index}."); + Assert.True(ColorSpaceComparer.Equals(clampedExpected, clampedActual), $"Colors {clampedExpected} and {clampedActual} are not equal at index {index}."); } /// diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorPackingTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorPackingTests.cs new file mode 100644 index 000000000..20b4f1679 --- /dev/null +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorPackingTests.cs @@ -0,0 +1,168 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Numerics; +using SixLabors.ImageSharp.Formats.Jpeg.Components; +using SixLabors.ImageSharp.Tests.TestUtilities; + +namespace SixLabors.ImageSharp.Tests.Formats.Jpg; + +/// +/// Tests the planar and packed buffer transformations used around JPEG color-profile conversion. +/// +[Trait("Format", "Jpg")] +public class JpegColorPackingTests +{ + private static readonly int[] Lengths = [0, 1, 2, 3, 4, 5, 7, 8, 15, 16, 17, 31, 32, 33, 129]; + + /// + /// Verifies every packing operation against its scalar definition with and without hardware intrinsics. + /// + [Fact] + public void PackingOperationsMatchScalarDefinitions() + => FeatureTestRunner.RunWithHwIntrinsicsFeature(ValidatePackingOperations, HwIntrinsics.AllowAll | HwIntrinsics.DisableHWIntrinsic); + + /// + /// Exercises every SIMD transition and scalar remainder for the packing operations. + /// + private static void ValidatePackingOperations() + { + foreach (int length in Lengths) + { + ValidatePackedNormalizeInterleave3(length); + ValidateUnpackDeinterleave3(length); + ValidatePackedNormalizeInterleave4(length); + ValidatePackedInvertNormalizeInterleave4(length); + } + } + + /// + /// Compares normalized three-plane interleaving with the original scalar loop. + /// + /// The number of samples in each component plane. + private static void ValidatePackedNormalizeInterleave3(int length) + { + const float scale = 1F / 255F; + float[] x = CreateSamples(length, 1); + float[] y = CreateSamples(length, 2); + float[] z = CreateSamples(length, 3); + float[] expected = new float[length * 3]; + float[] actual = new float[length * 3]; + + for (int i = 0; i < length; i++) + { + int packedOffset = i * 3; + expected[packedOffset] = x[i] * scale; + expected[packedOffset + 1] = y[i] * scale; + expected[packedOffset + 2] = z[i] * scale; + } + + JpegColorConverterBase.PackedNormalizeInterleave3(x, y, z, actual, scale); + + Assert.Equal(expected, actual); + } + + /// + /// Compares packed three-channel deinterleaving with the original scalar loop. + /// + /// The number of packed values. + private static void ValidateUnpackDeinterleave3(int length) + { + Vector3[] packed = new Vector3[length]; + float[] expectedX = CreateSamples(length, 1); + float[] expectedY = CreateSamples(length, 2); + float[] expectedZ = CreateSamples(length, 3); + float[] actualX = new float[length]; + float[] actualY = new float[length]; + float[] actualZ = new float[length]; + + for (int i = 0; i < length; i++) + { + packed[i] = new Vector3(expectedX[i], expectedY[i], expectedZ[i]); + } + + JpegColorConverterBase.UnpackDeinterleave3(packed, actualX, actualY, actualZ); + + Assert.Equal(expectedX, actualX); + Assert.Equal(expectedY, actualY); + Assert.Equal(expectedZ, actualZ); + } + + /// + /// Compares normalized four-plane interleaving with the original scalar loop. + /// + /// The number of samples in each component plane. + private static void ValidatePackedNormalizeInterleave4(int length) + { + const float maximumValue = 255F; + const float scale = 1F / maximumValue; + float[] x = CreateSamples(length, 1); + float[] y = CreateSamples(length, 2); + float[] z = CreateSamples(length, 3); + float[] w = CreateSamples(length, 4); + float[] expected = new float[length * 4]; + float[] actual = new float[length * 4]; + + for (int i = 0; i < length; i++) + { + int packedOffset = i * 4; + expected[packedOffset] = x[i] * scale; + expected[packedOffset + 1] = y[i] * scale; + expected[packedOffset + 2] = z[i] * scale; + expected[packedOffset + 3] = w[i] * scale; + } + + JpegColorConverterBase.PackedNormalizeInterleave4(x, y, z, w, actual, maximumValue); + + Assert.Equal(expected, actual); + } + + /// + /// Compares inverted normalized four-plane interleaving with the original scalar loop. + /// + /// The number of samples in each component plane. + private static void ValidatePackedInvertNormalizeInterleave4(int length) + { + const float maximumValue = 255F; + const float scale = 1F / maximumValue; + float[] x = CreateSamples(length, 1); + float[] y = CreateSamples(length, 2); + float[] z = CreateSamples(length, 3); + float[] w = CreateSamples(length, 4); + float[] expected = new float[length * 4]; + float[] actual = new float[length * 4]; + + for (int i = 0; i < length; i++) + { + int packedOffset = i * 4; + expected[packedOffset] = (maximumValue - x[i]) * scale; + expected[packedOffset + 1] = (maximumValue - y[i]) * scale; + expected[packedOffset + 2] = (maximumValue - z[i]) * scale; + expected[packedOffset + 3] = (maximumValue - w[i]) * scale; + } + + JpegColorConverterBase.PackedInvertNormalizeInterleave4(x, y, z, w, actual, maximumValue); + + Assert.Equal(expected, actual); + } + + /// + /// Creates deterministic, non-integral sample values that expose lane-order and arithmetic mistakes. + /// + /// The number of samples to create. + /// The one-based component number used to distinguish each plane. + /// The generated sample values. + private static float[] CreateSamples(int length, int component) + { + float[] samples = new float[length]; + + for (int i = 0; i < samples.Length; i++) + { + // The relatively prime multipliers produce a distinct sequence for each plane + // while keeping every value inside the eight-bit JPEG sample domain. + samples[i] = (((i * 37) + (component * 53)) % 251) + (component * 0.125F); + } + + return samples; + } +} diff --git a/tests/ImageSharp.Tests/Formats/Png/PngEncoderFilterTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngEncoderFilterTests.cs index 0e76f4fe9..423d54e5f 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngEncoderFilterTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngEncoderFilterTests.cs @@ -63,9 +63,7 @@ public class PngEncoderFilterTests : MeasureFixture data.TestFilter(); } - FeatureTestRunner.RunWithHwIntrinsicsFeature( - RunTest, - HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX2); + FeatureTestRunner.RunWithHwIntrinsicsFeature(RunTest, HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX2); } [Fact] @@ -213,12 +211,7 @@ public class PngEncoderFilterTests : MeasureFixture /// [Fact] public void EncodeMatchesReferencesAcrossRegisterBoundaries() - => FeatureTestRunner.RunWithHwIntrinsicsFeature( - AssertEncodersMatchReferences, - HwIntrinsics.AllowAll - | HwIntrinsics.DisableAVX512F - | HwIntrinsics.DisableAVX2 - | HwIntrinsics.DisableHWIntrinsic); + => FeatureTestRunner.RunWithHwIntrinsicsFeature(AssertEncodersMatchReferences, HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX512F | HwIntrinsics.DisableAVX2 | HwIntrinsics.DisableHWIntrinsic); /// /// Compares every filter with its independent scalar reference across SIMD boundaries and pixel strides. @@ -243,29 +236,13 @@ public class PngEncoderFilterTests : MeasureFixture random.NextBytes(scanline); random.NextBytes(previousScanline); - AssertFilterMatchesReference( - PngFilterMethod.Sub, - scanline, - previousScanline, - bytesPerPixel); - - AssertFilterMatchesReference( - PngFilterMethod.Up, - scanline, - previousScanline, - bytesPerPixel); - - AssertFilterMatchesReference( - PngFilterMethod.Average, - scanline, - previousScanline, - bytesPerPixel); - - AssertFilterMatchesReference( - PngFilterMethod.Paeth, - scanline, - previousScanline, - bytesPerPixel); + AssertFilterMatchesReference(PngFilterMethod.Sub, scanline, previousScanline, bytesPerPixel); + + AssertFilterMatchesReference(PngFilterMethod.Up, scanline, previousScanline, bytesPerPixel); + + AssertFilterMatchesReference(PngFilterMethod.Average, scanline, previousScanline, bytesPerPixel); + + AssertFilterMatchesReference(PngFilterMethod.Paeth, scanline, previousScanline, bytesPerPixel); } } } @@ -277,11 +254,7 @@ public class PngEncoderFilterTests : MeasureFixture /// The current scanline. /// The preceding scanline. /// The component distance between adjacent pixels. - private static void AssertFilterMatchesReference( - PngFilterMethod filter, - byte[] scanline, - byte[] previousScanline, - int bytesPerPixel) + private static void AssertFilterMatchesReference(PngFilterMethod filter, byte[] scanline, byte[] previousScanline, int bytesPerPixel) { byte[] expected = new byte[scanline.Length + 1]; byte[] actual = new byte[scanline.Length + 1]; @@ -301,36 +274,16 @@ public class PngEncoderFilterTests : MeasureFixture break; case PngFilterMethod.Average: - ReferenceImplementations.EncodeAverageFilter( - scanline, - previousScanline, - expected, - bytesPerPixel, - out expectedSum); - - AverageFilter.Encode( - scanline, - previousScanline, - actual, - (uint)bytesPerPixel, - out actualSum); + ReferenceImplementations.EncodeAverageFilter(scanline, previousScanline, expected, bytesPerPixel, out expectedSum); + + AverageFilter.Encode(scanline, previousScanline, actual, (uint)bytesPerPixel, out actualSum); break; case PngFilterMethod.Paeth: - ReferenceImplementations.EncodePaethFilter( - scanline, - previousScanline, - expected, - bytesPerPixel, - out expectedSum); - - PaethFilter.Encode( - scanline, - previousScanline, - actual, - bytesPerPixel, - out actualSum); + ReferenceImplementations.EncodePaethFilter(scanline, previousScanline, expected, bytesPerPixel, out expectedSum); + + PaethFilter.Encode(scanline, previousScanline, actual, bytesPerPixel, out actualSum); break; diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelBlenderTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelBlenderTests.cs index 448de9ec4..34606fcde 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelBlenderTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelBlenderTests.cs @@ -866,12 +866,7 @@ public class PixelBlenderTests /// The source opacity. /// The pixel coverage. /// The blended pixel. - private static TPixel BlendWithCoverageScalar( - PixelBlender blender, - TPixel background, - TPixel source, - float amount, - float coverage) + private static TPixel BlendWithCoverageScalar(PixelBlender blender, TPixel background, TPixel source, float amount, float coverage) where TPixel : unmanaged, IPixel { Span destination = stackalloc TPixel[1]; @@ -880,14 +875,7 @@ public class PixelBlenderTests Span coverageSpan = stackalloc float[1] { coverage }; Span buffer = stackalloc Vector4[3]; - blender.BlendWithCoverage( - Configuration.Default, - destination, - backgroundSpan, - sourceSpan, - amount, - coverageSpan, - buffer); + blender.BlendWithCoverage(Configuration.Default, destination, backgroundSpan, sourceSpan, amount, coverageSpan, buffer); return destination[0]; } diff --git a/tests/ImageSharp.Tests/PixelFormats/Vector4ConvertersTests.cs b/tests/ImageSharp.Tests/PixelFormats/Vector4ConvertersTests.cs index 52f45aad7..837d807f0 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Vector4ConvertersTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Vector4ConvertersTests.cs @@ -20,24 +20,14 @@ public class Vector4ConvertersTests /// [Fact] public void MultiplyThenAddMatchesComponentArithmeticAcrossHardwareWidths() - => FeatureTestRunner.RunWithHwIntrinsicsFeature( - AssertMultiplyThenAddMatchesComponentArithmetic, - HwIntrinsics.AllowAll - | HwIntrinsics.DisableAVX512F - | HwIntrinsics.DisableAVX - | HwIntrinsics.DisableHWIntrinsic); + => FeatureTestRunner.RunWithHwIntrinsicsFeature(AssertMultiplyThenAddMatchesComponentArithmetic, HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX512F | HwIntrinsics.DisableAVX | HwIntrinsics.DisableHWIntrinsic); /// /// Verifies add-then-divide behavior for every SIMD boundary and the software fallback. /// [Fact] public void AddThenDivideMatchesComponentArithmeticAcrossHardwareWidths() - => FeatureTestRunner.RunWithHwIntrinsicsFeature( - AssertAddThenDivideMatchesComponentArithmetic, - HwIntrinsics.AllowAll - | HwIntrinsics.DisableAVX512F - | HwIntrinsics.DisableAVX - | HwIntrinsics.DisableHWIntrinsic); + => FeatureTestRunner.RunWithHwIntrinsicsFeature(AssertAddThenDivideMatchesComponentArithmetic, HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX512F | HwIntrinsics.DisableAVX | HwIntrinsics.DisableHWIntrinsic); /// /// Compares the multiply-then-add traversal with independently evaluated component expressions. @@ -56,11 +46,7 @@ public class Vector4ConvertersTests { Vector4 value = actual[i]; - expected[i] = new Vector4( - (value.X * multiplier.X) + offset.X, - (value.Y * multiplier.Y) + offset.Y, - (value.Z * multiplier.Z) + offset.Z, - (value.W * multiplier.W) + offset.W); + expected[i] = new Vector4((value.X * multiplier.X) + offset.X, (value.Y * multiplier.Y) + offset.Y, (value.Z * multiplier.Z) + offset.Z, (value.W * multiplier.W) + offset.W); } Vector4Converters.MultiplyThenAdd(actual, multiplier, offset); @@ -86,11 +72,7 @@ public class Vector4ConvertersTests { Vector4 value = actual[i]; - expected[i] = new Vector4( - (value.X + offset.X) / divisor.X, - (value.Y + offset.Y) / divisor.Y, - (value.Z + offset.Z) / divisor.Z, - (value.W + offset.W) / divisor.W); + expected[i] = new Vector4((value.X + offset.X) / divisor.X, (value.Y + offset.Y) / divisor.Y, (value.Z + offset.Z) / divisor.Z, (value.W + offset.W) / divisor.W); } Vector4Converters.AddThenDivide(actual, offset, divisor); @@ -110,11 +92,7 @@ public class Vector4ConvertersTests for (int i = 0; i < result.Length; i++) { - result[i] = new Vector4( - (i * 17F) - 31F, - (i * -23F) + 37F, - (i * .25F) - 41F, - (i * 3F) + 43F); + result[i] = new Vector4((i * 17F) - 31F, (i * -23F) + 37F, (i * .25F) - 41F, (i * 3F) + 43F); } return result;