Browse Source

Port most of the function components.

pull/2359/head
James Jackson-South 3 years ago
parent
commit
517ec80280
  1. 9
      src/ImageSharp/Common/Constants.cs
  2. 20
      src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs
  3. 2
      src/ImageSharp/Formats/Jpeg/Components/FloatingPointDCT.Intrinsic.cs
  4. 253
      src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.cs

9
src/ImageSharp/Common/Constants.cs

@ -1,6 +1,8 @@
// Copyright (c) Six Labors.
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.Intrinsics;
namespace SixLabors.ImageSharp;
/// <summary>
@ -13,6 +15,11 @@ internal static class Constants
/// </summary>
public static readonly float Epsilon = 0.001F;
/// <summary>
/// The epsilon value for comparing floating point numbers.
/// </summary>
public static readonly Vector256<float> Epsilon256 = Vector256.Create(0.001F);
/// <summary>
/// The epsilon squared value for comparing floating point numbers.
/// </summary>

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

@ -532,7 +532,7 @@ internal static partial class SimdUtils
}
/// <summary>
/// Performs a multiplication and an addition of the <see cref="Vector256{T}"/>.
/// Performs a multiplication and an 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>
@ -549,22 +549,20 @@ internal static partial class SimdUtils
{
return Fma.MultiplyAdd(vm1, vm0, va);
}
else
{
return Avx.Add(Avx.Multiply(vm0, vm1), va);
}
return Avx.Add(Avx.Multiply(vm0, vm1), va);
}
/// <summary>
/// Performs a multiplication and a substraction of the <see cref="Vector256{T}"/>.
/// Performs a multiplication and a subtraction of the <see cref="Vector256{Single}"/>.
/// </summary>
/// <remarks>ret = (vm0 * vm1) - vs</remarks>
/// <param name="vs">The vector to substract from the intermediate result.</param>
/// <param name="vs">The vector to subtract from the 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> MultiplySubstract(
public static Vector256<float> MultiplySubtract(
in Vector256<float> vs,
in Vector256<float> vm0,
in Vector256<float> vm1)
@ -573,10 +571,8 @@ internal static partial class SimdUtils
{
return Fma.MultiplySubtract(vm1, vm0, vs);
}
else
{
return Avx.Subtract(Avx.Multiply(vm0, vm1), vs);
}
return Avx.Subtract(Avx.Multiply(vm0, vm1), vs);
}
/// <summary>

2
src/ImageSharp/Formats/Jpeg/Components/FloatingPointDCT.Intrinsic.cs

@ -99,7 +99,7 @@ internal static partial class FloatingPointDCT
var mm256_F_1_4142 = Vector256.Create(1.414213562f);
Vector256<float> tmp13 = Avx.Add(tmp1, tmp3);
Vector256<float> tmp12 = SimdUtils.HwIntrinsics.MultiplySubstract(tmp13, Avx.Subtract(tmp1, tmp3), mm256_F_1_4142);
Vector256<float> tmp12 = SimdUtils.HwIntrinsics.MultiplySubtract(tmp13, Avx.Subtract(tmp1, tmp3), mm256_F_1_4142);
tmp0 = Avx.Add(tmp10, tmp13);
tmp3 = Avx.Subtract(tmp10, tmp13);

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

@ -3,6 +3,8 @@
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86;
namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders;
@ -27,9 +29,17 @@ internal static partial class PorterDuffFunctions
/// <returns>The <see cref="Vector4"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Normal(Vector4 backdrop, Vector4 source)
{
return source;
}
=> source;
/// <summary>
/// Returns the result of the "Normal" compositing equation.
/// </summary>
/// <param name="backdrop">The backdrop vector.</param>
/// <param name="source">The source vector.</param>
/// <returns>The <see cref="Vector256{Single}"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector256<float> Normal(Vector256<float> backdrop, Vector256<float> source)
=> source;
/// <summary>
/// Returns the result of the "Multiply" compositing equation.
@ -39,9 +49,17 @@ internal static partial class PorterDuffFunctions
/// <returns>The <see cref="Vector4"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Multiply(Vector4 backdrop, Vector4 source)
{
return backdrop * source;
}
=> backdrop * source;
/// <summary>
/// Returns the result of the "Multiply" compositing equation.
/// </summary>
/// <param name="backdrop">The backdrop vector.</param>
/// <param name="source">The source vector.</param>
/// <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);
/// <summary>
/// Returns the result of the "Add" compositing equation.
@ -51,9 +69,17 @@ internal static partial class PorterDuffFunctions
/// <returns>The <see cref="Vector4"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Add(Vector4 backdrop, Vector4 source)
{
return Vector4.Min(Vector4.One, backdrop + source);
}
=> Vector4.Min(Vector4.One, backdrop + source);
/// <summary>
/// Returns the result of the "Add" compositing equation.
/// </summary>
/// <param name="backdrop">The backdrop vector.</param>
/// <param name="source">The source vector.</param>
/// <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));
/// <summary>
/// Returns the result of the "Subtract" compositing equation.
@ -63,9 +89,17 @@ internal static partial class PorterDuffFunctions
/// <returns>The <see cref="Vector4"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Subtract(Vector4 backdrop, Vector4 source)
{
return Vector4.Max(Vector4.Zero, backdrop - source);
}
=> Vector4.Max(Vector4.Zero, backdrop - source);
/// <summary>
/// Returns the result of the "Subtract" compositing equation.
/// </summary>
/// <param name="backdrop">The backdrop vector.</param>
/// <param name="source">The source vector.</param>
/// <returns>The <see cref="Vector256{Single}"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector256<float> Subtract(Vector256<float> backdrop, Vector256<float> source)
=> Avx.Min(Vector256.Create(1F), Avx.Subtract(backdrop, source));
/// <summary>
/// Returns the result of the "Screen" compositing equation.
@ -75,8 +109,19 @@ internal static partial class PorterDuffFunctions
/// <returns>The <see cref="Vector4"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Screen(Vector4 backdrop, Vector4 source)
=> Vector4.One - ((Vector4.One - backdrop) * (Vector4.One - source));
/// <summary>
/// Returns the result of the "Screen" compositing equation.
/// </summary>
/// <param name="backdrop">The backdrop vector.</param>
/// <param name="source">The source vector.</param>
/// <returns>The <see cref="Vector256{Single}"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector256<float> Screen(Vector256<float> backdrop, Vector256<float> source)
{
return Vector4.One - ((Vector4.One - backdrop) * (Vector4.One - source));
Vector256<float> vOne = Vector256.Create(1F);
return Avx.Subtract(vOne, Avx.Multiply(Avx.Subtract(vOne, backdrop), Avx.Subtract(vOne, source)));
}
/// <summary>
@ -87,9 +132,17 @@ internal static partial class PorterDuffFunctions
/// <returns>The <see cref="Vector4"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Darken(Vector4 backdrop, Vector4 source)
{
return Vector4.Min(backdrop, source);
}
=> Vector4.Min(backdrop, source);
/// <summary>
/// Returns the result of the "Darken" compositing equation.
/// </summary>
/// <param name="backdrop">The backdrop vector.</param>
/// <param name="source">The source vector.</param>
/// <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);
/// <summary>
/// Returns the result of the "Lighten" compositing equation.
@ -98,10 +151,17 @@ internal static partial class PorterDuffFunctions
/// <param name="source">The source vector.</param>
/// <returns>The <see cref="Vector4"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Lighten(Vector4 backdrop, Vector4 source)
{
return Vector4.Max(backdrop, source);
}
public static Vector4 Lighten(Vector4 backdrop, Vector4 source) => Vector4.Max(backdrop, source);
/// <summary>
/// Returns the result of the "Lighten" compositing equation.
/// </summary>
/// <param name="backdrop">The backdrop vector.</param>
/// <param name="source">The source vector.</param>
/// <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);
/// <summary>
/// Returns the result of the "Overlay" compositing equation.
@ -136,16 +196,14 @@ internal static partial class PorterDuffFunctions
}
/// <summary>
/// Helper function for Overlay andHardLight modes
/// Helper function for Overlay and HardLight modes
/// </summary>
/// <param name="backdrop">Backdrop color element</param>
/// <param name="source">Source color element</param>
/// <returns>Overlay value</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static float OverlayValueFunction(float backdrop, float source)
{
return backdrop <= 0.5f ? (2 * backdrop * source) : 1 - (2 * (1 - source) * (1 - backdrop));
}
=> backdrop <= 0.5f ? (2 * backdrop * source) : 1 - (2 * (1 - source) * (1 - backdrop));
/// <summary>
/// Returns the result of the "Over" compositing equation.
@ -175,6 +233,40 @@ internal static partial class PorterDuffFunctions
return color;
}
/// <summary>
/// Returns the result of the "Over" compositing equation.
/// </summary>
/// <param name="destination">The destination vector.</param>
/// <param name="source">The source vector.</param>
/// <param name="blend">The amount to blend. Range 0..1</param>
/// <returns>The <see cref="Vector256{Single}"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector256<float> Over(Vector256<float> destination, Vector256<float> source, Vector256<float> blend)
{
const int blendAlphaControl = 0b_10_00_10_00;
const int shuffleAlphaControl = 0b_11_11_11_11;
// calculate weights
Vector256<float> sW = Avx.Shuffle(source, source, shuffleAlphaControl);
Vector256<float> dW = Avx.Shuffle(destination, destination, shuffleAlphaControl);
Vector256<float> blendW = Avx.Multiply(sW, dW);
Vector256<float> dstW = Avx.Subtract(dW, blendW);
Vector256<float> srcW = Avx.Subtract(sW, blendW);
// calculate final alpha
Vector256<float> alpha = Avx.Add(dstW, sW);
// calculate final color
Vector256<float> color = Avx.Multiply(destination, dstW);
color = SimdUtils.HwIntrinsics.MultiplyAdd(source, srcW, color);
color = SimdUtils.HwIntrinsics.MultiplyAdd(blend, blendW, color);
// unpremultiply
color = Avx.Divide(color, Avx.Max(alpha, Constants.Epsilon256));
return Avx.Blend(color, alpha, blendAlphaControl);
}
/// <summary>
/// Returns the result of the "Atop" compositing equation.
/// </summary>
@ -202,6 +294,36 @@ internal static partial class PorterDuffFunctions
return color;
}
/// <summary>
/// Returns the result of the "Atop" compositing equation.
/// </summary>
/// <param name="destination">The destination vector.</param>
/// <param name="source">The source vector.</param>
/// <param name="blend">The amount to blend. Range 0..1</param>
/// <returns>The <see cref="Vector256{Single}"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector256<float> Atop(Vector256<float> destination, Vector256<float> source, Vector256<float> blend)
{
// calculate weights
const int blendAlphaControl = 0b_10_00_10_00;
const int shuffleAlphaControl = 0b_11_11_11_11;
// calculate final alpha
Vector256<float> alpha = Avx.Shuffle(destination, destination, shuffleAlphaControl);
// calculate weights
Vector256<float> sW = Avx.Shuffle(source, source, shuffleAlphaControl);
Vector256<float> blendW = Avx.Multiply(sW, alpha);
Vector256<float> dstW = Avx.Subtract(alpha, blendW);
// calculate final color
Vector256<float> color = SimdUtils.HwIntrinsics.MultiplyAdd(destination, dstW, Avx.Multiply(blend, blendW));
// unpremultiply
color = Avx.Divide(color, Avx.Max(alpha, Constants.Epsilon256));
return Avx.Blend(color, alpha, blendAlphaControl);
}
/// <summary>
/// Returns the result of the "In" compositing equation.
/// </summary>
@ -220,6 +342,31 @@ internal static partial class PorterDuffFunctions
return color;
}
/// <summary>
/// Returns the result of the "In" compositing equation.
/// </summary>
/// <param name="destination">The destination vector.</param>
/// <param name="source">The source vector.</param>
/// <returns>The <see cref="Vector256{Single}"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector256<float> In(Vector256<float> destination, Vector256<float> source)
{
const int blendAlphaControl = 0b_10_00_10_00;
const int shuffleAlphaControl = 0b_11_11_11_11;
// calculate alpha
Vector256<float> sW = Avx.Shuffle(source, source, shuffleAlphaControl);
Vector256<float> dW = Avx.Shuffle(destination, destination, shuffleAlphaControl);
Vector256<float> alpha = Avx.Multiply(sW, dW);
// premultiply
Vector256<float> color = Avx.Multiply(source, alpha);
// unpremultiply
color = Avx.Divide(color, Avx.Max(alpha, Constants.Epsilon256));
return Avx.Blend(color, alpha, blendAlphaControl);
}
/// <summary>
/// Returns the result of the "Out" compositing equation.
/// </summary>
@ -238,6 +385,31 @@ internal static partial class PorterDuffFunctions
return color;
}
/// <summary>
/// Returns the result of the "Out" compositing equation.
/// </summary>
/// <param name="destination">The destination vector.</param>
/// <param name="source">The source vector.</param>
/// <returns>The <see cref="Vector256{Single}"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector256<float> Out(Vector256<float> destination, Vector256<float> source)
{
const int blendAlphaControl = 0b_10_00_10_00;
const int shuffleAlphaControl = 0b_11_11_11_11;
// calculate alpha
Vector256<float> sW = Avx.Shuffle(source, source, shuffleAlphaControl);
Vector256<float> dW = Avx.Shuffle(destination, destination, shuffleAlphaControl);
Vector256<float> alpha = Avx.Multiply(Avx.Subtract(Vector256.Create(1F), dW), sW);
// premultiply
Vector256<float> color = Avx.Multiply(source, alpha);
// unpremultiply
color = Avx.Divide(color, Avx.Max(alpha, Constants.Epsilon256));
return Avx.Blend(color, alpha, blendAlphaControl);
}
/// <summary>
/// Returns the result of the "XOr" compositing equation.
/// </summary>
@ -260,9 +432,38 @@ internal static partial class PorterDuffFunctions
return color;
}
/// <summary>
/// Returns the result of the "XOr" compositing equation.
/// </summary>
/// <param name="destination">The destination vector.</param>
/// <param name="source">The source vector.</param>
/// <returns>The <see cref="Vector256{Single}"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Vector4 Clear(Vector4 backdrop, Vector4 source)
public static Vector256<float> Xor(Vector256<float> destination, Vector256<float> source)
{
return Vector4.Zero;
const int blendAlphaControl = 0b_10_00_10_00;
const int shuffleAlphaControl = 0b_11_11_11_11;
// calculate weights
Vector256<float> sW = Avx.Shuffle(source, source, shuffleAlphaControl);
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);
// calculate alpha
Vector256<float> alpha = SimdUtils.HwIntrinsics.MultiplyAdd(sW, srcW, Avx.Multiply(dW, dstW));
Vector256<float> color = SimdUtils.HwIntrinsics.MultiplyAdd(Avx.Multiply(sW, source), srcW, Avx.Multiply(Avx.Multiply(dW, destination), dstW));
// unpremultiply
color = Avx.Divide(color, Avx.Max(alpha, Constants.Epsilon256));
return Avx.Blend(color, alpha, blendAlphaControl);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Vector4 Clear(Vector4 backdrop, Vector4 source) => Vector4.Zero;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Vector256<float> Clear(Vector256<float> backdrop, Vector256<float> source) => Vector256<float>.Zero;
}

Loading…
Cancel
Save