Browse Source

Modernize base PorterDuffFunctions

pull/3109/head
James Jackson-South 1 month ago
parent
commit
1c5e3e1a69
  1. 2
      src/ImageSharp/Common/Helpers/Numerics.cs
  2. 37
      src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs
  3. 22
      src/ImageSharp/Common/Helpers/Vector256Utilities.cs
  4. 57
      src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.cs

2
src/ImageSharp/Common/Helpers/Numerics.cs

@ -690,7 +690,7 @@ internal static class Numerics
/// </summary>
/// <param name="vectors">The span of vectors</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe void CubePowOnXYZ(Span<Vector4> vectors)
public static void CubePowOnXYZ(Span<Vector4> vectors)
{
ref Vector4 baseRef = ref MemoryMarshal.GetReference(vectors);
ref Vector4 endRef = ref Unsafe.Add(ref baseRef, (uint)vectors.Length);

37
src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs

@ -602,48 +602,25 @@ internal static partial class SimdUtils
}
/// <summary>
/// Performs a multiplication and an addition of the <see cref="Vector256{Single}"/>.
/// TODO: Fix. The arguments are in a different order to the FMA intrinsic.
/// Performs a multiplication and a negated addition of the <see cref="Vector256{Single}"/>.
/// </summary>
/// <remarks>ret = (vm0 * vm1) + va</remarks>
/// <param name="va">The vector to add to the intermediate result.</param>
/// <remarks>ret = va - (vm0 * vm1)</remarks>
/// <param name="va">The vector to add to the negated intermediate result.</param>
/// <param name="vm0">The first vector to multiply.</param>
/// <param name="vm1">The second vector to multiply.</param>
/// <returns>The <see cref="Vector256{T}"/>.</returns>
[MethodImpl(InliningOptions.AlwaysInline)]
public static Vector256<float> MultiplyAdd(
[MethodImpl(InliningOptions.ShortMethod)]
public static Vector256<float> MultiplyAddNegated(
Vector256<float> va,
Vector256<float> vm0,
Vector256<float> vm1)
{
if (Fma.IsSupported)
{
return Fma.MultiplyAdd(vm1, vm0, va);
}
return va + (vm0 * vm1);
}
/// <summary>
/// Performs a multiplication and a negated addition of the <see cref="Vector256{Single}"/>.
/// </summary>
/// <remarks>ret = c - (a * b)</remarks>
/// <param name="a">The first vector to multiply.</param>
/// <param name="b">The second vector to multiply.</param>
/// <param name="c">The vector to add negated to the intermediate result.</param>
/// <returns>The <see cref="Vector256{T}"/>.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static Vector256<float> MultiplyAddNegated(
Vector256<float> a,
Vector256<float> b,
Vector256<float> c)
{
if (Fma.IsSupported)
{
return Fma.MultiplyAddNegated(a, b, c);
return Fma.MultiplyAddNegated(vm0, vm1, va);
}
return Avx.Subtract(c, Avx.Multiply(a, b));
return Avx.Subtract(va, Avx.Multiply(vm0, vm1));
}
/// <summary>

22
src/ImageSharp/Common/Helpers/Vector256Utilities.cs

@ -115,6 +115,28 @@ internal static class Vector256_
return va + (vm0 * vm1);
}
/// <summary>
/// Performs a multiplication and a negated addition of the <see cref="Vector256{Single}"/>.
/// </summary>
/// <remarks>ret = va - (vm0 * vm1)</remarks>
/// <param name="va">The vector to add to the negated intermediate result.</param>
/// <param name="vm0">The first vector to multiply.</param>
/// <param name="vm1">The second vector to multiply.</param>
/// <returns>The <see cref="Vector256{T}"/>.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static Vector256<float> MultiplyAddNegated(
Vector256<float> va,
Vector256<float> vm0,
Vector256<float> vm1)
{
if (Fma.IsSupported)
{
return Fma.MultiplyAddNegated(vm0, vm1, va);
}
return va - (vm0 * vm1);
}
/// <summary>
/// Performs a multiplication and a subtraction of the <see cref="Vector256{Single}"/>.
/// </summary>

57
src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.cs

@ -5,6 +5,7 @@ using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86;
using SixLabors.ImageSharp.Common.Helpers;
namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders;
@ -62,7 +63,7 @@ internal static partial class PorterDuffFunctions
/// <returns>The <see cref="Vector256{Single}"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector256<float> Multiply(Vector256<float> backdrop, Vector256<float> source)
=> Avx.Multiply(backdrop, source);
=> backdrop * source;
/// <summary>
/// Returns the result of the "Add" compositing equation.
@ -82,7 +83,7 @@ internal static partial class PorterDuffFunctions
/// <returns>The <see cref="Vector256{Single}"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector256<float> Add(Vector256<float> backdrop, Vector256<float> source)
=> Avx.Min(Vector256.Create(1F), Avx.Add(backdrop, source));
=> Vector256.Min(Vector256.Create(1F), backdrop + source);
/// <summary>
/// Returns the result of the "Subtract" compositing equation.
@ -102,7 +103,7 @@ internal static partial class PorterDuffFunctions
/// <returns>The <see cref="Vector256{Single}"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector256<float> Subtract(Vector256<float> backdrop, Vector256<float> source)
=> Avx.Max(Vector256<float>.Zero, Avx.Subtract(backdrop, source));
=> Vector256.Max(Vector256<float>.Zero, backdrop - source);
/// <summary>
/// Returns the result of the "Screen" compositing equation.
@ -124,7 +125,7 @@ internal static partial class PorterDuffFunctions
public static Vector256<float> Screen(Vector256<float> backdrop, Vector256<float> source)
{
Vector256<float> vOne = Vector256.Create(1F);
return SimdUtils.HwIntrinsics.MultiplyAddNegated(Avx.Subtract(vOne, backdrop), Avx.Subtract(vOne, source), vOne);
return Vector256_.MultiplyAddNegated(vOne, vOne - backdrop, vOne - source);
}
/// <summary>
@ -145,7 +146,7 @@ internal static partial class PorterDuffFunctions
/// <returns>The <see cref="Vector256{Single}"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector256<float> Darken(Vector256<float> backdrop, Vector256<float> source)
=> Avx.Min(backdrop, source);
=> Vector256.Min(backdrop, source);
/// <summary>
/// Returns the result of the "Lighten" compositing equation.
@ -164,7 +165,7 @@ internal static partial class PorterDuffFunctions
/// <returns>The <see cref="Vector256{Single}"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector256<float> Lighten(Vector256<float> backdrop, Vector256<float> source)
=> Avx.Max(backdrop, source);
=> Vector256.Max(backdrop, source);
/// <summary>
/// Returns the result of the "Overlay" compositing equation.
@ -192,7 +193,7 @@ internal static partial class PorterDuffFunctions
public static Vector256<float> Overlay(Vector256<float> backdrop, Vector256<float> source)
{
Vector256<float> color = OverlayValueFunction(backdrop, source);
return Avx.Min(Vector256.Create(1F), Avx.Blend(color, Vector256<float>.Zero, BlendAlphaControl));
return Vector256.Min(Vector256.Create(1F), Avx.Blend(color, Vector256<float>.Zero, BlendAlphaControl));
}
/// <summary>
@ -221,7 +222,7 @@ internal static partial class PorterDuffFunctions
public static Vector256<float> HardLight(Vector256<float> backdrop, Vector256<float> source)
{
Vector256<float> color = OverlayValueFunction(source, backdrop);
return Avx.Min(Vector256.Create(1F), Avx.Blend(color, Vector256<float>.Zero, BlendAlphaControl));
return Vector256.Min(Vector256.Create(1F), Avx.Blend(color, Vector256<float>.Zero, BlendAlphaControl));
}
/// <summary>
@ -244,10 +245,10 @@ internal static partial class PorterDuffFunctions
public static Vector256<float> OverlayValueFunction(Vector256<float> backdrop, Vector256<float> source)
{
Vector256<float> vOne = Vector256.Create(1F);
Vector256<float> left = Avx.Multiply(Avx.Add(backdrop, backdrop), source);
Vector256<float> left = (backdrop + backdrop) * source;
Vector256<float> vOneMinusSource = Avx.Subtract(vOne, source);
Vector256<float> right = SimdUtils.HwIntrinsics.MultiplyAddNegated(Avx.Add(vOneMinusSource, vOneMinusSource), Avx.Subtract(vOne, backdrop), vOne);
Vector256<float> right = Vector256_.MultiplyAddNegated(vOne, vOneMinusSource + vOneMinusSource, vOne - backdrop);
Vector256<float> cmp = Avx.CompareGreaterThan(backdrop, Vector256.Create(.5F));
return Avx.BlendVariable(left, right, cmp);
}
@ -295,17 +296,17 @@ internal static partial class PorterDuffFunctions
Vector256<float> sW = Avx.Permute(source, ShuffleAlphaControl);
Vector256<float> dW = Avx.Permute(destination, ShuffleAlphaControl);
Vector256<float> blendW = Avx.Multiply(sW, dW);
Vector256<float> dstW = Avx.Subtract(dW, blendW);
Vector256<float> srcW = Avx.Subtract(sW, blendW);
Vector256<float> blendW = sW * dW;
Vector256<float> dstW = dW - blendW;
Vector256<float> srcW = sW - blendW;
// calculate final alpha
Vector256<float> alpha = Avx.Add(dstW, sW);
Vector256<float> alpha = dstW + sW;
// calculate final color
Vector256<float> color = Avx.Multiply(destination, dstW);
color = SimdUtils.HwIntrinsics.MultiplyAdd(color, source, srcW);
color = SimdUtils.HwIntrinsics.MultiplyAdd(color, blend, blendW);
Vector256<float> color = destination * dstW;
color = Vector256_.MultiplyAdd(color, source, srcW);
color = Vector256_.MultiplyAdd(color, blend, blendW);
// unpremultiply
return Numerics.UnPremultiply(color, alpha);
@ -354,11 +355,11 @@ internal static partial class PorterDuffFunctions
// calculate weights
Vector256<float> sW = Avx.Permute(source, ShuffleAlphaControl);
Vector256<float> blendW = Avx.Multiply(sW, alpha);
Vector256<float> dstW = Avx.Subtract(alpha, blendW);
Vector256<float> blendW = sW * alpha;
Vector256<float> dstW = alpha - blendW;
// calculate final color
Vector256<float> color = SimdUtils.HwIntrinsics.MultiplyAdd(Avx.Multiply(blend, blendW), destination, dstW);
Vector256<float> color = Vector256_.MultiplyAdd(Avx.Multiply(blend, blendW), destination, dstW);
// unpremultiply
return Numerics.UnPremultiply(color, alpha);
@ -392,10 +393,10 @@ internal static partial class PorterDuffFunctions
public static Vector256<float> In(Vector256<float> destination, Vector256<float> source)
{
// calculate alpha
Vector256<float> alpha = Avx.Permute(Avx.Multiply(source, destination), ShuffleAlphaControl);
Vector256<float> alpha = Avx.Permute(source * destination, ShuffleAlphaControl);
// premultiply
Vector256<float> color = Avx.Multiply(source, alpha);
Vector256<float> color = source * alpha;
// unpremultiply
return Numerics.UnPremultiply(color, alpha);
@ -429,10 +430,10 @@ internal static partial class PorterDuffFunctions
public static Vector256<float> Out(Vector256<float> destination, Vector256<float> source)
{
// calculate alpha
Vector256<float> alpha = Avx.Permute(Avx.Multiply(source, Avx.Subtract(Vector256.Create(1F), destination)), ShuffleAlphaControl);
Vector256<float> alpha = Avx.Permute(source * (Vector256.Create(1F) - destination), ShuffleAlphaControl);
// premultiply
Vector256<float> color = Avx.Multiply(source, alpha);
Vector256<float> color = source * alpha;
// unpremultiply
return Numerics.UnPremultiply(color, alpha);
@ -475,12 +476,12 @@ internal static partial class PorterDuffFunctions
Vector256<float> dW = Avx.Shuffle(destination, destination, ShuffleAlphaControl);
Vector256<float> vOne = Vector256.Create(1F);
Vector256<float> srcW = Avx.Subtract(vOne, dW);
Vector256<float> dstW = Avx.Subtract(vOne, sW);
Vector256<float> srcW = vOne - dW;
Vector256<float> dstW = vOne - sW;
// calculate alpha
Vector256<float> alpha = SimdUtils.HwIntrinsics.MultiplyAdd(Avx.Multiply(dW, dstW), sW, srcW);
Vector256<float> color = SimdUtils.HwIntrinsics.MultiplyAdd(Avx.Multiply(Avx.Multiply(dW, destination), dstW), Avx.Multiply(sW, source), srcW);
Vector256<float> alpha = Vector256_.MultiplyAdd(Avx.Multiply(dW, dstW), sW, srcW);
Vector256<float> color = Vector256_.MultiplyAdd(Avx.Multiply(Avx.Multiply(dW, destination), dstW), Avx.Multiply(sW, source), srcW);
// unpremultiply
return Numerics.UnPremultiply(color, alpha);

Loading…
Cancel
Save