From f2aa2a7965f293f22559dcf9c0107b09b66dbeeb Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 24 Mar 2020 14:50:03 +0000 Subject: [PATCH] Replace Vector4.Clamp --- src/ImageSharp/ColorSpaces/Cmyk.cs | 2 +- .../Common/Helpers/DenseMatrixUtils.cs | 12 ++-- .../SimdUtils.FallbackIntrinsics128.cs | 4 +- src/ImageSharp/Common/Helpers/SimdUtils.cs | 2 +- .../{Vector4Utils.cs => Vector4Utilities.cs} | 18 +++++- .../Jpeg/Components/Block8x8F.Generated.cs | 32 +++++----- .../Jpeg/Components/Block8x8F.Generated.tt | 2 +- .../Formats/Jpeg/Components/Block8x8F.cs | 2 +- .../PixelImplementations/Argb32.cs | 2 +- .../PixelImplementations/Bgra32.cs | 2 +- .../PixelImplementations/Bgra4444.cs | 2 +- .../PixelImplementations/Bgra5551.cs | 2 +- .../PixelImplementations/Byte4.cs | 2 +- .../PixelFormats/PixelImplementations/L16.cs | 2 +- .../PixelFormats/PixelImplementations/L8.cs | 2 +- .../PixelFormats/PixelImplementations/La16.cs | 2 +- .../PixelFormats/PixelImplementations/La32.cs | 2 +- .../PixelImplementations/NormalizedByte4.cs | 2 +- .../PixelImplementations/NormalizedShort4.cs | 2 +- .../PixelImplementations/Rgb24.cs | 2 +- .../PixelImplementations/Rgb48.cs | 2 +- .../PixelImplementations/Rgba1010102.cs | 2 +- .../PixelImplementations/Rgba32.cs | 4 +- .../PixelImplementations/Rgba64.cs | 4 +- .../PixelImplementations/RgbaVector.cs | 2 +- .../PixelImplementations/Short4.cs | 2 +- .../PixelFormats/Utils/Vector4Converters.cs | 4 +- .../Convolution/BokehBlurProcessor{TPixel}.cs | 2 +- .../Filters/FilterProcessor{TPixel}.cs | 2 +- .../Linear/LinearTransformUtilities.cs | 6 +- .../General/BasicMath/ClampVector4.cs | 60 +++++++++++++++++++ .../Helpers/Vector4UtilsTests.cs | 8 +-- .../PixelOperations/PixelOperationsTests.cs | 24 ++++---- 33 files changed, 145 insertions(+), 75 deletions(-) rename src/ImageSharp/Common/Helpers/{Vector4Utils.cs => Vector4Utilities.cs} (85%) create mode 100644 tests/ImageSharp.Benchmarks/General/BasicMath/ClampVector4.cs diff --git a/src/ImageSharp/ColorSpaces/Cmyk.cs b/src/ImageSharp/ColorSpaces/Cmyk.cs index c2331c379..5229cf14f 100644 --- a/src/ImageSharp/ColorSpaces/Cmyk.cs +++ b/src/ImageSharp/ColorSpaces/Cmyk.cs @@ -59,7 +59,7 @@ namespace SixLabors.ImageSharp.ColorSpaces [MethodImpl(InliningOptions.ShortMethod)] public Cmyk(Vector4 vector) { - vector = Vector4.Clamp(vector, Min, Max); + vector = Vector4Utilities.FastClamp(vector, Min, Max); this.C = vector.X; this.M = vector.Y; this.Y = vector.Z; diff --git a/src/ImageSharp/Common/Helpers/DenseMatrixUtils.cs b/src/ImageSharp/Common/Helpers/DenseMatrixUtils.cs index bd25a7b44..462eeb302 100644 --- a/src/ImageSharp/Common/Helpers/DenseMatrixUtils.cs +++ b/src/ImageSharp/Common/Helpers/DenseMatrixUtils.cs @@ -59,7 +59,7 @@ namespace SixLabors.ImageSharp ref Vector4 target = ref Unsafe.Add(ref targetRowRef, column); vector.W = target.W; - Vector4Utils.UnPremultiply(ref vector); + Vector4Utilities.UnPremultiply(ref vector); target = vector; } @@ -105,7 +105,7 @@ namespace SixLabors.ImageSharp out Vector4 vector); ref Vector4 target = ref Unsafe.Add(ref targetRowRef, column); - Vector4Utils.UnPremultiply(ref vector); + Vector4Utilities.UnPremultiply(ref vector); target = vector; } @@ -140,7 +140,7 @@ namespace SixLabors.ImageSharp { int offsetX = (sourceOffsetColumnBase + x - radiusX).Clamp(minColumn, maxColumn); var currentColor = sourceRowSpan[offsetX].ToVector4(); - Vector4Utils.Premultiply(ref currentColor); + Vector4Utilities.Premultiply(ref currentColor); vectorX += matrixX[y, x] * currentColor; vectorY += matrixY[y, x] * currentColor; @@ -193,7 +193,7 @@ namespace SixLabors.ImageSharp ref Vector4 target = ref Unsafe.Add(ref targetRowRef, column); vector.W = target.W; - Vector4Utils.UnPremultiply(ref vector); + Vector4Utilities.UnPremultiply(ref vector); target = vector; } @@ -238,7 +238,7 @@ namespace SixLabors.ImageSharp ref vector); ref Vector4 target = ref Unsafe.Add(ref targetRowRef, column); - Vector4Utils.UnPremultiply(ref vector); + Vector4Utilities.UnPremultiply(ref vector); target = vector; } @@ -270,7 +270,7 @@ namespace SixLabors.ImageSharp { int offsetX = (sourceOffsetColumnBase + x - radiusX).Clamp(minColumn, maxColumn); var currentColor = sourceRowSpan[offsetX].ToVector4(); - Vector4Utils.Premultiply(ref currentColor); + Vector4Utilities.Premultiply(ref currentColor); vector += matrix[y, x] * currentColor; } } diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs b/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs index aaacfdd85..6a93f9efc 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; @@ -125,8 +125,6 @@ namespace SixLabors.ImageSharp Vector4 s = Unsafe.Add(ref sBase, i); s *= maxBytes; s += half; - - // I'm not sure if Vector4.Clamp() is properly implemented with intrinsics. s = Vector4.Max(Vector4.Zero, s); s = Vector4.Min(maxBytes, s); diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.cs b/src/ImageSharp/Common/Helpers/SimdUtils.cs index b58ec900f..0dc45d887 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.cs @@ -28,7 +28,7 @@ namespace SixLabors.ImageSharp [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static Vector4 PseudoRound(this Vector4 v) { - var sign = Vector4.Clamp(v, new Vector4(-1), new Vector4(1)); + var sign = Vector4Utilities.FastClamp(v, new Vector4(-1), new Vector4(1)); return v + (sign * 0.5f); } diff --git a/src/ImageSharp/Common/Helpers/Vector4Utils.cs b/src/ImageSharp/Common/Helpers/Vector4Utilities.cs similarity index 85% rename from src/ImageSharp/Common/Helpers/Vector4Utils.cs rename to src/ImageSharp/Common/Helpers/Vector4Utilities.cs index 594a5ff10..02bb4d916 100644 --- a/src/ImageSharp/Common/Helpers/Vector4Utils.cs +++ b/src/ImageSharp/Common/Helpers/Vector4Utilities.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; @@ -11,8 +11,20 @@ namespace SixLabors.ImageSharp /// /// Utility methods for the struct. /// - internal static class Vector4Utils + internal static class Vector4Utilities { + /// + /// Restricts a vector between a minimum and a maximum value. + /// 5x Faster then . + /// + /// The vector to restrict. + /// The minimum value. + /// The maximum value. + /// The . + [MethodImpl(InliningOptions.ShortMethod)] + public static Vector4 FastClamp(Vector4 x, Vector4 min, Vector4 max) + => Vector4.Min(Vector4.Max(min, x), max); + /// /// Pre-multiplies the "x", "y", "z" components of a vector by its "w" component leaving the "w" component intact. /// @@ -107,4 +119,4 @@ namespace SixLabors.ImageSharp } } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.cs index 033eedb92..8e14ed2c3 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.cs @@ -99,22 +99,22 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components var CMax4 = new Vector4(maximum); var COff4 = new Vector4(MathF.Ceiling(maximum / 2)); - this.V0L = Vector4.Clamp(this.V0L + COff4, CMin4, CMax4); - this.V0R = Vector4.Clamp(this.V0R + COff4, CMin4, CMax4); - this.V1L = Vector4.Clamp(this.V1L + COff4, CMin4, CMax4); - this.V1R = Vector4.Clamp(this.V1R + COff4, CMin4, CMax4); - this.V2L = Vector4.Clamp(this.V2L + COff4, CMin4, CMax4); - this.V2R = Vector4.Clamp(this.V2R + COff4, CMin4, CMax4); - this.V3L = Vector4.Clamp(this.V3L + COff4, CMin4, CMax4); - this.V3R = Vector4.Clamp(this.V3R + COff4, CMin4, CMax4); - this.V4L = Vector4.Clamp(this.V4L + COff4, CMin4, CMax4); - this.V4R = Vector4.Clamp(this.V4R + COff4, CMin4, CMax4); - this.V5L = Vector4.Clamp(this.V5L + COff4, CMin4, CMax4); - this.V5R = Vector4.Clamp(this.V5R + COff4, CMin4, CMax4); - this.V6L = Vector4.Clamp(this.V6L + COff4, CMin4, CMax4); - this.V6R = Vector4.Clamp(this.V6R + COff4, CMin4, CMax4); - this.V7L = Vector4.Clamp(this.V7L + COff4, CMin4, CMax4); - this.V7R = Vector4.Clamp(this.V7R + COff4, CMin4, CMax4); + this.V0L = Vector4Utilities.FastClamp(this.V0L + COff4, CMin4, CMax4); + this.V0R = Vector4Utilities.FastClamp(this.V0R + COff4, CMin4, CMax4); + this.V1L = Vector4Utilities.FastClamp(this.V1L + COff4, CMin4, CMax4); + this.V1R = Vector4Utilities.FastClamp(this.V1R + COff4, CMin4, CMax4); + this.V2L = Vector4Utilities.FastClamp(this.V2L + COff4, CMin4, CMax4); + this.V2R = Vector4Utilities.FastClamp(this.V2R + COff4, CMin4, CMax4); + this.V3L = Vector4Utilities.FastClamp(this.V3L + COff4, CMin4, CMax4); + this.V3R = Vector4Utilities.FastClamp(this.V3R + COff4, CMin4, CMax4); + this.V4L = Vector4Utilities.FastClamp(this.V4L + COff4, CMin4, CMax4); + this.V4R = Vector4Utilities.FastClamp(this.V4R + COff4, CMin4, CMax4); + this.V5L = Vector4Utilities.FastClamp(this.V5L + COff4, CMin4, CMax4); + this.V5R = Vector4Utilities.FastClamp(this.V5R + COff4, CMin4, CMax4); + this.V6L = Vector4Utilities.FastClamp(this.V6L + COff4, CMin4, CMax4); + this.V6R = Vector4Utilities.FastClamp(this.V6R + COff4, CMin4, CMax4); + this.V7L = Vector4Utilities.FastClamp(this.V7L + COff4, CMin4, CMax4); + this.V7R = Vector4Utilities.FastClamp(this.V7R + COff4, CMin4, CMax4); } /// diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.tt b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.tt index 5370f2704..a1a6b0172 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.tt +++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.tt @@ -73,7 +73,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components for (int j = 0; j < 2; j++) { char side = j == 0 ? 'L' : 'R'; - Write($"this.V{i}{side} = Vector4.Clamp(this.V{i}{side} + COff4, CMin4, CMax4);\r\n"); + Write($"this.V{i}{side} = Vector4Utilities.FastClamp(this.V{i}{side} + COff4, CMin4, CMax4);\r\n"); } } PopIndent(); diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs index 868faceea..70a34ddcf 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs @@ -589,7 +589,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components private static Vector4 DivideRound(Vector4 dividend, Vector4 divisor) { // sign(dividend) = max(min(dividend, 1), -1) - var sign = Vector4.Clamp(dividend, NegativeOne, Vector4.One); + var sign = Vector4Utilities.FastClamp(dividend, NegativeOne, Vector4.One); // AlmostRound(dividend/divisor) = dividend/divisor + 0.5*sign(dividend) return (dividend / divisor) + (sign * Offset); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs index d5f4c54fb..52f6bcaa1 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs @@ -373,7 +373,7 @@ namespace SixLabors.ImageSharp.PixelFormats { vector *= MaxBytes; vector += Half; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); + vector = Vector4Utilities.FastClamp(vector, Vector4.Zero, MaxBytes); this.R = (byte)vector.X; this.G = (byte)vector.Y; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs index 0f2991a35..40c187eb2 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs @@ -296,7 +296,7 @@ namespace SixLabors.ImageSharp.PixelFormats { vector *= MaxBytes; vector += Half; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); + vector = Vector4Utilities.FastClamp(vector, Vector4.Zero, MaxBytes); this.R = (byte)vector.X; this.G = (byte)vector.Y; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs index f06831284..bbbf9145c 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs @@ -162,7 +162,7 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] private static ushort Pack(ref Vector4 vector) { - vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One); + vector = Vector4Utilities.FastClamp(vector, Vector4.Zero, Vector4.One); return (ushort)((((int)Math.Round(vector.W * 15F) & 0x0F) << 12) | (((int)Math.Round(vector.X * 15F) & 0x0F) << 8) | (((int)Math.Round(vector.Y * 15F) & 0x0F) << 4) diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs index 92f2a3f75..d10d10b47 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs @@ -163,7 +163,7 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] private static ushort Pack(ref Vector4 vector) { - vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One); + vector = Vector4Utilities.FastClamp(vector, Vector4.Zero, Vector4.One); return (ushort)( (((int)Math.Round(vector.X * 31F) & 0x1F) << 10) | (((int)Math.Round(vector.Y * 31F) & 0x1F) << 5) diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs index 728966b00..49b4f4138 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs @@ -171,7 +171,7 @@ namespace SixLabors.ImageSharp.PixelFormats const float Max = 255F; // Clamp the value between min and max values - vector = Vector4.Clamp(vector, Vector4.Zero, new Vector4(Max)); + vector = Vector4Utilities.FastClamp(vector, Vector4.Zero, new Vector4(Max)); uint byte4 = (uint)Math.Round(vector.X) & 0xFF; uint byte3 = ((uint)Math.Round(vector.Y) & 0xFF) << 0x8; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/L16.cs b/src/ImageSharp/PixelFormats/PixelImplementations/L16.cs index 7235abd21..815ae6a4e 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/L16.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/L16.cs @@ -176,7 +176,7 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] internal void ConvertFromRgbaScaledVector4(Vector4 vector) { - vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * Max; + vector = Vector4Utilities.FastClamp(vector, Vector4.Zero, Vector4.One) * Max; this.PackedValue = ImageMaths.Get16BitBT709Luminance( vector.X, vector.Y, diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/L8.cs b/src/ImageSharp/PixelFormats/PixelImplementations/L8.cs index c622f1750..37a028db2 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/L8.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/L8.cs @@ -156,7 +156,7 @@ namespace SixLabors.ImageSharp.PixelFormats { vector *= MaxBytes; vector += Half; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); + vector = Vector4Utilities.FastClamp(vector, Vector4.Zero, MaxBytes); this.PackedValue = ImageMaths.Get8BitBT709Luminance((byte)vector.X, (byte)vector.Y, (byte)vector.Z); } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/La16.cs b/src/ImageSharp/PixelFormats/PixelImplementations/La16.cs index 66cb757c3..104c2be45 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/La16.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/La16.cs @@ -219,7 +219,7 @@ namespace SixLabors.ImageSharp.PixelFormats { vector *= MaxBytes; vector += Half; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); + vector = Vector4Utilities.FastClamp(vector, Vector4.Zero, MaxBytes); this.L = ImageMaths.Get8BitBT709Luminance((byte)vector.X, (byte)vector.Y, (byte)vector.Z); this.A = (byte)vector.W; } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs index 4885dae61..98a6cdae4 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs @@ -233,7 +233,7 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] internal void ConvertFromRgbaScaledVector4(Vector4 vector) { - vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * Max; + vector = Vector4Utilities.FastClamp(vector, Vector4.Zero, Vector4.One) * Max; this.L = ImageMaths.Get16BitBT709Luminance( vector.X, vector.Y, diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs index 3a4b92ff3..a7b350d55 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs @@ -174,7 +174,7 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] private static uint Pack(ref Vector4 vector) { - vector = Vector4.Clamp(vector, MinusOne, Vector4.One) * Half; + vector = Vector4Utilities.FastClamp(vector, MinusOne, Vector4.One) * Half; uint byte4 = ((uint)MathF.Round(vector.X) & 0xFF) << 0; uint byte3 = ((uint)MathF.Round(vector.Y) & 0xFF) << 8; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs index 052e44f71..59433f17e 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs @@ -177,7 +177,7 @@ namespace SixLabors.ImageSharp.PixelFormats private static ulong Pack(ref Vector4 vector) { vector *= Max; - vector = Vector4.Clamp(vector, Min, Max); + vector = Vector4Utilities.FastClamp(vector, Min, Max); // Round rather than truncate. ulong word4 = ((ulong)MathF.Round(vector.X) & 0xFFFF) << 0x00; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs index 5eb7b74b2..6e4839fed 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs @@ -254,7 +254,7 @@ namespace SixLabors.ImageSharp.PixelFormats { vector *= MaxBytes; vector += Half; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); + vector = Vector4Utilities.FastClamp(vector, Vector4.Zero, MaxBytes); this.R = (byte)vector.X; this.G = (byte)vector.Y; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs index e494ff68e..dff8fe83f 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs @@ -85,7 +85,7 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void FromVector4(Vector4 vector) { - vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * Max; + vector = Vector4Utilities.FastClamp(vector, Vector4.Zero, Vector4.One) * Max; this.R = (ushort)MathF.Round(vector.X); this.G = (ushort)MathF.Round(vector.Y); this.B = (ushort)MathF.Round(vector.Z); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs index 2b5670778..7ca47f838 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs @@ -163,7 +163,7 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] private static uint Pack(ref Vector4 vector) { - vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * Multiplier; + vector = Vector4Utilities.FastClamp(vector, Vector4.Zero, Vector4.One) * Multiplier; return (uint)( (((int)Math.Round(vector.X) & 0x03FF) << 0) diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs index 8f67f2166..43ec095a1 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs @@ -452,7 +452,7 @@ namespace SixLabors.ImageSharp.PixelFormats { vector *= MaxBytes; vector += Half; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); + vector = Vector4Utilities.FastClamp(vector, Vector4.Zero, MaxBytes); return new Rgba32((byte)vector.X, (byte)vector.Y, (byte)vector.Z, (byte)vector.W); } @@ -491,7 +491,7 @@ namespace SixLabors.ImageSharp.PixelFormats { vector *= MaxBytes; vector += Half; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); + vector = Vector4Utilities.FastClamp(vector, Vector4.Zero, MaxBytes); this.R = (byte)vector.X; this.G = (byte)vector.Y; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs index 88ef1dc98..8e5f8f093 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs @@ -127,7 +127,7 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public Rgba64(Vector4 vector) { - vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * Max; + vector = Vector4Utilities.FastClamp(vector, Vector4.Zero, Vector4.One) * Max; this.R = (ushort)MathF.Round(vector.X); this.G = (ushort)MathF.Round(vector.Y); this.B = (ushort)MathF.Round(vector.Z); @@ -209,7 +209,7 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void FromVector4(Vector4 vector) { - vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * Max; + vector = Vector4Utilities.FastClamp(vector, Vector4.Zero, Vector4.One) * Max; this.R = (ushort)MathF.Round(vector.X); this.G = (ushort)MathF.Round(vector.Y); this.B = (ushort)MathF.Round(vector.Z); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs b/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs index 8a6bc94a7..8a6f882c3 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs @@ -111,7 +111,7 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void FromVector4(Vector4 vector) { - vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One); + vector = Vector4Utilities.FastClamp(vector, Vector4.Zero, Vector4.One); this.R = vector.X; this.G = vector.Y; this.B = vector.Z; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs index e709cd04f..135aa8d58 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs @@ -183,7 +183,7 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] private static ulong Pack(ref Vector4 vector) { - vector = Vector4.Clamp(vector, Min, Max); + vector = Vector4Utilities.FastClamp(vector, Min, Max); // Clamp the value between min and max values ulong word4 = ((ulong)Math.Round(vector.X) & 0xFFFF) << 0x00; diff --git a/src/ImageSharp/PixelFormats/Utils/Vector4Converters.cs b/src/ImageSharp/PixelFormats/Utils/Vector4Converters.cs index 447869a7d..ba676b3b8 100644 --- a/src/ImageSharp/PixelFormats/Utils/Vector4Converters.cs +++ b/src/ImageSharp/PixelFormats/Utils/Vector4Converters.cs @@ -24,7 +24,7 @@ namespace SixLabors.ImageSharp.PixelFormats.Utils if (modifiers.IsDefined(PixelConversionModifiers.Premultiply)) { - Vector4Utils.Premultiply(vectors); + Vector4Utilities.Premultiply(vectors); } } @@ -36,7 +36,7 @@ namespace SixLabors.ImageSharp.PixelFormats.Utils { if (modifiers.IsDefined(PixelConversionModifiers.Premultiply)) { - Vector4Utils.UnPremultiply(vectors); + Vector4Utilities.UnPremultiply(vectors); } if (modifiers.IsDefined(PixelConversionModifiers.SRgbCompand)) diff --git a/src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor{TPixel}.cs index 493218cde..cf97751be 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor{TPixel}.cs @@ -304,7 +304,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution for (int x = 0; x < this.bounds.Width; x++) { ref Vector4 v = ref Unsafe.Add(ref sourceRef, x); - var clamp = Vector4.Clamp(v, low, high); + var clamp = Vector4Utilities.FastClamp(v, low, high); v.X = MathF.Pow(clamp.X, this.inverseGamma); v.Y = MathF.Pow(clamp.Y, this.inverseGamma); v.Z = MathF.Pow(clamp.Z, this.inverseGamma); diff --git a/src/ImageSharp/Processing/Processors/Filters/FilterProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Filters/FilterProcessor{TPixel}.cs index 7da4eb1b1..dee9d2ff6 100644 --- a/src/ImageSharp/Processing/Processors/Filters/FilterProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Filters/FilterProcessor{TPixel}.cs @@ -74,7 +74,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Filters Span rowSpan = this.source.GetPixelRowSpan(y).Slice(this.startX, span.Length); PixelOperations.Instance.ToVector4(this.configuration, rowSpan, span); - Vector4Utils.Transform(span, ref Unsafe.AsRef(this.matrix)); + Vector4Utilities.Transform(span, ref Unsafe.AsRef(this.matrix)); PixelOperations.Instance.FromVector4Destructive(this.configuration, span, rowSpan); } diff --git a/src/ImageSharp/Processing/Processors/Transforms/Linear/LinearTransformUtilities.cs b/src/ImageSharp/Processing/Processors/Transforms/Linear/LinearTransformUtilities.cs index 04aaa1102..0a00cf8e9 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Linear/LinearTransformUtilities.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Linear/LinearTransformUtilities.cs @@ -52,7 +52,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms MathF.Floor(maxXY.X), MathF.Floor(maxXY.Y)); - sourceExtents = Vector4.Clamp(sourceExtents, Vector4.Zero, maxSourceExtents); + sourceExtents = Vector4Utilities.FastClamp(sourceExtents, Vector4.Zero, maxSourceExtents); int left = (int)sourceExtents.X; int top = (int)sourceExtents.Y; @@ -78,13 +78,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms // Values are first premultiplied to prevent darkening of edge pixels. var current = sourcePixels[x, y].ToVector4(); - Vector4Utils.Premultiply(ref current); + Vector4Utilities.Premultiply(ref current); sum += current * xWeight * yWeight; } } // Reverse the premultiplication - Vector4Utils.UnPremultiply(ref sum); + Vector4Utilities.UnPremultiply(ref sum); targetRow[column] = sum; } diff --git a/tests/ImageSharp.Benchmarks/General/BasicMath/ClampVector4.cs b/tests/ImageSharp.Benchmarks/General/BasicMath/ClampVector4.cs new file mode 100644 index 000000000..8cbb31d21 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/BasicMath/ClampVector4.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections.Generic; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Text; +using BenchmarkDotNet.Attributes; + +namespace SixLabors.ImageSharp.Benchmarks.General.BasicMath +{ + public class ClampVector4 + { + private readonly float min = -1.5f; + private readonly float max = 2.5f; + private static readonly float[] Values = { -10, -5, -3, -1.5f, -0.5f, 0f, 1f, 1.5f, 2.5f, 3, 10 }; + + [Benchmark(Baseline = true)] + public Vector4 UsingVectorClamp() + { + Vector4 acc = Vector4.Zero; + + for (int i = 0; i < Values.Length; i++) + { + acc += ClampUsingVectorClamp(Values[i], this.min, this.max); + } + + return acc; + } + + [Benchmark] + public Vector4 UsingVectorMinMax() + { + Vector4 acc = Vector4.Zero; + + for (int i = 0; i < Values.Length; i++) + { + acc += ClampUsingVectorMinMax(Values[i], this.min, this.max); + } + + return acc; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Vector4 ClampUsingVectorClamp(float x, float min, float max) + { + return Vector4.Clamp(new Vector4(x), new Vector4(min), new Vector4(max)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Vector4 ClampUsingVectorMinMax(float x, float min, float max) + { + return Vector4.Min(new Vector4(max), Vector4.Max(new Vector4(min), new Vector4(x))); + } + + // RESULTS + // | Method | Mean | Error | StdDev | Ratio | + // |------------------ |---------:|---------:|---------:|------:| + // | UsingVectorClamp | 75.21 ns | 1.572 ns | 4.057 ns | 1.00 | + // | UsingVectorMinMax | 15.35 ns | 0.356 ns | 0.789 ns | 0.20 | + } +} diff --git a/tests/ImageSharp.Tests/Helpers/Vector4UtilsTests.cs b/tests/ImageSharp.Tests/Helpers/Vector4UtilsTests.cs index af789a9b6..bc1ffda48 100644 --- a/tests/ImageSharp.Tests/Helpers/Vector4UtilsTests.cs +++ b/tests/ImageSharp.Tests/Helpers/Vector4UtilsTests.cs @@ -23,11 +23,11 @@ namespace SixLabors.ImageSharp.Tests.Helpers Vector4[] source = rnd.GenerateRandomVectorArray(length, 0, 1); Vector4[] expected = source.Select(v => { - Vector4Utils.Premultiply(ref v); + Vector4Utilities.Premultiply(ref v); return v; }).ToArray(); - Vector4Utils.Premultiply(source); + Vector4Utilities.Premultiply(source); Assert.Equal(expected, source, this.approximateFloatComparer); } @@ -42,11 +42,11 @@ namespace SixLabors.ImageSharp.Tests.Helpers Vector4[] source = rnd.GenerateRandomVectorArray(length, 0, 1); Vector4[] expected = source.Select(v => { - Vector4Utils.UnPremultiply(ref v); + Vector4Utilities.UnPremultiply(ref v); return v; }).ToArray(); - Vector4Utils.UnPremultiply(source); + Vector4Utilities.UnPremultiply(source); Assert.Equal(expected, source, this.approximateFloatComparer); } diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.cs index b2b39b590..9d48675f1 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.cs @@ -170,7 +170,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations { if (this.HasAlpha) { - Vector4Utils.Premultiply(ref v); + Vector4Utilities.Premultiply(ref v); } } @@ -178,7 +178,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations { if (this.HasAlpha) { - Vector4Utils.UnPremultiply(ref v); + Vector4Utilities.UnPremultiply(ref v); } } @@ -199,7 +199,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations { if (this.HasAlpha) { - Vector4Utils.Premultiply(ref v); + Vector4Utilities.Premultiply(ref v); } } @@ -207,7 +207,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations { if (this.HasAlpha) { - Vector4Utils.UnPremultiply(ref v); + Vector4Utilities.UnPremultiply(ref v); } } @@ -234,7 +234,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations if (this.HasAlpha) { - Vector4Utils.Premultiply(ref v); + Vector4Utilities.Premultiply(ref v); } } @@ -242,7 +242,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations { if (this.HasAlpha) { - Vector4Utils.UnPremultiply(ref v); + Vector4Utilities.UnPremultiply(ref v); } SRgbCompanding.Compress(ref v); @@ -349,12 +349,12 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations { void SourceAction(ref Vector4 v) { - Vector4Utils.UnPremultiply(ref v); + Vector4Utilities.UnPremultiply(ref v); } void ExpectedAction(ref Vector4 v) { - Vector4Utils.Premultiply(ref v); + Vector4Utilities.Premultiply(ref v); } TPixel[] source = CreatePixelTestData(count, (ref Vector4 v) => SourceAction(ref v)); @@ -372,12 +372,12 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations { void SourceAction(ref Vector4 v) { - Vector4Utils.UnPremultiply(ref v); + Vector4Utilities.UnPremultiply(ref v); } void ExpectedAction(ref Vector4 v) { - Vector4Utils.Premultiply(ref v); + Vector4Utilities.Premultiply(ref v); } TPixel[] source = CreateScaledPixelTestData(count, (ref Vector4 v) => SourceAction(ref v)); @@ -399,14 +399,14 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations { void SourceAction(ref Vector4 v) { - Vector4Utils.UnPremultiply(ref v); + Vector4Utilities.UnPremultiply(ref v); SRgbCompanding.Compress(ref v); } void ExpectedAction(ref Vector4 v) { SRgbCompanding.Expand(ref v); - Vector4Utils.Premultiply(ref v); + Vector4Utilities.Premultiply(ref v); } TPixel[] source = CreateScaledPixelTestData(count, (ref Vector4 v) => SourceAction(ref v));