Browse Source

Fix pre/unpremultiply methods

pull/2369/head
James Jackson-South 3 years ago
parent
commit
2c30c90de7
  1. 5
      .gitattributes
  2. 109
      src/ImageSharp/Common/Helpers/Numerics.cs
  3. 198
      src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.cs
  4. 22
      src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.tt
  5. 90
      src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.cs
  6. 4
      tests/ImageSharp.Benchmarks/PixelBlenders/PorterDuffBulkVsPixel.cs
  7. 4
      tests/Images/External/ReferenceOutput/PorterDuffCompositorTests/PorterDuffOutputIsCorrect_Rgba32_pd-dest_DestOut.png
  8. 4
      tests/Images/External/ReferenceOutput/PorterDuffCompositorTests/PorterDuffOutputIsCorrect_Rgba32_pd-dest_In.png
  9. 4
      tests/Images/External/ReferenceOutput/PorterDuffCompositorTests/PorterDuffOutputIsCorrect_Rgba32_pd-dest_Out.png

5
.gitattributes

@ -64,18 +64,19 @@
# Set explicit file behavior to:
# treat as text
# normalize to Unix-style line endings and
# use a union merge when resoling conflicts
# use a union merge when resolving conflicts
###############################################################################
*.csproj text eol=lf merge=union
*.dbproj text eol=lf merge=union
*.fsproj text eol=lf merge=union
*.ncrunchproject text eol=lf merge=union
*.vbproj text eol=lf merge=union
*.shproj text eol=lf merge=union
###############################################################################
# Set explicit file behavior to:
# treat as text
# normalize to Windows-style line endings and
# use a union merge when resoling conflicts
# use a union merge when resolving conflicts
###############################################################################
*.sln text eol=crlf merge=union
###############################################################################

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

@ -474,21 +474,8 @@ internal static class Numerics
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Premultiply(ref Vector4 source)
{
float w = source.W;
source *= w;
source.W = w;
}
/// <summary>
/// Reverses the result of premultiplying a vector via <see cref="Premultiply(ref Vector4)"/>.
/// </summary>
/// <param name="source">The <see cref="Vector4"/> to premultiply</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void UnPremultiply(ref Vector4 source)
{
float w = source.W;
source /= w;
source.W = w;
Vector4 alpha = PermuteW(source);
source = WithW(source * alpha, alpha);
}
/// <summary>
@ -498,7 +485,7 @@ internal static class Numerics
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Premultiply(Span<Vector4> 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<float>
ref Vector256<float> vectorsBase = ref Unsafe.As<Vector4, Vector256<float>>(ref MemoryMarshal.GetReference(vectors));
@ -507,7 +494,7 @@ internal static class Numerics
while (Unsafe.IsAddressLessThan(ref vectorsBase, ref vectorsLast))
{
Vector256<float> source = vectorsBase;
Vector256<float> multiply = Avx.Shuffle(source, source, ShuffleAlphaControl);
Vector256<float> multiply = Avx.Permute(source, ShuffleAlphaControl);
vectorsBase = Avx.Blend(Avx.Multiply(source, multiply), source, BlendAlphaControl);
vectorsBase = ref Unsafe.Add(ref vectorsBase, 1);
}
@ -532,6 +519,28 @@ internal static class Numerics
}
}
/// <summary>
/// Reverses the result of premultiplying a vector via <see cref="Premultiply(ref Vector4)"/>.
/// </summary>
/// <param name="source">The <see cref="Vector4"/> to premultiply</param>
[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;
}
source = WithW(source / alpha, alpha);
}
/// <summary>
/// Bulk variant of <see cref="UnPremultiply(ref Vector4)"/>
/// </summary>
@ -539,17 +548,18 @@ internal static class Numerics
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void UnPremultiply(Span<Vector4> 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<float>
ref Vector256<float> vectorsBase = ref Unsafe.As<Vector4, Vector256<float>>(ref MemoryMarshal.GetReference(vectors));
ref Vector256<float> vectorsLast = ref Unsafe.Add(ref vectorsBase, (IntPtr)((uint)vectors.Length / 2u));
Vector256<float> epsilon = Vector256.Create(Constants.Epsilon);
while (Unsafe.IsAddressLessThan(ref vectorsBase, ref vectorsLast))
{
Vector256<float> source = vectorsBase;
Vector256<float> multiply = Avx.Shuffle(source, source, ShuffleAlphaControl);
vectorsBase = Avx.Blend(Avx.Divide(source, multiply), source, BlendAlphaControl);
Vector256<float> alpha = Avx.Permute(source, ShuffleAlphaControl);
vectorsBase = UnPremultiply(source, alpha);
vectorsBase = ref Unsafe.Add(ref vectorsBase, 1);
}
@ -573,6 +583,61 @@ internal static class Numerics
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector256<float> UnPremultiply(Vector256<float> source, Vector256<float> alpha)
{
// Check if alpha is zero to avoid division by zero
Vector256<float> zeroMask = Avx.CompareEqual(alpha, Vector256<float>.Zero);
// Divide source by alpha if alpha is nonzero, otherwise set all components to match the source value
Vector256<float> 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);
}
/// <summary>
/// Permutes the given vector return a new instance with all the values set to <see cref="Vector4.W"/>.
/// </summary>
/// <param name="value">The vector.</param>
/// <returns>The <see cref="Vector4"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 PermuteW(Vector4 value)
{
if (Sse.IsSupported)
{
return Sse.Shuffle(value.AsVector128(), value.AsVector128(), 0b11111111).AsVector4();
}
return new(value.W);
}
/// <summary>
/// Sets the W component of the given vector <paramref name="value"/> to the given value from <paramref name="w"/>.
/// </summary>
/// <param name="value">The vector to set.</param>
/// <param name="w">The vector containing the W value.</param>
/// <returns>The <see cref="Vector4"/>.</returns>
[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 <w[3], w[0], value[2], value[0]>
// Then return <value[0], value[1], tmp[2], tmp[0]> (which is <value[0], value[1], value[2], w[3]>)
Vector128<float> 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;
}
/// <summary>
/// Calculates the cube pow of all the XYZ channels of the input vectors.
/// </summary>
@ -586,7 +651,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 +660,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);

198
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);
}

22
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);
}

90
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;
}
/// <summary>
@ -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);
}
/// <summary>
@ -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;
}
/// <summary>
@ -362,8 +361,7 @@ internal static partial class PorterDuffFunctions
Vector256<float> 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);
}
/// <summary>
@ -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;
}
/// <summary>
@ -400,8 +398,7 @@ internal static partial class PorterDuffFunctions
Vector256<float> 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);
}
/// <summary>
@ -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;
}
/// <summary>
@ -438,8 +435,7 @@ internal static partial class PorterDuffFunctions
Vector256<float> 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);
}
/// <summary>
@ -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;
}
/// <summary>
@ -487,8 +483,7 @@ internal static partial class PorterDuffFunctions
Vector256<float> 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<float> Clear(Vector256<float> backdrop, Vector256<float> source) => Vector256<float>.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 <w[3], w[0], value[2], value[0]>
// Then return <value[0], value[1], tmp[2], tmp[0]> (which is <value[0], value[1], value[2], w[3]>)
Vector128<float> 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);
}
}

4
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<Rgba32> image = new(800, 800);
using IMemoryOwner<float> amounts = Configuration.Default.MemoryAllocator.Allocate<float>(image.Width);
@ -77,7 +77,7 @@ public class PorterDuffBulkVsPixel
}
[Benchmark(Description = "ImageSharp BulkPixelConvert")]
public static Size BulkPixelConvert()
public Size BulkPixelConvert()
{
using Image<Rgba32> image = new(800, 800);
using IMemoryOwner<float> amounts = Configuration.Default.MemoryAllocator.Allocate<float>(image.Width);

4
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

4
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

4
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

Loading…
Cancel
Save