From 746b34d46f52b13e6bab922899ba8825ab23b5b5 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sun, 19 Feb 2023 13:22:00 +1000 Subject: [PATCH] Finish porting function components --- .../PixelBlenders/PorterDuffFunctions.cs | 110 +++++++++++------- 1 file changed, 69 insertions(+), 41 deletions(-) diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.cs b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.cs index d7d31c0c8b..551f17f209 100644 --- a/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.cs +++ b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.cs @@ -21,6 +21,12 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders; /// internal static partial class PorterDuffFunctions { + private const int BlendAlphaControl = 0b_10_00_10_00; + private const int ShuffleAlphaControl = 0b_11_11_11_11; + private static readonly Vector256 Vector256Half = Vector256.Create(0.5F); + private static readonly Vector256 Vector256One = Vector256.Create(1F); + private static readonly Vector256 Vector256Two = Vector256.Create(2F); + /// /// Returns the result of the "Normal" compositing equation. /// @@ -79,7 +85,7 @@ internal static partial class PorterDuffFunctions /// The . [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector256 Add(Vector256 backdrop, Vector256 source) - => Avx.Min(Vector256.Create(1F), Avx.Add(backdrop, source)); + => Avx.Min(Vector256One, Avx.Add(backdrop, source)); /// /// Returns the result of the "Subtract" compositing equation. @@ -99,7 +105,7 @@ internal static partial class PorterDuffFunctions /// The . [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector256 Subtract(Vector256 backdrop, Vector256 source) - => Avx.Min(Vector256.Create(1F), Avx.Subtract(backdrop, source)); + => Avx.Min(Vector256One, Avx.Subtract(backdrop, source)); /// /// Returns the result of the "Screen" compositing equation. @@ -119,10 +125,7 @@ internal static partial class PorterDuffFunctions /// The . [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector256 Screen(Vector256 backdrop, Vector256 source) - { - Vector256 vOne = Vector256.Create(1F); - return Avx.Subtract(vOne, Avx.Multiply(Avx.Subtract(vOne, backdrop), Avx.Subtract(vOne, source))); - } + => Avx.Subtract(Vector256One, Avx.Multiply(Avx.Subtract(Vector256One, backdrop), Avx.Subtract(Vector256One, source))); /// /// Returns the result of the "Darken" compositing equation. @@ -179,6 +182,19 @@ internal static partial class PorterDuffFunctions return Vector4.Min(Vector4.One, new Vector4(cr, cg, cb, 0)); } + /// + /// Returns the result of the "Overlay" compositing equation. + /// + /// The backdrop vector. + /// The source vector. + /// The . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector256 Overlay(Vector256 backdrop, Vector256 source) + { + Vector256 color = OverlayValueFunction(backdrop, source); + return Avx.Min(Vector256One, Avx.Blend(color, Vector256.Zero, BlendAlphaControl)); + } + /// /// Returns the result of the "HardLight" compositing equation. /// @@ -195,6 +211,19 @@ internal static partial class PorterDuffFunctions return Vector4.Min(Vector4.One, new Vector4(cr, cg, cb, 0)); } + /// + /// Returns the result of the "HardLight" compositing equation. + /// + /// The backdrop vector. + /// The source vector. + /// The . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector256 HardLight(Vector256 backdrop, Vector256 source) + { + Vector256 color = OverlayValueFunction(source, backdrop); + return Avx.Min(Vector256One, Avx.Blend(color, Vector256.Zero, BlendAlphaControl)); + } + /// /// Helper function for Overlay and HardLight modes /// @@ -205,6 +234,22 @@ internal static partial class PorterDuffFunctions private static float OverlayValueFunction(float backdrop, float source) => backdrop <= 0.5f ? (2 * backdrop * source) : 1 - (2 * (1 - source) * (1 - backdrop)); + /// + /// Helper function for Overlay and HardLight modes + /// + /// Backdrop color element + /// Source color element + /// Overlay value + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector256 OverlayValueFunction(Vector256 backdrop, Vector256 source) + { + Vector256 left = Avx.Multiply(Avx.Multiply(Vector256Two, backdrop), source); + Vector256 right = Avx.Subtract(Vector256One, Avx.Multiply(Avx.Multiply(Vector256Two, Avx.Subtract(Vector256One, source)), Avx.Subtract(Vector256One, backdrop))); + + Vector256 cmp = Avx.CompareGreaterThan(backdrop, Vector256Half); + return Avx.BlendVariable(left, right, cmp); + } + /// /// Returns the result of the "Over" compositing equation. /// @@ -243,12 +288,9 @@ internal static partial class PorterDuffFunctions [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 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); @@ -264,7 +306,7 @@ internal static partial class PorterDuffFunctions // unpremultiply color = Avx.Divide(color, Avx.Max(alpha, Constants.Epsilon256)); - return Avx.Blend(color, alpha, blendAlphaControl); + return Avx.Blend(color, alpha, BlendAlphaControl); } /// @@ -304,15 +346,11 @@ internal static partial class PorterDuffFunctions [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); + Vector256 alpha = Avx.Shuffle(destination, destination, ShuffleAlphaControl); // calculate weights - Vector256 sW = Avx.Shuffle(source, source, shuffleAlphaControl); + Vector256 sW = Avx.Shuffle(source, source, ShuffleAlphaControl); Vector256 blendW = Avx.Multiply(sW, alpha); Vector256 dstW = Avx.Subtract(alpha, blendW); @@ -321,7 +359,7 @@ internal static partial class PorterDuffFunctions // unpremultiply color = Avx.Divide(color, Avx.Max(alpha, Constants.Epsilon256)); - return Avx.Blend(color, alpha, blendAlphaControl); + return Avx.Blend(color, alpha, BlendAlphaControl); } /// @@ -351,12 +389,9 @@ internal static partial class PorterDuffFunctions [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 sW = Avx.Shuffle(source, source, ShuffleAlphaControl); + Vector256 dW = Avx.Shuffle(destination, destination, ShuffleAlphaControl); Vector256 alpha = Avx.Multiply(sW, dW); // premultiply @@ -364,7 +399,7 @@ internal static partial class PorterDuffFunctions // unpremultiply color = Avx.Divide(color, Avx.Max(alpha, Constants.Epsilon256)); - return Avx.Blend(color, alpha, blendAlphaControl); + return Avx.Blend(color, alpha, BlendAlphaControl); } /// @@ -394,20 +429,17 @@ internal static partial class PorterDuffFunctions [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); + Vector256 sW = Avx.Shuffle(source, source, ShuffleAlphaControl); + Vector256 dW = Avx.Shuffle(destination, destination, ShuffleAlphaControl); + Vector256 alpha = Avx.Multiply(Avx.Subtract(Vector256One, 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); + return Avx.Blend(color, alpha, BlendAlphaControl); } /// @@ -441,16 +473,12 @@ internal static partial class PorterDuffFunctions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector256 Xor(Vector256 destination, Vector256 source) { - 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 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); + Vector256 srcW = Avx.Subtract(Vector256One, dW); + Vector256 dstW = Avx.Subtract(Vector256One, sW); // calculate alpha Vector256 alpha = SimdUtils.HwIntrinsics.MultiplyAdd(sW, srcW, Avx.Multiply(dW, dstW)); @@ -458,7 +486,7 @@ internal static partial class PorterDuffFunctions // unpremultiply color = Avx.Divide(color, Avx.Max(alpha, Constants.Epsilon256)); - return Avx.Blend(color, alpha, blendAlphaControl); + return Avx.Blend(color, alpha, BlendAlphaControl); } [MethodImpl(MethodImplOptions.AggressiveInlining)]