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..f16c91b40 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,10 +125,7 @@ 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);
+ s = Vector4Utilities.FastClamp(s, Vector4.Zero, maxBytes);
ref ByteVector4 d = ref Unsafe.Add(ref dBase, i);
d.X = (byte)s.X;
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..9fb4eb790 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(x, min), 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/ImageExtensions.cs b/src/ImageSharp/ImageExtensions.cs
index bb3128282..0bdbcc4ab 100644
--- a/src/ImageSharp/ImageExtensions.cs
+++ b/src/ImageSharp/ImageExtensions.cs
@@ -112,12 +112,12 @@ namespace SixLabors.ImageSharp
public static string ToBase64String(this Image source, IImageFormat format)
where TPixel : unmanaged, IPixel
{
- using (var stream = new MemoryStream())
- {
- source.Save(stream, format);
- stream.Flush();
- return $"data:{format.DefaultMimeType};base64,{Convert.ToBase64String(stream.ToArray())}";
- }
+ using var stream = new MemoryStream();
+ source.Save(stream, format);
+
+ // Always available.
+ stream.TryGetBuffer(out ArraySegment buffer);
+ return $"data:{format.DefaultMimeType};base64,{Convert.ToBase64String(buffer.Array, 0, (int)stream.Length)}";
}
}
}
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..145b98b0f
--- /dev/null
+++ b/tests/ImageSharp.Benchmarks/General/BasicMath/ClampVector4.cs
@@ -0,0 +1,61 @@
+// Copyright (c) Six Labors and contributors.
+// Licensed under the Apache License, Version 2.0.
+
+using System.Numerics;
+using System.Runtime.CompilerServices;
+
+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));