diff --git a/src/ImageSharp/Common/Helpers/Numerics.cs b/src/ImageSharp/Common/Helpers/Numerics.cs index 81cc4b5399..7ba60cfe57 100644 --- a/src/ImageSharp/Common/Helpers/Numerics.cs +++ b/src/ImageSharp/Common/Helpers/Numerics.cs @@ -474,21 +474,10 @@ internal static class Numerics [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Premultiply(ref Vector4 source) { - float w = source.W; - source *= w; - source.W = w; - } - - /// - /// Reverses the result of premultiplying a vector via . - /// - /// The to premultiply - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void UnPremultiply(ref Vector4 source) - { - float w = source.W; - source /= w; - source.W = w; + // Load into a local variable to prevent accessing the source from memory multiple times. + Vector4 src = source; + Vector4 alpha = PermuteW(src); + source = WithW(src * alpha, alpha); } /// @@ -498,7 +487,7 @@ internal static class Numerics [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Premultiply(Span vectors) { - if (Avx2.IsSupported && vectors.Length >= 2) + if (Avx.IsSupported && vectors.Length >= 2) { // Divide by 2 as 4 elements per Vector4 and 8 per Vector256 ref Vector256 vectorsBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(vectors)); @@ -507,8 +496,8 @@ internal static class Numerics while (Unsafe.IsAddressLessThan(ref vectorsBase, ref vectorsLast)) { Vector256 source = vectorsBase; - Vector256 multiply = Avx.Shuffle(source, source, ShuffleAlphaControl); - vectorsBase = Avx.Blend(Avx.Multiply(source, multiply), source, BlendAlphaControl); + Vector256 alpha = Avx.Permute(source, ShuffleAlphaControl); + vectorsBase = Avx.Blend(Avx.Multiply(source, alpha), source, BlendAlphaControl); vectorsBase = ref Unsafe.Add(ref vectorsBase, 1); } @@ -532,6 +521,30 @@ internal static class Numerics } } + /// + /// Reverses the result of premultiplying a vector via . + /// + /// The to premultiply + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void UnPremultiply(ref Vector4 source) + { + Vector4 alpha = PermuteW(source); + UnPremultiply(ref source, alpha); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void UnPremultiply(ref Vector4 source, Vector4 alpha) + { + if (alpha == Vector4.Zero) + { + return; + } + + // Divide source by alpha if alpha is nonzero, otherwise set all components to match the source value + // Blend the result with the alpha vector to ensure that the alpha component is unchanged + source = WithW(source / alpha, alpha); + } + /// /// Bulk variant of /// @@ -539,17 +552,18 @@ internal static class Numerics [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void UnPremultiply(Span vectors) { - if (Avx2.IsSupported && vectors.Length >= 2) + if (Avx.IsSupported && vectors.Length >= 2) { // Divide by 2 as 4 elements per Vector4 and 8 per Vector256 ref Vector256 vectorsBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(vectors)); ref Vector256 vectorsLast = ref Unsafe.Add(ref vectorsBase, (IntPtr)((uint)vectors.Length / 2u)); + Vector256 epsilon = Vector256.Create(Constants.Epsilon); while (Unsafe.IsAddressLessThan(ref vectorsBase, ref vectorsLast)) { Vector256 source = vectorsBase; - Vector256 multiply = Avx.Shuffle(source, source, ShuffleAlphaControl); - vectorsBase = Avx.Blend(Avx.Divide(source, multiply), source, BlendAlphaControl); + Vector256 alpha = Avx.Permute(source, ShuffleAlphaControl); + vectorsBase = UnPremultiply(source, alpha); vectorsBase = ref Unsafe.Add(ref vectorsBase, 1); } @@ -573,6 +587,61 @@ internal static class Numerics } } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector256 UnPremultiply(Vector256 source, Vector256 alpha) + { + // Check if alpha is zero to avoid division by zero + Vector256 zeroMask = Avx.CompareEqual(alpha, Vector256.Zero); + + // Divide source by alpha if alpha is nonzero, otherwise set all components to match the source value + Vector256 result = Avx.BlendVariable(Avx.Divide(source, alpha), source, zeroMask); + + // Blend the result with the alpha vector to ensure that the alpha component is unchanged + return Avx.Blend(result, alpha, BlendAlphaControl); + } + + /// + /// Permutes the given vector return a new instance with all the values set to . + /// + /// The vector. + /// The . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 PermuteW(Vector4 value) + { + if (Sse.IsSupported) + { + return Sse.Shuffle(value.AsVector128(), value.AsVector128(), ShuffleAlphaControl).AsVector4(); + } + + return new(value.W); + } + + /// + /// Sets the W component of the given vector to the given value from . + /// + /// The vector to set. + /// The vector containing the W value. + /// The . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 WithW(Vector4 value, Vector4 w) + { + if (Sse41.IsSupported) + { + return Sse41.Insert(value.AsVector128(), w.AsVector128(), 0b11_11_0000).AsVector4(); + } + + if (Sse.IsSupported) + { + // Create tmp as + // Then return (which is ) + Vector128 tmp = Sse.Shuffle(w.AsVector128(), value.AsVector128(), 0b00_10_00_11); + return Sse.Shuffle(value.AsVector128(), tmp, 0b00_10_01_00).AsVector4(); + } + + value.W = w.W; + return value; + } + /// /// Calculates the cube pow of all the XYZ channels of the input vectors. /// @@ -586,7 +655,7 @@ internal static class Numerics while (Unsafe.IsAddressLessThan(ref baseRef, ref endRef)) { Vector4 v = baseRef; - float a = v.W; + Vector4 a = PermuteW(v); // Fast path for the default gamma exposure, which is 3. In this case we can skip // calling Math.Pow 3 times (one per component), as the method is an internal call and @@ -595,7 +664,7 @@ internal static class Numerics // back to the target index in the temporary span. The whole iteration will get completely // inlined and traslated into vectorized instructions, with much better performance. v = v * v * v; - v.W = a; + v = WithW(v, a); baseRef = v; baseRef = ref Unsafe.Add(ref baseRef, 1); diff --git a/src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs b/src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs index 345f4b5c2e..9b73eb6ccf 100644 --- a/src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs +++ b/src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs @@ -47,10 +47,7 @@ internal interface IShuffle4 : IComponentShuffle internal readonly struct DefaultShuffle4 : IShuffle4 { public DefaultShuffle4(byte control) - { - DebugGuard.MustBeBetweenOrEqualTo(control, 0, 3, nameof(control)); - this.Control = control; - } + => this.Control = control; public byte Control { get; } diff --git a/src/ImageSharp/Common/Helpers/Shuffle/IPad3Shuffle4.cs b/src/ImageSharp/Common/Helpers/Shuffle/IPad3Shuffle4.cs index 348e8ec010..5dfdd91718 100644 --- a/src/ImageSharp/Common/Helpers/Shuffle/IPad3Shuffle4.cs +++ b/src/ImageSharp/Common/Helpers/Shuffle/IPad3Shuffle4.cs @@ -15,10 +15,7 @@ internal interface IPad3Shuffle4 : IComponentShuffle internal readonly struct DefaultPad3Shuffle4 : IPad3Shuffle4 { public DefaultPad3Shuffle4(byte control) - { - DebugGuard.MustBeBetweenOrEqualTo(control, 0, 3, nameof(control)); - this.Control = control; - } + => this.Control = control; public byte Control { get; } diff --git a/src/ImageSharp/Common/Helpers/Shuffle/IShuffle3.cs b/src/ImageSharp/Common/Helpers/Shuffle/IShuffle3.cs index 6ac8a2428a..6bf8c5f03d 100644 --- a/src/ImageSharp/Common/Helpers/Shuffle/IShuffle3.cs +++ b/src/ImageSharp/Common/Helpers/Shuffle/IShuffle3.cs @@ -15,10 +15,7 @@ internal interface IShuffle3 : IComponentShuffle internal readonly struct DefaultShuffle3 : IShuffle3 { public DefaultShuffle3(byte control) - { - DebugGuard.MustBeBetweenOrEqualTo(control, 0, 3, nameof(control)); - this.Control = control; - } + => this.Control = control; public byte Control { get; } diff --git a/src/ImageSharp/Common/Helpers/Shuffle/IShuffle4Slice3.cs b/src/ImageSharp/Common/Helpers/Shuffle/IShuffle4Slice3.cs index d4a5e8130a..ef46661f5f 100644 --- a/src/ImageSharp/Common/Helpers/Shuffle/IShuffle4Slice3.cs +++ b/src/ImageSharp/Common/Helpers/Shuffle/IShuffle4Slice3.cs @@ -15,10 +15,7 @@ internal interface IShuffle4Slice3 : IComponentShuffle internal readonly struct DefaultShuffle4Slice3 : IShuffle4Slice3 { public DefaultShuffle4Slice3(byte control) - { - DebugGuard.MustBeBetweenOrEqualTo(control, 0, 3, nameof(control)); - this.Control = control; - } + => this.Control = control; public byte Control { get; } diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.cs b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.cs index bd522da192..e7cf3b2921 100644 --- a/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.cs @@ -23,7 +23,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 NormalSrc(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return source; } @@ -49,7 +49,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 NormalSrcAtop(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Atop(backdrop, source, Normal(backdrop, source)); } @@ -79,7 +79,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 NormalSrcOver(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Over(backdrop, source, Normal(backdrop, source)); } @@ -109,7 +109,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 NormalSrcIn(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return In(backdrop, source); } @@ -135,7 +135,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 NormalSrcOut(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Out(backdrop, source); } @@ -187,7 +187,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 NormalDestAtop(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Atop(source, backdrop, Normal(source, backdrop)); } @@ -217,7 +217,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 NormalDestOver(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Over(source, backdrop, Normal(source, backdrop)); } @@ -247,7 +247,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 NormalDestIn(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return In(source, backdrop); } @@ -273,7 +273,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 NormalDestOut(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Out(source, backdrop); } @@ -299,7 +299,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 NormalXor(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Xor(backdrop, source); } @@ -325,7 +325,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 NormalClear(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Clear(backdrop, source); } @@ -568,7 +568,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 MultiplySrc(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return source; } @@ -594,7 +594,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 MultiplySrcAtop(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Atop(backdrop, source, Multiply(backdrop, source)); } @@ -624,7 +624,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 MultiplySrcOver(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Over(backdrop, source, Multiply(backdrop, source)); } @@ -654,7 +654,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 MultiplySrcIn(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return In(backdrop, source); } @@ -680,7 +680,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 MultiplySrcOut(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Out(backdrop, source); } @@ -732,7 +732,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 MultiplyDestAtop(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Atop(source, backdrop, Multiply(source, backdrop)); } @@ -762,7 +762,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 MultiplyDestOver(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Over(source, backdrop, Multiply(source, backdrop)); } @@ -792,7 +792,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 MultiplyDestIn(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return In(source, backdrop); } @@ -818,7 +818,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 MultiplyDestOut(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Out(source, backdrop); } @@ -844,7 +844,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 MultiplyXor(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Xor(backdrop, source); } @@ -870,7 +870,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 MultiplyClear(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Clear(backdrop, source); } @@ -1113,7 +1113,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 AddSrc(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return source; } @@ -1139,7 +1139,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 AddSrcAtop(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Atop(backdrop, source, Add(backdrop, source)); } @@ -1169,7 +1169,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 AddSrcOver(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Over(backdrop, source, Add(backdrop, source)); } @@ -1199,7 +1199,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 AddSrcIn(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return In(backdrop, source); } @@ -1225,7 +1225,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 AddSrcOut(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Out(backdrop, source); } @@ -1277,7 +1277,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 AddDestAtop(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Atop(source, backdrop, Add(source, backdrop)); } @@ -1307,7 +1307,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 AddDestOver(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Over(source, backdrop, Add(source, backdrop)); } @@ -1337,7 +1337,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 AddDestIn(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return In(source, backdrop); } @@ -1363,7 +1363,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 AddDestOut(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Out(source, backdrop); } @@ -1389,7 +1389,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 AddXor(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Xor(backdrop, source); } @@ -1415,7 +1415,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 AddClear(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Clear(backdrop, source); } @@ -1658,7 +1658,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 SubtractSrc(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return source; } @@ -1684,7 +1684,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 SubtractSrcAtop(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Atop(backdrop, source, Subtract(backdrop, source)); } @@ -1714,7 +1714,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 SubtractSrcOver(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Over(backdrop, source, Subtract(backdrop, source)); } @@ -1744,7 +1744,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 SubtractSrcIn(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return In(backdrop, source); } @@ -1770,7 +1770,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 SubtractSrcOut(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Out(backdrop, source); } @@ -1822,7 +1822,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 SubtractDestAtop(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Atop(source, backdrop, Subtract(source, backdrop)); } @@ -1852,7 +1852,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 SubtractDestOver(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Over(source, backdrop, Subtract(source, backdrop)); } @@ -1882,7 +1882,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 SubtractDestIn(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return In(source, backdrop); } @@ -1908,7 +1908,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 SubtractDestOut(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Out(source, backdrop); } @@ -1934,7 +1934,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 SubtractXor(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Xor(backdrop, source); } @@ -1960,7 +1960,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 SubtractClear(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Clear(backdrop, source); } @@ -2203,7 +2203,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 ScreenSrc(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return source; } @@ -2229,7 +2229,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 ScreenSrcAtop(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Atop(backdrop, source, Screen(backdrop, source)); } @@ -2259,7 +2259,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 ScreenSrcOver(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Over(backdrop, source, Screen(backdrop, source)); } @@ -2289,7 +2289,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 ScreenSrcIn(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return In(backdrop, source); } @@ -2315,7 +2315,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 ScreenSrcOut(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Out(backdrop, source); } @@ -2367,7 +2367,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 ScreenDestAtop(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Atop(source, backdrop, Screen(source, backdrop)); } @@ -2397,7 +2397,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 ScreenDestOver(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Over(source, backdrop, Screen(source, backdrop)); } @@ -2427,7 +2427,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 ScreenDestIn(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return In(source, backdrop); } @@ -2453,7 +2453,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 ScreenDestOut(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Out(source, backdrop); } @@ -2479,7 +2479,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 ScreenXor(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Xor(backdrop, source); } @@ -2505,7 +2505,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 ScreenClear(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Clear(backdrop, source); } @@ -2748,7 +2748,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 DarkenSrc(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return source; } @@ -2774,7 +2774,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 DarkenSrcAtop(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Atop(backdrop, source, Darken(backdrop, source)); } @@ -2804,7 +2804,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 DarkenSrcOver(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Over(backdrop, source, Darken(backdrop, source)); } @@ -2834,7 +2834,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 DarkenSrcIn(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return In(backdrop, source); } @@ -2860,7 +2860,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 DarkenSrcOut(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Out(backdrop, source); } @@ -2912,7 +2912,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 DarkenDestAtop(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Atop(source, backdrop, Darken(source, backdrop)); } @@ -2942,7 +2942,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 DarkenDestOver(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Over(source, backdrop, Darken(source, backdrop)); } @@ -2972,7 +2972,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 DarkenDestIn(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return In(source, backdrop); } @@ -2998,7 +2998,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 DarkenDestOut(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Out(source, backdrop); } @@ -3024,7 +3024,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 DarkenXor(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Xor(backdrop, source); } @@ -3050,7 +3050,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 DarkenClear(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Clear(backdrop, source); } @@ -3293,7 +3293,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 LightenSrc(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return source; } @@ -3319,7 +3319,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 LightenSrcAtop(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Atop(backdrop, source, Lighten(backdrop, source)); } @@ -3349,7 +3349,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 LightenSrcOver(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Over(backdrop, source, Lighten(backdrop, source)); } @@ -3379,7 +3379,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 LightenSrcIn(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return In(backdrop, source); } @@ -3405,7 +3405,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 LightenSrcOut(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Out(backdrop, source); } @@ -3457,7 +3457,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 LightenDestAtop(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Atop(source, backdrop, Lighten(source, backdrop)); } @@ -3487,7 +3487,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 LightenDestOver(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Over(source, backdrop, Lighten(source, backdrop)); } @@ -3517,7 +3517,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 LightenDestIn(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return In(source, backdrop); } @@ -3543,7 +3543,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 LightenDestOut(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Out(source, backdrop); } @@ -3569,7 +3569,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 LightenXor(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Xor(backdrop, source); } @@ -3595,7 +3595,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 LightenClear(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Clear(backdrop, source); } @@ -3838,7 +3838,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 OverlaySrc(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return source; } @@ -3864,7 +3864,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 OverlaySrcAtop(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Atop(backdrop, source, Overlay(backdrop, source)); } @@ -3894,7 +3894,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 OverlaySrcOver(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Over(backdrop, source, Overlay(backdrop, source)); } @@ -3924,7 +3924,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 OverlaySrcIn(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return In(backdrop, source); } @@ -3950,7 +3950,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 OverlaySrcOut(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Out(backdrop, source); } @@ -4002,7 +4002,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 OverlayDestAtop(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Atop(source, backdrop, Overlay(source, backdrop)); } @@ -4032,7 +4032,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 OverlayDestOver(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Over(source, backdrop, Overlay(source, backdrop)); } @@ -4062,7 +4062,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 OverlayDestIn(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return In(source, backdrop); } @@ -4088,7 +4088,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 OverlayDestOut(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Out(source, backdrop); } @@ -4114,7 +4114,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 OverlayXor(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Xor(backdrop, source); } @@ -4140,7 +4140,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 OverlayClear(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Clear(backdrop, source); } @@ -4383,7 +4383,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 HardLightSrc(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return source; } @@ -4409,7 +4409,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 HardLightSrcAtop(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Atop(backdrop, source, HardLight(backdrop, source)); } @@ -4439,7 +4439,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 HardLightSrcOver(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Over(backdrop, source, HardLight(backdrop, source)); } @@ -4469,7 +4469,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 HardLightSrcIn(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return In(backdrop, source); } @@ -4495,7 +4495,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 HardLightSrcOut(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Out(backdrop, source); } @@ -4547,7 +4547,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 HardLightDestAtop(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Atop(source, backdrop, HardLight(source, backdrop)); } @@ -4577,7 +4577,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 HardLightDestOver(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Over(source, backdrop, HardLight(source, backdrop)); } @@ -4607,7 +4607,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 HardLightDestIn(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return In(source, backdrop); } @@ -4633,7 +4633,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 HardLightDestOut(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Out(source, backdrop); } @@ -4659,7 +4659,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 HardLightXor(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Xor(backdrop, source); } @@ -4685,7 +4685,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 HardLightClear(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Clear(backdrop, source); } diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.tt b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.tt index 69dac875c3..64eee502bb 100644 --- a/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.tt @@ -33,7 +33,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 <#=blender#>Src(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return source; } @@ -59,7 +59,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 <#=blender#>SrcAtop(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Atop(backdrop, source, <#=blender#>(backdrop, source)); } @@ -89,7 +89,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 <#=blender#>SrcOver(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Over(backdrop, source, <#=blender#>(backdrop, source)); } @@ -119,7 +119,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 <#=blender#>SrcIn(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return In(backdrop, source); } @@ -145,7 +145,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 <#=blender#>SrcOut(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Out(backdrop, source); } @@ -197,7 +197,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 <#=blender#>DestAtop(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Atop(source, backdrop, <#=blender#>(source, backdrop)); } @@ -227,7 +227,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 <#=blender#>DestOver(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Over(source, backdrop, <#=blender#>(source, backdrop)); } @@ -257,7 +257,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 <#=blender#>DestIn(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return In(source, backdrop); } @@ -283,7 +283,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 <#=blender#>DestOut(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Out(source, backdrop); } @@ -309,7 +309,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 <#=blender#>Xor(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Xor(backdrop, source); } @@ -335,7 +335,7 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 <#=blender#>Clear(Vector4 backdrop, Vector4 source, float opacity) { - source = WithW(source, source * opacity); + source = Numerics.WithW(source, source * opacity); return Clear(backdrop, source); } diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.cs b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.cs index baf7d80c0a..ca358be31c 100644 --- a/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.cs +++ b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.cs @@ -263,8 +263,8 @@ internal static partial class PorterDuffFunctions public static Vector4 Over(Vector4 destination, Vector4 source, Vector4 blend) { // calculate weights - Vector4 sW = PermuteW(source); - Vector4 dW = PermuteW(destination); + Vector4 sW = Numerics.PermuteW(source); + Vector4 dW = Numerics.PermuteW(destination); Vector4 blendW = sW * dW; Vector4 dstW = dW - blendW; @@ -277,8 +277,8 @@ internal static partial class PorterDuffFunctions Vector4 color = (destination * dstW) + (source * srcW) + (blend * blendW); // unpremultiply - color /= Vector4.Max(alpha, new(Constants.Epsilon)); - return WithW(color, alpha); + Numerics.UnPremultiply(ref color, alpha); + return color; } /// @@ -308,8 +308,7 @@ internal static partial class PorterDuffFunctions color = SimdUtils.HwIntrinsics.MultiplyAdd(color, blend, blendW); // unpremultiply - color = Avx.Divide(color, Avx.Max(alpha, Vector256.Create(Constants.Epsilon))); - return Avx.Blend(color, alpha, BlendAlphaControl); + return Numerics.UnPremultiply(color, alpha); } /// @@ -323,8 +322,8 @@ internal static partial class PorterDuffFunctions public static Vector4 Atop(Vector4 destination, Vector4 source, Vector4 blend) { // calculate weights - Vector4 sW = PermuteW(source); - Vector4 dW = PermuteW(destination); + Vector4 sW = Numerics.PermuteW(source); + Vector4 dW = Numerics.PermuteW(destination); Vector4 blendW = sW * dW; Vector4 dstW = dW - blendW; @@ -336,8 +335,8 @@ internal static partial class PorterDuffFunctions Vector4 color = (destination * dstW) + (blend * blendW); // unpremultiply - color /= Vector4.Max(alpha, new(Constants.Epsilon)); - return WithW(color, alpha); + Numerics.UnPremultiply(ref color, alpha); + return color; } /// @@ -362,8 +361,7 @@ internal static partial class PorterDuffFunctions Vector256 color = SimdUtils.HwIntrinsics.MultiplyAdd(Avx.Multiply(blend, blendW), destination, dstW); // unpremultiply - color = Avx.Divide(color, Avx.Max(alpha, Vector256.Create(Constants.Epsilon))); - return Avx.Blend(color, alpha, BlendAlphaControl); + return Numerics.UnPremultiply(color, alpha); } /// @@ -375,13 +373,13 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 In(Vector4 destination, Vector4 source) { - Vector4 sW = PermuteW(source); - Vector4 dW = PermuteW(destination); + Vector4 sW = Numerics.PermuteW(source); + Vector4 dW = Numerics.PermuteW(destination); Vector4 alpha = dW * sW; - Vector4 color = source * alpha; // premultiply - color /= Vector4.Max(alpha, new(Constants.Epsilon)); // unpremultiply - return WithW(color, alpha); + Vector4 color = source * alpha; // premultiply + Numerics.UnPremultiply(ref color, alpha); // unpremultiply + return color; } /// @@ -400,8 +398,7 @@ internal static partial class PorterDuffFunctions Vector256 color = Avx.Multiply(source, alpha); // unpremultiply - color = Avx.Divide(color, Avx.Max(alpha, Vector256.Create(Constants.Epsilon))); - return Avx.Blend(color, alpha, BlendAlphaControl); + return Numerics.UnPremultiply(color, alpha); } /// @@ -413,13 +410,13 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 Out(Vector4 destination, Vector4 source) { - Vector4 sW = PermuteW(source); - Vector4 dW = PermuteW(destination); + Vector4 sW = Numerics.PermuteW(source); + Vector4 dW = Numerics.PermuteW(destination); Vector4 alpha = (Vector4.One - dW) * sW; - Vector4 color = source * alpha; // premultiply - color /= Vector4.Max(alpha, new(Constants.Epsilon)); // unpremultiply - return WithW(color, alpha); + Vector4 color = source * alpha; // premultiply + Numerics.UnPremultiply(ref color, alpha); // unpremultiply + return color; } /// @@ -438,8 +435,7 @@ internal static partial class PorterDuffFunctions Vector256 color = Avx.Multiply(source, alpha); // unpremultiply - color = Avx.Divide(color, Avx.Max(alpha, Vector256.Create(Constants.Epsilon))); - return Avx.Blend(color, alpha, BlendAlphaControl); + return Numerics.UnPremultiply(color, alpha); } /// @@ -451,8 +447,8 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 Xor(Vector4 destination, Vector4 source) { - Vector4 sW = PermuteW(source); - Vector4 dW = PermuteW(destination); + Vector4 sW = Numerics.PermuteW(source); + Vector4 dW = Numerics.PermuteW(destination); Vector4 srcW = Vector4.One - dW; Vector4 dstW = Vector4.One - sW; @@ -461,8 +457,8 @@ internal static partial class PorterDuffFunctions Vector4 color = (sW * source * srcW) + (dW * destination * dstW); // unpremultiply - color /= Vector4.Max(alpha, new(Constants.Epsilon)); - return WithW(color, alpha); + Numerics.UnPremultiply(ref color, alpha); + return color; } /// @@ -487,8 +483,7 @@ internal static partial class PorterDuffFunctions Vector256 color = SimdUtils.HwIntrinsics.MultiplyAdd(Avx.Multiply(Avx.Multiply(dW, destination), dstW), Avx.Multiply(sW, source), srcW); // unpremultiply - color = Avx.Divide(color, Avx.Max(alpha, Vector256.Create(Constants.Epsilon))); - return Avx.Blend(color, alpha, BlendAlphaControl); + return Numerics.UnPremultiply(color, alpha); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -496,35 +491,4 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] private static Vector256 Clear(Vector256 backdrop, Vector256 source) => Vector256.Zero; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static Vector4 WithW(Vector4 value, Vector4 w) - { - if (Sse41.IsSupported) - { - return Sse41.Insert(value.AsVector128(), w.AsVector128(), 0b11_11_0000).AsVector4(); - } - - if (Sse.IsSupported) - { - // Create tmp as - // Then return (which is ) - Vector128 tmp = Sse.Shuffle(w.AsVector128(), value.AsVector128(), 0b00_10_00_11); - return Sse.Shuffle(value.AsVector128(), tmp, 0b00_10_01_00).AsVector4(); - } - - value.W = w.W; - return value; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static Vector4 PermuteW(Vector4 value) - { - if (Sse.IsSupported) - { - return Sse.Shuffle(value.AsVector128(), value.AsVector128(), 0b11111111).AsVector4(); - } - - return new(value.W); - } } diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/PremultiplyVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/PremultiplyVector4.cs index d30693c6c7..44496a2496 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/PremultiplyVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/PremultiplyVector4.cs @@ -8,7 +8,6 @@ using BenchmarkDotNet.Attributes; namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk; -[Config(typeof(Config.ShortCore31))] public class PremultiplyVector4 { private static readonly Vector4[] Vectors = CreateVectors(); @@ -28,9 +27,18 @@ public class PremultiplyVector4 [Benchmark] public void Premultiply() { - Numerics.Premultiply(Vectors); + ref Vector4 baseRef = ref MemoryMarshal.GetReference(Vectors); + + for (int i = 0; i < Vectors.Length; i++) + { + ref Vector4 v = ref Unsafe.Add(ref baseRef, i); + Numerics.Premultiply(ref v); + } } + [Benchmark] + public void PremultiplyBulk() => Numerics.Premultiply(Vectors); + [MethodImpl(InliningOptions.ShortMethod)] private static void Premultiply(ref Vector4 source) { @@ -41,13 +49,13 @@ public class PremultiplyVector4 private static Vector4[] CreateVectors() { - var rnd = new Random(42); + Random rnd = new(42); return GenerateRandomVectorArray(rnd, 2048, 0, 1); } private static Vector4[] GenerateRandomVectorArray(Random rnd, int length, float minVal, float maxVal) { - var values = new Vector4[length]; + Vector4[] values = new Vector4[length]; for (int i = 0; i < length; i++) { diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/Shuffle3Channel.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/Shuffle3Channel.cs index 9bd85f4743..fcde0ea1bd 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/Shuffle3Channel.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/Shuffle3Channel.cs @@ -1,9 +1,7 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using System.Runtime.InteropServices; using BenchmarkDotNet.Attributes; -using Iced.Intel; namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk; diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/Shuffle4Slice3Channel.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/Shuffle4Slice3Channel.cs index f0890221c8..ef01185f91 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/Shuffle4Slice3Channel.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/Shuffle4Slice3Channel.cs @@ -1,9 +1,7 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using System.Runtime.InteropServices; using BenchmarkDotNet.Attributes; -using Iced.Intel; namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk; diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/UnPremultiplyVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/UnPremultiplyVector4.cs index ea36a341fc..c2b371b8a5 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/UnPremultiplyVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/UnPremultiplyVector4.cs @@ -8,7 +8,6 @@ using BenchmarkDotNet.Attributes; namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk; -[Config(typeof(Config.ShortCore31))] public class UnPremultiplyVector4 { private static readonly Vector4[] Vectors = CreateVectors(); @@ -21,6 +20,7 @@ public class UnPremultiplyVector4 for (int i = 0; i < Vectors.Length; i++) { ref Vector4 v = ref Unsafe.Add(ref baseRef, i); + UnPremultiply(ref v); } } @@ -28,9 +28,18 @@ public class UnPremultiplyVector4 [Benchmark] public void UnPremultiply() { - Numerics.UnPremultiply(Vectors); + ref Vector4 baseRef = ref MemoryMarshal.GetReference(Vectors); + + for (int i = 0; i < Vectors.Length; i++) + { + ref Vector4 v = ref Unsafe.Add(ref baseRef, i); + Numerics.UnPremultiply(ref v); + } } + [Benchmark] + public void UnPremultiplyBulk() => Numerics.UnPremultiply(Vectors); + [MethodImpl(InliningOptions.ShortMethod)] private static void UnPremultiply(ref Vector4 source) { @@ -41,13 +50,13 @@ public class UnPremultiplyVector4 private static Vector4[] CreateVectors() { - var rnd = new Random(42); + Random rnd = new(42); return GenerateRandomVectorArray(rnd, 2048, 0, 1); } private static Vector4[] GenerateRandomVectorArray(Random rnd, int length, float minVal, float maxVal) { - var values = new Vector4[length]; + Vector4[] values = new Vector4[length]; for (int i = 0; i < length; i++) { diff --git a/tests/ImageSharp.Benchmarks/PixelBlenders/PorterDuffBulkVsPixel.cs b/tests/ImageSharp.Benchmarks/PixelBlenders/PorterDuffBulkVsPixel.cs index 3e6667dbc2..a308c0c468 100644 --- a/tests/ImageSharp.Benchmarks/PixelBlenders/PorterDuffBulkVsPixel.cs +++ b/tests/ImageSharp.Benchmarks/PixelBlenders/PorterDuffBulkVsPixel.cs @@ -60,7 +60,7 @@ public class PorterDuffBulkVsPixel } [Benchmark(Description = "ImageSharp BulkVectorConvert")] - public static Size BulkVectorConvert() + public Size BulkVectorConvert() { using Image image = new(800, 800); using IMemoryOwner amounts = Configuration.Default.MemoryAllocator.Allocate(image.Width); @@ -77,7 +77,7 @@ public class PorterDuffBulkVsPixel } [Benchmark(Description = "ImageSharp BulkPixelConvert")] - public static Size BulkPixelConvert() + public Size BulkPixelConvert() { using Image image = new(800, 800); using IMemoryOwner amounts = Configuration.Default.MemoryAllocator.Allocate(image.Width); diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs index 75e7d39091..0c35008658 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs @@ -12,6 +12,10 @@ using static SixLabors.ImageSharp.Tests.TestImages.Tiff; namespace SixLabors.ImageSharp.Tests.Formats.Tiff; +// Several of the tests in this class comparing images with associated alpha encoding use a high tolerance for comparison. +// This is due to an issue in the reference decoder where it is not correctly checking for a zero alpha component value +// before unpremultying the encoded values. This can lead to incorrect values when the rgb channels contain non-zero values. +// The tests should be manually verified following any changes to the decoder. [Trait("Format", "Tiff")] [ValidateDisposedMemoryAllocations] public class TiffDecoderTests : TiffDecoderBaseTester @@ -205,8 +209,7 @@ public class TiffDecoderTests : TiffDecoderBaseTester return; } - // Note: Using tolerant comparer here, because there is a small difference to the reference decoder probably due to floating point rounding issues. - TestTiffDecoder(provider, useExactComparer: false); + TestTiffDecoder(provider, useExactComparer: false, compareTolerance: 0.264F); } [Theory] @@ -262,8 +265,7 @@ public class TiffDecoderTests : TiffDecoderBaseTester return; } - // Note: Using tolerant comparer here, because there is a small difference to the reference decoder probably due to floating point rounding issues. - TestTiffDecoder(provider, useExactComparer: false); + TestTiffDecoder(provider, useExactComparer: false, compareTolerance: 0.376F); } [Theory] @@ -289,8 +291,7 @@ public class TiffDecoderTests : TiffDecoderBaseTester return; } - // Note: Using tolerant comparer here, because there is a small difference to the reference decoder probably due to floating point rounding issues. - TestTiffDecoder(provider, useExactComparer: false); + TestTiffDecoder(provider, useExactComparer: false, compareTolerance: 0.405F); } [Theory] @@ -431,8 +432,7 @@ public class TiffDecoderTests : TiffDecoderBaseTester return; } - // Note: Using tolerant comparer here, because there is a small difference to the reference decoder probably due to floating point rounding issues. - TestTiffDecoder(provider, useExactComparer: false); + TestTiffDecoder(provider, useExactComparer: false, compareTolerance: 0.247F); } [Theory] @@ -470,8 +470,7 @@ public class TiffDecoderTests : TiffDecoderBaseTester return; } - // Note: Using tolerant comparer here, because there is a small difference to the reference decoder probably due to floating point rounding issues. - TestTiffDecoder(provider, useExactComparer: false, compareTolerance: 0.0002f); + TestTiffDecoder(provider, useExactComparer: false, compareTolerance: 0.118F); } [Theory] @@ -500,8 +499,7 @@ public class TiffDecoderTests : TiffDecoderBaseTester return; } - // Note: Using tolerant comparer here, because there is a small difference to the reference decoder probably due to floating point rounding issues. - TestTiffDecoder(provider, useExactComparer: false, compareTolerance: 0.0002f); + TestTiffDecoder(provider, useExactComparer: false, compareTolerance: 0.075F); } [Theory] diff --git a/tests/Images/External/ReferenceOutput/PorterDuffCompositorTests/PorterDuffOutputIsCorrect_Rgba32_pd-dest_DestOut.png b/tests/Images/External/ReferenceOutput/PorterDuffCompositorTests/PorterDuffOutputIsCorrect_Rgba32_pd-dest_DestOut.png index bd50175d7c..ebd022edbf 100644 --- a/tests/Images/External/ReferenceOutput/PorterDuffCompositorTests/PorterDuffOutputIsCorrect_Rgba32_pd-dest_DestOut.png +++ b/tests/Images/External/ReferenceOutput/PorterDuffCompositorTests/PorterDuffOutputIsCorrect_Rgba32_pd-dest_DestOut.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2952981bde801d566e5b7503722907b2f4318b71c327276735e929d9f598ffc0 -size 1707 +oid sha256:9562915ef66d9ca6a42108cae51ad08fa711dddc79aaedad2c4be83bd8c38534 +size 1952 diff --git a/tests/Images/External/ReferenceOutput/PorterDuffCompositorTests/PorterDuffOutputIsCorrect_Rgba32_pd-dest_In.png b/tests/Images/External/ReferenceOutput/PorterDuffCompositorTests/PorterDuffOutputIsCorrect_Rgba32_pd-dest_In.png index 265985c3f2..4dcb0c4294 100644 --- a/tests/Images/External/ReferenceOutput/PorterDuffCompositorTests/PorterDuffOutputIsCorrect_Rgba32_pd-dest_In.png +++ b/tests/Images/External/ReferenceOutput/PorterDuffCompositorTests/PorterDuffOutputIsCorrect_Rgba32_pd-dest_In.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:de9b2fbf7dce7980ade102386aa070c48a31ee32807a13a28b4e172c0fc26a16 -size 1561 +oid sha256:dfb99359c216d5aee6eabed9f549c406e3b18f50fb255db2a936cba217888cd0 +size 1740 diff --git a/tests/Images/External/ReferenceOutput/PorterDuffCompositorTests/PorterDuffOutputIsCorrect_Rgba32_pd-dest_Out.png b/tests/Images/External/ReferenceOutput/PorterDuffCompositorTests/PorterDuffOutputIsCorrect_Rgba32_pd-dest_Out.png index 8cdaf949d2..44c0a812a3 100644 --- a/tests/Images/External/ReferenceOutput/PorterDuffCompositorTests/PorterDuffOutputIsCorrect_Rgba32_pd-dest_Out.png +++ b/tests/Images/External/ReferenceOutput/PorterDuffCompositorTests/PorterDuffOutputIsCorrect_Rgba32_pd-dest_Out.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3effcb28b17363a5ee26d38d55f7354e1e9499824863cb389a1b002c18ad3644 -size 2099 +oid sha256:d2049fbfdebb20807ea1d402e1a0b8c8bed0995d16900f5739ad0db5d2acd501 +size 2273