diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/AssociatedAlphaPixelBlenders.Generated.cs b/src/ImageSharp/PixelFormats/PixelBlenders/AssociatedAlphaPixelBlenders.Generated.cs
index 94ae2ac71..85313dc20 100644
--- a/src/ImageSharp/PixelFormats/PixelBlenders/AssociatedAlphaPixelBlenders.Generated.cs
+++ b/src/ImageSharp/PixelFormats/PixelBlenders/AssociatedAlphaPixelBlenders.Generated.cs
@@ -3,84150 +3,3910 @@
//
using System.Numerics;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
using System.Runtime.Intrinsics;
-using System.Runtime.Intrinsics.X86;
namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders;
///
-/// Provides generated Porter-Duff blenders for associated-alpha pixel formats.
+/// Provides the associated-alpha equations consumed by the shared pixel-blending traversal.
///
-internal static partial class AssociatedAlphaPixelBlenders
- where TPixel : unmanaged, IPixel
+internal static class AssociatedAlphaPixelBlenderOperators
{
-
///
- /// A pixel blender that implements the "NormalSrc" composition equation.
+ /// Applies the "NormalSrc" associated-alpha composition equation.
///
- public sealed class NormalSrc : AssociatedAlphaPixelBlender
+ public readonly struct NormalSrc : IPixelBlenderOperator
{
- ///
- /// Gets the static instance of this blender.
- ///
- public static NormalSrc Instance { get; } = new NormalSrc();
-
///
- public override TPixel Blend(TPixel background, TPixel source, float amount)
- {
- return TPixel.FromAssociatedScaledVector4(AssociatedAlphaPorterDuffFunctions.NormalSrc(background.ToAssociatedScaledVector4(), source.ToAssociatedScaledVector4(), Numerics.Clamp(amount, 0, 1)));
- }
+ public static Vector4 Invoke(Vector4 background, Vector4 source, float amount)
+ => AssociatedAlphaPorterDuffFunctions.NormalSrc(background, source, amount);
///
- protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount)
- {
- amount = Numerics.Clamp(amount, 0, 1);
-
- if (Avx512F.IsSupported && destination.Length >= 4)
- {
- // Divide by 4 as 4 elements per Vector4 and 16 per Vector512
- ref Vector512 destinationBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(destination));
- ref Vector512 destinationLast = ref Unsafe.Add(ref destinationBase, (uint)destination.Length / 4u);
-
- ref Vector512 backgroundBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(background));
- ref Vector512 sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source));
- Vector512 opacity = Vector512.Create(amount);
+ public static Vector256 Invoke(
+ Vector256 background,
+ Vector256 source,
+ Vector256 amount)
+ => AssociatedAlphaPorterDuffFunctions.NormalSrc(background, source, amount);
- while (Unsafe.IsAddressLessThan(ref destinationBase, ref destinationLast))
- {
- destinationBase = AssociatedAlphaPorterDuffFunctions.NormalSrc(backgroundBase, sourceBase, opacity);
- destinationBase = ref Unsafe.Add(ref destinationBase, 1);
- backgroundBase = ref Unsafe.Add(ref backgroundBase, 1);
- sourceBase = ref Unsafe.Add(ref sourceBase, 1);
- }
+ ///
+ public static Vector512 Invoke(
+ Vector512 background,
+ Vector512 source,
+ Vector512 amount)
+ => AssociatedAlphaPorterDuffFunctions.NormalSrc(background, source, amount);
+ }
- int remainder = Numerics.Modulo4(destination.Length);
- if (remainder != 0)
- {
- for (int i = destination.Length - remainder; i < destination.Length; i++)
- {
- destination[i] = AssociatedAlphaPorterDuffFunctions.NormalSrc(background[i], source[i], amount);
- }
- }
- }
- else if (Avx2.IsSupported && destination.Length >= 2)
- {
- // Divide by 2 as 4 elements per Vector4 and 8 per Vector256
- ref Vector256 destinationBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(destination));
- ref Vector256 destinationLast = ref Unsafe.Add(ref destinationBase, (uint)destination.Length / 2u);
+ ///
+ /// Applies the "MultiplySrc" associated-alpha composition equation.
+ ///
+ public readonly struct MultiplySrc : IPixelBlenderOperator
+ {
+ ///
+ public static Vector4 Invoke(Vector4 background, Vector4 source, float amount)
+ => AssociatedAlphaPorterDuffFunctions.MultiplySrc(background, source, amount);
- ref Vector256 backgroundBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(background));
- ref Vector256 sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source));
- Vector256 opacity = Vector256.Create(amount);
+ ///
+ public static Vector256 Invoke(
+ Vector256 background,
+ Vector256 source,
+ Vector256 amount)
+ => AssociatedAlphaPorterDuffFunctions.MultiplySrc(background, source, amount);
- while (Unsafe.IsAddressLessThan(ref destinationBase, ref destinationLast))
- {
- destinationBase = AssociatedAlphaPorterDuffFunctions.NormalSrc(backgroundBase, sourceBase, opacity);
- destinationBase = ref Unsafe.Add(ref destinationBase, 1);
- backgroundBase = ref Unsafe.Add(ref backgroundBase, 1);
- sourceBase = ref Unsafe.Add(ref sourceBase, 1);
- }
+ ///
+ public static Vector512 Invoke(
+ Vector512 background,
+ Vector512 source,
+ Vector512 amount)
+ => AssociatedAlphaPorterDuffFunctions.MultiplySrc(background, source, amount);
+ }
- if (Numerics.Modulo2(destination.Length) != 0)
- {
- // Vector4 fits neatly in pairs. Any overlap has to be equal to 1.
- int i = destination.Length - 1;
- destination[i] = AssociatedAlphaPorterDuffFunctions.NormalSrc(background[i], source[i], amount);
- }
- }
- else
- {
- for (int i = 0; i < destination.Length; i++)
- {
- destination[i] = AssociatedAlphaPorterDuffFunctions.NormalSrc(background[i], source[i], amount);
- }
- }
- }
+ ///
+ /// Applies the "AddSrc" associated-alpha composition equation.
+ ///
+ public readonly struct AddSrc : IPixelBlenderOperator
+ {
+ ///
+ public static Vector4 Invoke(Vector4 background, Vector4 source, float amount)
+ => AssociatedAlphaPorterDuffFunctions.AddSrc(background, source, amount);
///
- protected override void BlendFunction(Span destination, ReadOnlySpan background, Vector4 source, float amount)
- {
- amount = Numerics.Clamp(amount, 0, 1);
+ public static Vector256 Invoke(
+ Vector256 background,
+ Vector256 source,
+ Vector256 amount)
+ => AssociatedAlphaPorterDuffFunctions.AddSrc(background, source, amount);
- if (Avx512F.IsSupported && destination.Length >= 4)
- {
- // Divide by 4 as 4 elements per Vector4 and 16 per Vector512
- ref Vector512 destinationBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(destination));
- ref Vector512 destinationLast = ref Unsafe.Add(ref destinationBase, (uint)destination.Length / 4u);
+ ///
+ public static Vector512 Invoke(
+ Vector512 background,
+ Vector512 source,
+ Vector512 amount)
+ => AssociatedAlphaPorterDuffFunctions.AddSrc(background, source, amount);
+ }
- ref Vector512 backgroundBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(background));
- Vector512 sourceBase = Vector512.Create(
- source.X, source.Y, source.Z, source.W,
- source.X, source.Y, source.Z, source.W,
- source.X, source.Y, source.Z, source.W,
- source.X, source.Y, source.Z, source.W);
- Vector512 opacity = Vector512.Create(amount);
+ ///
+ /// Applies the "SubtractSrc" associated-alpha composition equation.
+ ///
+ public readonly struct SubtractSrc : IPixelBlenderOperator
+ {
+ ///
+ public static Vector4 Invoke(Vector4 background, Vector4 source, float amount)
+ => AssociatedAlphaPorterDuffFunctions.SubtractSrc(background, source, amount);
- while (Unsafe.IsAddressLessThan(ref destinationBase, ref destinationLast))
- {
- destinationBase = AssociatedAlphaPorterDuffFunctions.NormalSrc(backgroundBase, sourceBase, opacity);
- destinationBase = ref Unsafe.Add(ref destinationBase, 1);
- backgroundBase = ref Unsafe.Add(ref backgroundBase, 1);
- }
+ ///
+ public static Vector256 Invoke(
+ Vector256 background,
+ Vector256 source,
+ Vector256 amount)
+ => AssociatedAlphaPorterDuffFunctions.SubtractSrc(background, source, amount);
- int remainder = Numerics.Modulo4(destination.Length);
- if (remainder != 0)
- {
- for (int i = destination.Length - remainder; i < destination.Length; i++)
- {
- destination[i] = AssociatedAlphaPorterDuffFunctions.NormalSrc(background[i], source, amount);
- }
- }
- }
- else if (Avx2.IsSupported && destination.Length >= 2)
- {
- // Divide by 2 as 4 elements per Vector4 and 8 per Vector256
- ref Vector256 destinationBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(destination));
- ref Vector256 destinationLast = ref Unsafe.Add(ref destinationBase, (uint)destination.Length / 2u);
+ ///
+ public static Vector512 Invoke(
+ Vector512 background,
+ Vector512 source,
+ Vector512 amount)
+ => AssociatedAlphaPorterDuffFunctions.SubtractSrc(background, source, amount);
+ }
- ref Vector256 backgroundBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(background));
- Vector256 sourceBase = Vector256.Create(source.X, source.Y, source.Z, source.W, source.X, source.Y, source.Z, source.W);
- Vector256 opacity = Vector256.Create(amount);
+ ///
+ /// Applies the "ScreenSrc" associated-alpha composition equation.
+ ///
+ public readonly struct ScreenSrc : IPixelBlenderOperator
+ {
+ ///
+ public static Vector4 Invoke(Vector4 background, Vector4 source, float amount)
+ => AssociatedAlphaPorterDuffFunctions.ScreenSrc(background, source, amount);
- while (Unsafe.IsAddressLessThan(ref destinationBase, ref destinationLast))
- {
- destinationBase = AssociatedAlphaPorterDuffFunctions.NormalSrc(backgroundBase, sourceBase, opacity);
- destinationBase = ref Unsafe.Add(ref destinationBase, 1);
- backgroundBase = ref Unsafe.Add(ref backgroundBase, 1);
- }
+ ///
+ public static Vector256 Invoke(
+ Vector256 background,
+ Vector256 source,
+ Vector256 amount)
+ => AssociatedAlphaPorterDuffFunctions.ScreenSrc(background, source, amount);
- if (Numerics.Modulo2(destination.Length) != 0)
- {
- // Vector4 fits neatly in pairs. Any overlap has to be equal to 1.
- int i = destination.Length - 1;
- destination[i] = AssociatedAlphaPorterDuffFunctions.NormalSrc(background[i], source, amount);
- }
- }
- else
- {
- for (int i = 0; i < destination.Length; i++)
- {
- destination[i] = AssociatedAlphaPorterDuffFunctions.NormalSrc(background[i], source, amount);
- }
- }
- }
+ ///
+ public static Vector512 Invoke(
+ Vector512 background,
+ Vector512 source,
+ Vector512 amount)
+ => AssociatedAlphaPorterDuffFunctions.ScreenSrc(background, source, amount);
+ }
+ ///
+ /// Applies the "DarkenSrc" associated-alpha composition equation.
+ ///
+ public readonly struct DarkenSrc : IPixelBlenderOperator
+ {
///
- protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount)
- {
- if (Avx512F.IsSupported && destination.Length >= 4)
- {
- // Divide by 4 as 4 elements per Vector4 and 16 per Vector512
- ref Vector512 destinationBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(destination));
- ref Vector512 destinationLast = ref Unsafe.Add(ref destinationBase, (uint)destination.Length / 4u);
+ public static Vector4 Invoke(Vector4 background, Vector4 source, float amount)
+ => AssociatedAlphaPorterDuffFunctions.DarkenSrc(background, source, amount);
- ref Vector512 backgroundBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(background));
- ref Vector512 sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source));
- ref float amountBase = ref MemoryMarshal.GetReference(amount);
+ ///
+ public static Vector256 Invoke(
+ Vector256 background,
+ Vector256 source,
+ Vector256 amount)
+ => AssociatedAlphaPorterDuffFunctions.DarkenSrc(background, source, amount);
- Vector512 vOne = Vector512.Create(1F);
+ ///
+ public static Vector512 Invoke(
+ Vector512 background,
+ Vector512 source,
+ Vector512 amount)
+ => AssociatedAlphaPorterDuffFunctions.DarkenSrc(background, source, amount);
+ }
- while (Unsafe.IsAddressLessThan(ref destinationBase, ref destinationLast))
- {
- float amount0 = amountBase;
- float amount1 = Unsafe.Add(ref amountBase, 1);
- float amount2 = Unsafe.Add(ref amountBase, 2);
- float amount3 = Unsafe.Add(ref amountBase, 3);
+ ///
+ /// Applies the "LightenSrc" associated-alpha composition equation.
+ ///
+ public readonly struct LightenSrc : IPixelBlenderOperator
+ {
+ ///
+ public static Vector4 Invoke(Vector4 background, Vector4 source, float amount)
+ => AssociatedAlphaPorterDuffFunctions.LightenSrc(background, source, amount);
- // We need to create a Vector512 containing the current four amount values
- // taking up each quarter of the Vector512 and then clamp them.
- Vector512 opacity = Vector512.Create(
- amount0, amount0, amount0, amount0,
- amount1, amount1, amount1, amount1,
- amount2, amount2, amount2, amount2,
- amount3, amount3, amount3, amount3);
- opacity = Vector512.Min(Vector512.Max(Vector512.Zero, opacity), vOne);
+ ///
+ public static Vector256 Invoke(
+ Vector256 background,
+ Vector256 source,
+ Vector256 amount)
+ => AssociatedAlphaPorterDuffFunctions.LightenSrc(background, source, amount);
- destinationBase = AssociatedAlphaPorterDuffFunctions.NormalSrc(backgroundBase, sourceBase, opacity);
- destinationBase = ref Unsafe.Add(ref destinationBase, 1);
- backgroundBase = ref Unsafe.Add(ref backgroundBase, 1);
- sourceBase = ref Unsafe.Add(ref sourceBase, 1);
- amountBase = ref Unsafe.Add(ref amountBase, 4);
- }
+ ///
+ public static Vector512 Invoke(
+ Vector512 background,
+ Vector512 source,
+ Vector512 amount)
+ => AssociatedAlphaPorterDuffFunctions.LightenSrc(background, source, amount);
+ }
- int remainder = Numerics.Modulo4(destination.Length);
- if (remainder != 0)
- {
- for (int i = destination.Length - remainder; i < destination.Length; i++)
- {
- destination[i] = AssociatedAlphaPorterDuffFunctions.NormalSrc(background[i], source[i], Numerics.Clamp(amount[i], 0, 1F));
- }
- }
- }
- else if (Avx2.IsSupported && destination.Length >= 2)
- {
- // Divide by 2 as 4 elements per Vector4 and 8 per Vector256
- ref Vector256 destinationBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(destination));
- ref Vector256 destinationLast = ref Unsafe.Add(ref destinationBase, (uint)destination.Length / 2u);
+ ///
+ /// Applies the "OverlaySrc" associated-alpha composition equation.
+ ///
+ public readonly struct OverlaySrc : IPixelBlenderOperator
+ {
+ ///
+ public static Vector4 Invoke(Vector4 background, Vector4 source, float amount)
+ => AssociatedAlphaPorterDuffFunctions.OverlaySrc(background, source, amount);
- ref Vector256 backgroundBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(background));
- ref Vector256 sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source));
- ref float amountBase = ref MemoryMarshal.GetReference(amount);
+ ///
+ public static Vector256 Invoke(
+ Vector256 background,
+ Vector256 source,
+ Vector256 amount)
+ => AssociatedAlphaPorterDuffFunctions.OverlaySrc(background, source, amount);
- Vector256 vOne = Vector256.Create(1F);
+ ///
+ public static Vector512 Invoke(
+ Vector512 background,
+ Vector512 source,
+ Vector512 amount)
+ => AssociatedAlphaPorterDuffFunctions.OverlaySrc(background, source, amount);
+ }
- while (Unsafe.IsAddressLessThan(ref destinationBase, ref destinationLast))
- {
- // We need to create a Vector256 containing the current and next amount values
- // taking up each half of the Vector256 and then clamp them.
- Vector256 opacity = Vector256.Create(
- Vector128.Create(amountBase),
- Vector128.Create(Unsafe.Add(ref amountBase, 1)));
- opacity = Avx.Min(Avx.Max(Vector256.Zero, opacity), vOne);
+ ///
+ /// Applies the "HardLightSrc" associated-alpha composition equation.
+ ///
+ public readonly struct HardLightSrc : IPixelBlenderOperator
+ {
+ ///
+ public static Vector4 Invoke(Vector4 background, Vector4 source, float amount)
+ => AssociatedAlphaPorterDuffFunctions.HardLightSrc(background, source, amount);
- destinationBase = AssociatedAlphaPorterDuffFunctions.NormalSrc(backgroundBase, sourceBase, opacity);
- destinationBase = ref Unsafe.Add(ref destinationBase, 1);
- backgroundBase = ref Unsafe.Add(ref backgroundBase, 1);
- sourceBase = ref Unsafe.Add(ref sourceBase, 1);
- amountBase = ref Unsafe.Add(ref amountBase, 2);
- }
+ ///
+ public static Vector256 Invoke(
+ Vector256 background,
+ Vector256 source,
+ Vector256 amount)
+ => AssociatedAlphaPorterDuffFunctions.HardLightSrc(background, source, amount);
- if (Numerics.Modulo2(destination.Length) != 0)
- {
- // Vector4 fits neatly in pairs. Any overlap has to be equal to 1.
- int i = destination.Length - 1;
- destination[i] = AssociatedAlphaPorterDuffFunctions.NormalSrc(background[i], source[i], Numerics.Clamp(amount[i], 0, 1F));
- }
- }
- else
- {
- for (int i = 0; i < destination.Length; i++)
- {
- destination[i] = AssociatedAlphaPorterDuffFunctions.NormalSrc(background[i], source[i], Numerics.Clamp(amount[i], 0, 1F));
- }
- }
- }
+ ///
+ public static Vector512 Invoke(
+ Vector512 background,
+ Vector512 source,
+ Vector512 amount)
+ => AssociatedAlphaPorterDuffFunctions.HardLightSrc(background, source, amount);
+ }
+ ///
+ /// Applies the "NormalSrcAtop" associated-alpha composition equation.
+ ///
+ public readonly struct NormalSrcAtop : IPixelBlenderOperator
+ {
///
- protected override void BlendFunction(Span destination, ReadOnlySpan background, Vector4 source, ReadOnlySpan amount)
- {
- if (Avx512F.IsSupported && destination.Length >= 4)
- {
- // Divide by 4 as 4 elements per Vector4 and 16 per Vector512
- ref Vector512 destinationBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(destination));
- ref Vector512 destinationLast = ref Unsafe.Add(ref destinationBase, (uint)destination.Length / 4u);
+ public static Vector4 Invoke(Vector4 background, Vector4 source, float amount)
+ => AssociatedAlphaPorterDuffFunctions.NormalSrcAtop(background, source, amount);
- ref Vector512 backgroundBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(background));
- ref float amountBase = ref MemoryMarshal.GetReference(amount);
+ ///
+ public static Vector256 Invoke(
+ Vector256 background,
+ Vector256 source,
+ Vector256 amount)
+ => AssociatedAlphaPorterDuffFunctions.NormalSrcAtop(background, source, amount);
- Vector512 sourceBase = Vector512.Create(
- source.X, source.Y, source.Z, source.W,
- source.X, source.Y, source.Z, source.W,
- source.X, source.Y, source.Z, source.W,
- source.X, source.Y, source.Z, source.W);
- Vector512 vOne = Vector512.Create(1F);
+ ///
+ public static Vector512 Invoke(
+ Vector512 background,
+ Vector512 source,
+ Vector512 amount)
+ => AssociatedAlphaPorterDuffFunctions.NormalSrcAtop(background, source, amount);
+ }
- while (Unsafe.IsAddressLessThan(ref destinationBase, ref destinationLast))
- {
- float amount0 = amountBase;
- float amount1 = Unsafe.Add(ref amountBase, 1);
- float amount2 = Unsafe.Add(ref amountBase, 2);
- float amount3 = Unsafe.Add(ref amountBase, 3);
+ ///
+ /// Applies the "MultiplySrcAtop" associated-alpha composition equation.
+ ///
+ public readonly struct MultiplySrcAtop : IPixelBlenderOperator
+ {
+ ///
+ public static Vector4 Invoke(Vector4 background, Vector4 source, float amount)
+ => AssociatedAlphaPorterDuffFunctions.MultiplySrcAtop(background, source, amount);
- // We need to create a Vector512 containing the current four amount values
- // taking up each quarter of the Vector512 and then clamp them.
- Vector512 opacity = Vector512.Create(
- amount0, amount0, amount0, amount0,
- amount1, amount1, amount1, amount1,
- amount2, amount2, amount2, amount2,
- amount3, amount3, amount3, amount3);
- opacity = Vector512.Min(Vector512.Max(Vector512.Zero, opacity), vOne);
+ ///
+ public static Vector256 Invoke(
+ Vector256 background,
+ Vector256 source,
+ Vector256 amount)
+ => AssociatedAlphaPorterDuffFunctions.MultiplySrcAtop(background, source, amount);
- destinationBase = AssociatedAlphaPorterDuffFunctions.NormalSrc(backgroundBase, sourceBase, opacity);
- destinationBase = ref Unsafe.Add(ref destinationBase, 1);
- backgroundBase = ref Unsafe.Add(ref backgroundBase, 1);
- amountBase = ref Unsafe.Add(ref amountBase, 4);
- }
+ ///
+ public static Vector512 Invoke(
+ Vector512 background,
+ Vector512 source,
+ Vector512 amount)
+ => AssociatedAlphaPorterDuffFunctions.MultiplySrcAtop(background, source, amount);
+ }
- int remainder = Numerics.Modulo4(destination.Length);
- if (remainder != 0)
- {
- for (int i = destination.Length - remainder; i < destination.Length; i++)
- {
- destination[i] = AssociatedAlphaPorterDuffFunctions.NormalSrc(background[i], source, Numerics.Clamp(amount[i], 0, 1F));
- }
- }
- }
- else if (Avx2.IsSupported && destination.Length >= 2)
- {
- // Divide by 2 as 4 elements per Vector4 and 8 per Vector256
- ref Vector256 destinationBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(destination));
- ref Vector256 destinationLast = ref Unsafe.Add(ref destinationBase, (uint)destination.Length / 2u);
+ ///
+ /// Applies the "AddSrcAtop" associated-alpha composition equation.
+ ///
+ public readonly struct AddSrcAtop : IPixelBlenderOperator
+ {
+ ///
+ public static Vector4 Invoke(Vector4 background, Vector4 source, float amount)
+ => AssociatedAlphaPorterDuffFunctions.AddSrcAtop(background, source, amount);
- ref Vector256 backgroundBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(background));
- ref float amountBase = ref MemoryMarshal.GetReference(amount);
+ ///
+ public static Vector256 Invoke(
+ Vector256 background,
+ Vector256 source,
+ Vector256 amount)
+ => AssociatedAlphaPorterDuffFunctions.AddSrcAtop(background, source, amount);
- Vector256 sourceBase = Vector256.Create(source.X, source.Y, source.Z, source.W, source.X, source.Y, source.Z, source.W);
- Vector256 vOne = Vector256.Create(1F);
+ ///
+ public static Vector512 Invoke(
+ Vector512 background,
+ Vector512 source,
+ Vector512 amount)
+ => AssociatedAlphaPorterDuffFunctions.AddSrcAtop(background, source, amount);
+ }
- while (Unsafe.IsAddressLessThan(ref destinationBase, ref destinationLast))
- {
- // We need to create a Vector256 containing the current and next amount values
- // taking up each half of the Vector256 and then clamp them.
- Vector256 opacity = Vector256.Create(
- Vector128.Create(amountBase),
- Vector128.Create(Unsafe.Add(ref amountBase, 1)));
- opacity = Avx.Min(Avx.Max(Vector256.Zero, opacity), vOne);
+ ///
+ /// Applies the "SubtractSrcAtop" associated-alpha composition equation.
+ ///
+ public readonly struct SubtractSrcAtop : IPixelBlenderOperator
+ {
+ ///
+ public static Vector4 Invoke(Vector4 background, Vector4 source, float amount)
+ => AssociatedAlphaPorterDuffFunctions.SubtractSrcAtop(background, source, amount);
- destinationBase = AssociatedAlphaPorterDuffFunctions.NormalSrc(backgroundBase, sourceBase, opacity);
- destinationBase = ref Unsafe.Add(ref destinationBase, 1);
- backgroundBase = ref Unsafe.Add(ref backgroundBase, 1);
- amountBase = ref Unsafe.Add(ref amountBase, 2);
- }
+ ///
+ public static Vector256 Invoke(
+ Vector256 background,
+ Vector256 source,
+ Vector256 amount)
+ => AssociatedAlphaPorterDuffFunctions.SubtractSrcAtop(background, source, amount);
- if (Numerics.Modulo2(destination.Length) != 0)
- {
- // Vector4 fits neatly in pairs. Any overlap has to be equal to 1.
- int i = destination.Length - 1;
- destination[i] = AssociatedAlphaPorterDuffFunctions.NormalSrc(background[i], source, Numerics.Clamp(amount[i], 0, 1F));
- }
- }
- else
- {
- for (int i = 0; i < destination.Length; i++)
- {
- destination[i] = AssociatedAlphaPorterDuffFunctions.NormalSrc(background[i], source, Numerics.Clamp(amount[i], 0, 1F));
- }
- }
- }
+ ///
+ public static Vector512 Invoke(
+ Vector512 background,
+ Vector512 source,
+ Vector512 amount)
+ => AssociatedAlphaPorterDuffFunctions.SubtractSrcAtop(background, source, amount);
+ }
+ ///
+ /// Applies the "ScreenSrcAtop" associated-alpha composition equation.
+ ///
+ public readonly struct ScreenSrcAtop : IPixelBlenderOperator
+ {
///
- protected override void BlendWithCoverageFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount, ReadOnlySpan coverage)
- {
- amount = Numerics.Clamp(amount, 0, 1);
+ public static Vector4 Invoke(Vector4 background, Vector4 source, float amount)
+ => AssociatedAlphaPorterDuffFunctions.ScreenSrcAtop(background, source, amount);
- if (Avx512F.IsSupported && destination.Length >= 4)
- {
- // Divide by 4 as 4 elements per Vector4 and 16 per Vector512
- ref Vector512 destinationBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(destination));
- ref Vector512 destinationLast = ref Unsafe.Add(ref destinationBase, (uint)destination.Length / 4u);
+ ///
+ public static Vector256 Invoke(
+ Vector256 background,
+ Vector256 source,
+ Vector256 amount)
+ => AssociatedAlphaPorterDuffFunctions.ScreenSrcAtop(background, source, amount);
- ref Vector512 backgroundBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(background));
- ref Vector512 sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source));
- ref float coverageBase = ref MemoryMarshal.GetReference(coverage);
- Vector512 opacity = Vector512.Create(amount);
- Vector512 vOne = Vector512.Create(1F);
+ ///
+ public static Vector512 Invoke(
+ Vector512 background,
+ Vector512 source,
+ Vector512 amount)
+ => AssociatedAlphaPorterDuffFunctions.ScreenSrcAtop(background, source, amount);
+ }
- while (Unsafe.IsAddressLessThan(ref destinationBase, ref destinationLast))
- {
- float coverage0 = coverageBase;
- float coverage1 = Unsafe.Add(ref coverageBase, 1);
- float coverage2 = Unsafe.Add(ref coverageBase, 2);
- float coverage3 = Unsafe.Add(ref coverageBase, 3);
+ ///
+ /// Applies the "DarkenSrcAtop" associated-alpha composition equation.
+ ///
+ public readonly struct DarkenSrcAtop : IPixelBlenderOperator
+ {
+ ///
+ public static Vector4 Invoke(Vector4 background, Vector4 source, float amount)
+ => AssociatedAlphaPorterDuffFunctions.DarkenSrcAtop(background, source, amount);
- // We need to create a Vector512 containing the current four coverage values
- // taking up each quarter of the Vector512 and then clamp them.
- Vector512 coverageVector = Vector512.Create(
- coverage0, coverage0, coverage0, coverage0,
- coverage1, coverage1, coverage1, coverage1,
- coverage2, coverage2, coverage2, coverage2,
- coverage3, coverage3, coverage3, coverage3);
- coverageVector = Vector512.Min(Vector512.Max(Vector512.Zero, coverageVector), vOne);
+ ///
+ public static Vector256 Invoke(
+ Vector256 background,
+ Vector256 source,
+ Vector256 amount)
+ => AssociatedAlphaPorterDuffFunctions.DarkenSrcAtop(background, source, amount);
- Vector512 blended = AssociatedAlphaPorterDuffFunctions.NormalSrc(backgroundBase, sourceBase, opacity);
- destinationBase = AssociatedAlphaPorterDuffFunctions.BlendWithCoverage(backgroundBase, blended, coverageVector);
- destinationBase = ref Unsafe.Add(ref destinationBase, 1);
- backgroundBase = ref Unsafe.Add(ref backgroundBase, 1);
- sourceBase = ref Unsafe.Add(ref sourceBase, 1);
- coverageBase = ref Unsafe.Add(ref coverageBase, 4);
- }
+ ///
+ public static Vector512 Invoke(
+ Vector512 background,
+ Vector512 source,
+ Vector512 amount)
+ => AssociatedAlphaPorterDuffFunctions.DarkenSrcAtop(background, source, amount);
+ }
- int remainder = Numerics.Modulo4(destination.Length);
- if (remainder != 0)
- {
- for (int i = destination.Length - remainder; i < destination.Length; i++)
- {
- Vector4 blended = AssociatedAlphaPorterDuffFunctions.NormalSrc(background[i], source[i], amount);
- destination[i] = AssociatedAlphaPorterDuffFunctions.BlendWithCoverage(background[i], blended, Numerics.Clamp(coverage[i], 0, 1F));
- }
- }
- }
- else if (Avx2.IsSupported && destination.Length >= 2)
- {
- // Divide by 2 as 4 elements per Vector4 and 8 per Vector256
- ref Vector256 destinationBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(destination));
- ref Vector256 destinationLast = ref Unsafe.Add(ref destinationBase, (uint)destination.Length / 2u);
+ ///
+ /// Applies the "LightenSrcAtop" associated-alpha composition equation.
+ ///
+ public readonly struct LightenSrcAtop : IPixelBlenderOperator
+ {
+ ///
+ public static Vector4 Invoke(Vector4 background, Vector4 source, float amount)
+ => AssociatedAlphaPorterDuffFunctions.LightenSrcAtop(background, source, amount);
- ref Vector256 backgroundBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(background));
- ref Vector256 sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source));
- ref float coverageBase = ref MemoryMarshal.GetReference(coverage);
- Vector256 opacity = Vector256.Create(amount);
- Vector256 vOne = Vector256.Create(1F);
+ ///
+ public static Vector256 Invoke(
+ Vector256 background,
+ Vector256 source,
+ Vector256 amount)
+ => AssociatedAlphaPorterDuffFunctions.LightenSrcAtop(background, source, amount);
- while (Unsafe.IsAddressLessThan(ref destinationBase, ref destinationLast))
- {
- // We need to create a Vector256 containing the current and next coverage values
- // taking up each half of the Vector256 and then clamp them.
- Vector256