diff --git a/src/ImageSharp/Common/Constants.cs b/src/ImageSharp/Common/Constants.cs
index fa2f72c74a..a3cfe3623f 100644
--- a/src/ImageSharp/Common/Constants.cs
+++ b/src/ImageSharp/Common/Constants.cs
@@ -1,6 +1,8 @@
-// Copyright (c) Six Labors.
+// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
+using System.Runtime.Intrinsics;
+
namespace SixLabors.ImageSharp;
///
@@ -13,6 +15,11 @@ internal static class Constants
///
public static readonly float Epsilon = 0.001F;
+ ///
+ /// The epsilon value for comparing floating point numbers.
+ ///
+ public static readonly Vector256 Epsilon256 = Vector256.Create(0.001F);
+
///
/// The epsilon squared value for comparing floating point numbers.
///
diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs b/src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs
index 4bc0040c67..128218aac2 100644
--- a/src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs
+++ b/src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs
@@ -532,7 +532,7 @@ internal static partial class SimdUtils
}
///
- /// Performs a multiplication and an addition of the .
+ /// Performs a multiplication and an addition of the .
///
/// ret = (vm0 * vm1) + va
/// The vector to add to the intermediate result.
@@ -549,22 +549,20 @@ internal static partial class SimdUtils
{
return Fma.MultiplyAdd(vm1, vm0, va);
}
- else
- {
- return Avx.Add(Avx.Multiply(vm0, vm1), va);
- }
+
+ return Avx.Add(Avx.Multiply(vm0, vm1), va);
}
///
- /// Performs a multiplication and a substraction of the .
+ /// Performs a multiplication and a subtraction of the .
///
/// ret = (vm0 * vm1) - vs
- /// The vector to substract from the intermediate result.
+ /// The vector to subtract from the intermediate result.
/// The first vector to multiply.
/// The second vector to multiply.
/// The .
[MethodImpl(InliningOptions.ShortMethod)]
- public static Vector256 MultiplySubstract(
+ public static Vector256 MultiplySubtract(
in Vector256 vs,
in Vector256 vm0,
in Vector256 vm1)
@@ -573,10 +571,8 @@ internal static partial class SimdUtils
{
return Fma.MultiplySubtract(vm1, vm0, vs);
}
- else
- {
- return Avx.Subtract(Avx.Multiply(vm0, vm1), vs);
- }
+
+ return Avx.Subtract(Avx.Multiply(vm0, vm1), vs);
}
///
diff --git a/src/ImageSharp/Formats/Jpeg/Components/FloatingPointDCT.Intrinsic.cs b/src/ImageSharp/Formats/Jpeg/Components/FloatingPointDCT.Intrinsic.cs
index cae89fc3cf..7e102f696d 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/FloatingPointDCT.Intrinsic.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/FloatingPointDCT.Intrinsic.cs
@@ -99,7 +99,7 @@ internal static partial class FloatingPointDCT
var mm256_F_1_4142 = Vector256.Create(1.414213562f);
Vector256 tmp13 = Avx.Add(tmp1, tmp3);
- Vector256 tmp12 = SimdUtils.HwIntrinsics.MultiplySubstract(tmp13, Avx.Subtract(tmp1, tmp3), mm256_F_1_4142);
+ Vector256 tmp12 = SimdUtils.HwIntrinsics.MultiplySubtract(tmp13, Avx.Subtract(tmp1, tmp3), mm256_F_1_4142);
tmp0 = Avx.Add(tmp10, tmp13);
tmp3 = Avx.Subtract(tmp10, tmp13);
diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.cs b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.cs
index 9bc7e35f30..d7d31c0c8b 100644
--- a/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.cs
+++ b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.cs
@@ -3,6 +3,8 @@
using System.Numerics;
using System.Runtime.CompilerServices;
+using System.Runtime.Intrinsics;
+using System.Runtime.Intrinsics.X86;
namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders;
@@ -27,9 +29,17 @@ internal static partial class PorterDuffFunctions
/// The .
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Normal(Vector4 backdrop, Vector4 source)
- {
- return source;
- }
+ => source;
+
+ ///
+ /// Returns the result of the "Normal" compositing equation.
+ ///
+ /// The backdrop vector.
+ /// The source vector.
+ /// The .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Vector256 Normal(Vector256 backdrop, Vector256 source)
+ => source;
///
/// Returns the result of the "Multiply" compositing equation.
@@ -39,9 +49,17 @@ internal static partial class PorterDuffFunctions
/// The .
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Multiply(Vector4 backdrop, Vector4 source)
- {
- return backdrop * source;
- }
+ => backdrop * source;
+
+ ///
+ /// Returns the result of the "Multiply" compositing equation.
+ ///
+ /// The backdrop vector.
+ /// The source vector.
+ /// The .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Vector256 Multiply(Vector256 backdrop, Vector256 source)
+ => Avx.Multiply(backdrop, source);
///
/// Returns the result of the "Add" compositing equation.
@@ -51,9 +69,17 @@ internal static partial class PorterDuffFunctions
/// The .
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Add(Vector4 backdrop, Vector4 source)
- {
- return Vector4.Min(Vector4.One, backdrop + source);
- }
+ => Vector4.Min(Vector4.One, backdrop + source);
+
+ ///
+ /// Returns the result of the "Add" compositing equation.
+ ///
+ /// The backdrop vector.
+ /// The source vector.
+ /// The .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Vector256 Add(Vector256 backdrop, Vector256 source)
+ => Avx.Min(Vector256.Create(1F), Avx.Add(backdrop, source));
///
/// Returns the result of the "Subtract" compositing equation.
@@ -63,9 +89,17 @@ internal static partial class PorterDuffFunctions
/// The .
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Subtract(Vector4 backdrop, Vector4 source)
- {
- return Vector4.Max(Vector4.Zero, backdrop - source);
- }
+ => Vector4.Max(Vector4.Zero, backdrop - source);
+
+ ///
+ /// Returns the result of the "Subtract" compositing equation.
+ ///
+ /// The backdrop vector.
+ /// The source vector.
+ /// The .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Vector256 Subtract(Vector256 backdrop, Vector256 source)
+ => Avx.Min(Vector256.Create(1F), Avx.Subtract(backdrop, source));
///
/// Returns the result of the "Screen" compositing equation.
@@ -75,8 +109,19 @@ internal static partial class PorterDuffFunctions
/// The .
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Screen(Vector4 backdrop, Vector4 source)
+ => Vector4.One - ((Vector4.One - backdrop) * (Vector4.One - source));
+
+ ///
+ /// Returns the result of the "Screen" compositing equation.
+ ///
+ /// The backdrop vector.
+ /// The source vector.
+ /// The .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Vector256 Screen(Vector256 backdrop, Vector256 source)
{
- return Vector4.One - ((Vector4.One - backdrop) * (Vector4.One - source));
+ Vector256 vOne = Vector256.Create(1F);
+ return Avx.Subtract(vOne, Avx.Multiply(Avx.Subtract(vOne, backdrop), Avx.Subtract(vOne, source)));
}
///
@@ -87,9 +132,17 @@ internal static partial class PorterDuffFunctions
/// The .
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Darken(Vector4 backdrop, Vector4 source)
- {
- return Vector4.Min(backdrop, source);
- }
+ => Vector4.Min(backdrop, source);
+
+ ///
+ /// Returns the result of the "Darken" compositing equation.
+ ///
+ /// The backdrop vector.
+ /// The source vector.
+ /// The .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Vector256 Darken(Vector256 backdrop, Vector256 source)
+ => Avx.Min(backdrop, source);
///
/// Returns the result of the "Lighten" compositing equation.
@@ -98,10 +151,17 @@ internal static partial class PorterDuffFunctions
/// The source vector.
/// The .
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Vector4 Lighten(Vector4 backdrop, Vector4 source)
- {
- return Vector4.Max(backdrop, source);
- }
+ public static Vector4 Lighten(Vector4 backdrop, Vector4 source) => Vector4.Max(backdrop, source);
+
+ ///
+ /// Returns the result of the "Lighten" compositing equation.
+ ///
+ /// The backdrop vector.
+ /// The source vector.
+ /// The .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Vector256 Lighten(Vector256 backdrop, Vector256 source)
+ => Avx.Max(backdrop, source);
///
/// Returns the result of the "Overlay" compositing equation.
@@ -136,16 +196,14 @@ internal static partial class PorterDuffFunctions
}
///
- /// Helper function for Overlay andHardLight modes
+ /// Helper function for Overlay and HardLight modes
///
/// Backdrop color element
/// Source color element
/// Overlay value
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static float OverlayValueFunction(float backdrop, float source)
- {
- return backdrop <= 0.5f ? (2 * backdrop * source) : 1 - (2 * (1 - source) * (1 - backdrop));
- }
+ => backdrop <= 0.5f ? (2 * backdrop * source) : 1 - (2 * (1 - source) * (1 - backdrop));
///
/// Returns the result of the "Over" compositing equation.
@@ -175,6 +233,40 @@ internal static partial class PorterDuffFunctions
return color;
}
+ ///
+ /// Returns the result of the "Over" compositing equation.
+ ///
+ /// The destination vector.
+ /// The source vector.
+ /// The amount to blend. Range 0..1
+ /// The .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Vector256 Over(Vector256 destination, Vector256 source, Vector256 blend)
+ {
+ const int blendAlphaControl = 0b_10_00_10_00;
+ const int shuffleAlphaControl = 0b_11_11_11_11;
+
+ // calculate weights
+ Vector256 sW = Avx.Shuffle(source, source, shuffleAlphaControl);
+ Vector256 dW = Avx.Shuffle(destination, destination, shuffleAlphaControl);
+ Vector256 blendW = Avx.Multiply(sW, dW);
+
+ Vector256 dstW = Avx.Subtract(dW, blendW);
+ Vector256 srcW = Avx.Subtract(sW, blendW);
+
+ // calculate final alpha
+ Vector256 alpha = Avx.Add(dstW, sW);
+
+ // calculate final color
+ Vector256 color = Avx.Multiply(destination, dstW);
+ color = SimdUtils.HwIntrinsics.MultiplyAdd(source, srcW, color);
+ color = SimdUtils.HwIntrinsics.MultiplyAdd(blend, blendW, color);
+
+ // unpremultiply
+ color = Avx.Divide(color, Avx.Max(alpha, Constants.Epsilon256));
+ return Avx.Blend(color, alpha, blendAlphaControl);
+ }
+
///
/// Returns the result of the "Atop" compositing equation.
///
@@ -202,6 +294,36 @@ internal static partial class PorterDuffFunctions
return color;
}
+ ///
+ /// Returns the result of the "Atop" compositing equation.
+ ///
+ /// The destination vector.
+ /// The source vector.
+ /// The amount to blend. Range 0..1
+ /// The .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Vector256 Atop(Vector256 destination, Vector256 source, Vector256 blend)
+ {
+ // calculate weights
+ const int blendAlphaControl = 0b_10_00_10_00;
+ const int shuffleAlphaControl = 0b_11_11_11_11;
+
+ // calculate final alpha
+ Vector256 alpha = Avx.Shuffle(destination, destination, shuffleAlphaControl);
+
+ // calculate weights
+ Vector256 sW = Avx.Shuffle(source, source, shuffleAlphaControl);
+ Vector256 blendW = Avx.Multiply(sW, alpha);
+ Vector256 dstW = Avx.Subtract(alpha, blendW);
+
+ // calculate final color
+ Vector256 color = SimdUtils.HwIntrinsics.MultiplyAdd(destination, dstW, Avx.Multiply(blend, blendW));
+
+ // unpremultiply
+ color = Avx.Divide(color, Avx.Max(alpha, Constants.Epsilon256));
+ return Avx.Blend(color, alpha, blendAlphaControl);
+ }
+
///
/// Returns the result of the "In" compositing equation.
///
@@ -220,6 +342,31 @@ internal static partial class PorterDuffFunctions
return color;
}
+ ///
+ /// Returns the result of the "In" compositing equation.
+ ///
+ /// The destination vector.
+ /// The source vector.
+ /// The .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Vector256 In(Vector256 destination, Vector256 source)
+ {
+ const int blendAlphaControl = 0b_10_00_10_00;
+ const int shuffleAlphaControl = 0b_11_11_11_11;
+
+ // calculate alpha
+ Vector256 sW = Avx.Shuffle(source, source, shuffleAlphaControl);
+ Vector256 dW = Avx.Shuffle(destination, destination, shuffleAlphaControl);
+ Vector256 alpha = Avx.Multiply(sW, dW);
+
+ // premultiply
+ Vector256 color = Avx.Multiply(source, alpha);
+
+ // unpremultiply
+ color = Avx.Divide(color, Avx.Max(alpha, Constants.Epsilon256));
+ return Avx.Blend(color, alpha, blendAlphaControl);
+ }
+
///
/// Returns the result of the "Out" compositing equation.
///
@@ -238,6 +385,31 @@ internal static partial class PorterDuffFunctions
return color;
}
+ ///
+ /// Returns the result of the "Out" compositing equation.
+ ///
+ /// The destination vector.
+ /// The source vector.
+ /// The .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Vector256 Out(Vector256 destination, Vector256 source)
+ {
+ const int blendAlphaControl = 0b_10_00_10_00;
+ const int shuffleAlphaControl = 0b_11_11_11_11;
+
+ // calculate alpha
+ Vector256 sW = Avx.Shuffle(source, source, shuffleAlphaControl);
+ Vector256 dW = Avx.Shuffle(destination, destination, shuffleAlphaControl);
+ Vector256 alpha = Avx.Multiply(Avx.Subtract(Vector256.Create(1F), dW), sW);
+
+ // premultiply
+ Vector256 color = Avx.Multiply(source, alpha);
+
+ // unpremultiply
+ color = Avx.Divide(color, Avx.Max(alpha, Constants.Epsilon256));
+ return Avx.Blend(color, alpha, blendAlphaControl);
+ }
+
///
/// Returns the result of the "XOr" compositing equation.
///
@@ -260,9 +432,38 @@ internal static partial class PorterDuffFunctions
return color;
}
+ ///
+ /// Returns the result of the "XOr" compositing equation.
+ ///
+ /// The destination vector.
+ /// The source vector.
+ /// The .
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static Vector4 Clear(Vector4 backdrop, Vector4 source)
+ public static Vector256 Xor(Vector256 destination, Vector256 source)
{
- return Vector4.Zero;
+ const int blendAlphaControl = 0b_10_00_10_00;
+ const int shuffleAlphaControl = 0b_11_11_11_11;
+
+ // calculate weights
+ Vector256 sW = Avx.Shuffle(source, source, shuffleAlphaControl);
+ Vector256 dW = Avx.Shuffle(destination, destination, shuffleAlphaControl);
+
+ Vector256 vOne = Vector256.Create(1F);
+ Vector256 srcW = Avx.Subtract(vOne, dW);
+ Vector256 dstW = Avx.Subtract(vOne, sW);
+
+ // calculate alpha
+ Vector256 alpha = SimdUtils.HwIntrinsics.MultiplyAdd(sW, srcW, Avx.Multiply(dW, dstW));
+ Vector256 color = SimdUtils.HwIntrinsics.MultiplyAdd(Avx.Multiply(sW, source), srcW, Avx.Multiply(Avx.Multiply(dW, destination), dstW));
+
+ // unpremultiply
+ color = Avx.Divide(color, Avx.Max(alpha, Constants.Epsilon256));
+ return Avx.Blend(color, alpha, blendAlphaControl);
}
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static Vector4 Clear(Vector4 backdrop, Vector4 source) => Vector4.Zero;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static Vector256 Clear(Vector256 backdrop, Vector256 source) => Vector256.Zero;
}