|
|
|
@ -401,6 +401,450 @@ var blenders = new []{ |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/// <inheritdoc /> |
|
|
|
protected override void BlendWithCoverageFunction(Span<Vector4> destination, ReadOnlySpan<Vector4> background, ReadOnlySpan<Vector4> source, float amount, ReadOnlySpan<float> coverage) |
|
|
|
{ |
|
|
|
amount = Numerics.Clamp(amount, 0, 1); |
|
|
|
|
|
|
|
if (Avx512F.IsSupported && destination.Length >= 4) |
|
|
|
{ |
|
|
|
// Divide by 4 as 4 elements per Vector4 and 16 per Vector512<float> |
|
|
|
ref Vector512<float> destinationBase = ref Unsafe.As<Vector4, Vector512<float>>(ref MemoryMarshal.GetReference(destination)); |
|
|
|
ref Vector512<float> destinationLast = ref Unsafe.Add(ref destinationBase, (uint)destination.Length / 4u); |
|
|
|
|
|
|
|
ref Vector512<float> backgroundBase = ref Unsafe.As<Vector4, Vector512<float>>(ref MemoryMarshal.GetReference(background)); |
|
|
|
ref Vector512<float> sourceBase = ref Unsafe.As<Vector4, Vector512<float>>(ref MemoryMarshal.GetReference(source)); |
|
|
|
ref float coverageBase = ref MemoryMarshal.GetReference(coverage); |
|
|
|
Vector512<float> opacity = Vector512.Create(amount); |
|
|
|
Vector512<float> vOne = Vector512.Create(1F); |
|
|
|
|
|
|
|
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); |
|
|
|
|
|
|
|
// We need to create a Vector512<float> containing the current four coverage values |
|
|
|
// taking up each quarter of the Vector512<float> and then clamp them. |
|
|
|
Vector512<float> 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<float>.Zero, coverageVector), vOne); |
|
|
|
|
|
|
|
Vector512<float> blended = PorterDuffFunctions.<#=blender_composer#>(backgroundBase, sourceBase, opacity); |
|
|
|
destinationBase = PorterDuffFunctions.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); |
|
|
|
} |
|
|
|
|
|
|
|
int remainder = Numerics.Modulo4(destination.Length); |
|
|
|
if (remainder != 0) |
|
|
|
{ |
|
|
|
for (int i = destination.Length - remainder; i < destination.Length; i++) |
|
|
|
{ |
|
|
|
Vector4 blended = PorterDuffFunctions.<#=blender_composer#>(background[i], source[i], amount); |
|
|
|
destination[i] = PorterDuffFunctions.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<float> |
|
|
|
ref Vector256<float> destinationBase = ref Unsafe.As<Vector4, Vector256<float>>(ref MemoryMarshal.GetReference(destination)); |
|
|
|
ref Vector256<float> destinationLast = ref Unsafe.Add(ref destinationBase, (uint)destination.Length / 2u); |
|
|
|
|
|
|
|
ref Vector256<float> backgroundBase = ref Unsafe.As<Vector4, Vector256<float>>(ref MemoryMarshal.GetReference(background)); |
|
|
|
ref Vector256<float> sourceBase = ref Unsafe.As<Vector4, Vector256<float>>(ref MemoryMarshal.GetReference(source)); |
|
|
|
ref float coverageBase = ref MemoryMarshal.GetReference(coverage); |
|
|
|
Vector256<float> opacity = Vector256.Create(amount); |
|
|
|
Vector256<float> vOne = Vector256.Create(1F); |
|
|
|
|
|
|
|
while (Unsafe.IsAddressLessThan(ref destinationBase, ref destinationLast)) |
|
|
|
{ |
|
|
|
// We need to create a Vector256<float> containing the current and next coverage values |
|
|
|
// taking up each half of the Vector256<float> and then clamp them. |
|
|
|
Vector256<float> coverageVector = Vector256.Create( |
|
|
|
Vector128.Create(coverageBase), |
|
|
|
Vector128.Create(Unsafe.Add(ref coverageBase, 1))); |
|
|
|
coverageVector = Avx.Min(Avx.Max(Vector256<float>.Zero, coverageVector), vOne); |
|
|
|
|
|
|
|
Vector256<float> blended = PorterDuffFunctions.<#=blender_composer#>(backgroundBase, sourceBase, opacity); |
|
|
|
destinationBase = PorterDuffFunctions.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, 2); |
|
|
|
} |
|
|
|
|
|
|
|
if (Numerics.Modulo2(destination.Length) != 0) |
|
|
|
{ |
|
|
|
// Vector4 fits neatly in pairs. Any overlap has to be equal to 1. |
|
|
|
int i = destination.Length - 1; |
|
|
|
Vector4 blended = PorterDuffFunctions.<#=blender_composer#>(background[i], source[i], amount); |
|
|
|
destination[i] = PorterDuffFunctions.BlendWithCoverage(background[i], blended, Numerics.Clamp(coverage[i], 0, 1F)); |
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
for (int i = 0; i < destination.Length; i++) |
|
|
|
{ |
|
|
|
Vector4 blended = PorterDuffFunctions.<#=blender_composer#>(background[i], source[i], amount); |
|
|
|
destination[i] = PorterDuffFunctions.BlendWithCoverage(background[i], blended, Numerics.Clamp(coverage[i], 0, 1F)); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/// <inheritdoc /> |
|
|
|
protected override void BlendWithCoverageFunction(Span<Vector4> destination, ReadOnlySpan<Vector4> background, Vector4 source, float amount, ReadOnlySpan<float> coverage) |
|
|
|
{ |
|
|
|
amount = Numerics.Clamp(amount, 0, 1); |
|
|
|
|
|
|
|
if (Avx512F.IsSupported && destination.Length >= 4) |
|
|
|
{ |
|
|
|
// Divide by 4 as 4 elements per Vector4 and 16 per Vector512<float> |
|
|
|
ref Vector512<float> destinationBase = ref Unsafe.As<Vector4, Vector512<float>>(ref MemoryMarshal.GetReference(destination)); |
|
|
|
ref Vector512<float> destinationLast = ref Unsafe.Add(ref destinationBase, (uint)destination.Length / 4u); |
|
|
|
|
|
|
|
ref Vector512<float> backgroundBase = ref Unsafe.As<Vector4, Vector512<float>>(ref MemoryMarshal.GetReference(background)); |
|
|
|
ref float coverageBase = ref MemoryMarshal.GetReference(coverage); |
|
|
|
|
|
|
|
Vector512<float> 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<float> opacity = Vector512.Create(amount); |
|
|
|
Vector512<float> vOne = Vector512.Create(1F); |
|
|
|
|
|
|
|
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); |
|
|
|
|
|
|
|
// We need to create a Vector512<float> containing the current four coverage values |
|
|
|
// taking up each quarter of the Vector512<float> and then clamp them. |
|
|
|
Vector512<float> 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<float>.Zero, coverageVector), vOne); |
|
|
|
|
|
|
|
Vector512<float> blended = PorterDuffFunctions.<#=blender_composer#>(backgroundBase, sourceBase, opacity); |
|
|
|
destinationBase = PorterDuffFunctions.BlendWithCoverage(backgroundBase, blended, coverageVector); |
|
|
|
destinationBase = ref Unsafe.Add(ref destinationBase, 1); |
|
|
|
backgroundBase = ref Unsafe.Add(ref backgroundBase, 1); |
|
|
|
coverageBase = ref Unsafe.Add(ref coverageBase, 4); |
|
|
|
} |
|
|
|
|
|
|
|
int remainder = Numerics.Modulo4(destination.Length); |
|
|
|
if (remainder != 0) |
|
|
|
{ |
|
|
|
for (int i = destination.Length - remainder; i < destination.Length; i++) |
|
|
|
{ |
|
|
|
Vector4 blended = PorterDuffFunctions.<#=blender_composer#>(background[i], source, amount); |
|
|
|
destination[i] = PorterDuffFunctions.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<float> |
|
|
|
ref Vector256<float> destinationBase = ref Unsafe.As<Vector4, Vector256<float>>(ref MemoryMarshal.GetReference(destination)); |
|
|
|
ref Vector256<float> destinationLast = ref Unsafe.Add(ref destinationBase, (uint)destination.Length / 2u); |
|
|
|
|
|
|
|
ref Vector256<float> backgroundBase = ref Unsafe.As<Vector4, Vector256<float>>(ref MemoryMarshal.GetReference(background)); |
|
|
|
ref float coverageBase = ref MemoryMarshal.GetReference(coverage); |
|
|
|
|
|
|
|
Vector256<float> sourceBase = Vector256.Create(source.X, source.Y, source.Z, source.W, source.X, source.Y, source.Z, source.W); |
|
|
|
Vector256<float> opacity = Vector256.Create(amount); |
|
|
|
Vector256<float> vOne = Vector256.Create(1F); |
|
|
|
|
|
|
|
while (Unsafe.IsAddressLessThan(ref destinationBase, ref destinationLast)) |
|
|
|
{ |
|
|
|
// We need to create a Vector256<float> containing the current and next coverage values |
|
|
|
// taking up each half of the Vector256<float> and then clamp them. |
|
|
|
Vector256<float> coverageVector = Vector256.Create( |
|
|
|
Vector128.Create(coverageBase), |
|
|
|
Vector128.Create(Unsafe.Add(ref coverageBase, 1))); |
|
|
|
coverageVector = Avx.Min(Avx.Max(Vector256<float>.Zero, coverageVector), vOne); |
|
|
|
|
|
|
|
Vector256<float> blended = PorterDuffFunctions.<#=blender_composer#>(backgroundBase, sourceBase, opacity); |
|
|
|
destinationBase = PorterDuffFunctions.BlendWithCoverage(backgroundBase, blended, coverageVector); |
|
|
|
destinationBase = ref Unsafe.Add(ref destinationBase, 1); |
|
|
|
backgroundBase = ref Unsafe.Add(ref backgroundBase, 1); |
|
|
|
coverageBase = ref Unsafe.Add(ref coverageBase, 2); |
|
|
|
} |
|
|
|
|
|
|
|
if (Numerics.Modulo2(destination.Length) != 0) |
|
|
|
{ |
|
|
|
// Vector4 fits neatly in pairs. Any overlap has to be equal to 1. |
|
|
|
int i = destination.Length - 1; |
|
|
|
Vector4 blended = PorterDuffFunctions.<#=blender_composer#>(background[i], source, amount); |
|
|
|
destination[i] = PorterDuffFunctions.BlendWithCoverage(background[i], blended, Numerics.Clamp(coverage[i], 0, 1F)); |
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
for (int i = 0; i < destination.Length; i++) |
|
|
|
{ |
|
|
|
Vector4 blended = PorterDuffFunctions.<#=blender_composer#>(background[i], source, amount); |
|
|
|
destination[i] = PorterDuffFunctions.BlendWithCoverage(background[i], blended, Numerics.Clamp(coverage[i], 0, 1F)); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/// <inheritdoc /> |
|
|
|
protected override void BlendWithCoverageFunction(Span<Vector4> destination, ReadOnlySpan<Vector4> background, ReadOnlySpan<Vector4> source, ReadOnlySpan<float> amount, ReadOnlySpan<float> coverage) |
|
|
|
{ |
|
|
|
if (Avx512F.IsSupported && destination.Length >= 4) |
|
|
|
{ |
|
|
|
// Divide by 4 as 4 elements per Vector4 and 16 per Vector512<float> |
|
|
|
ref Vector512<float> destinationBase = ref Unsafe.As<Vector4, Vector512<float>>(ref MemoryMarshal.GetReference(destination)); |
|
|
|
ref Vector512<float> destinationLast = ref Unsafe.Add(ref destinationBase, (uint)destination.Length / 4u); |
|
|
|
|
|
|
|
ref Vector512<float> backgroundBase = ref Unsafe.As<Vector4, Vector512<float>>(ref MemoryMarshal.GetReference(background)); |
|
|
|
ref Vector512<float> sourceBase = ref Unsafe.As<Vector4, Vector512<float>>(ref MemoryMarshal.GetReference(source)); |
|
|
|
ref float amountBase = ref MemoryMarshal.GetReference(amount); |
|
|
|
ref float coverageBase = ref MemoryMarshal.GetReference(coverage); |
|
|
|
|
|
|
|
Vector512<float> vOne = Vector512.Create(1F); |
|
|
|
|
|
|
|
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); |
|
|
|
|
|
|
|
// We need to create a Vector512<float> containing the current four amount values |
|
|
|
// taking up each quarter of the Vector512<float> and then clamp them. |
|
|
|
Vector512<float> 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<float>.Zero, opacity), vOne); |
|
|
|
|
|
|
|
float coverage0 = coverageBase; |
|
|
|
float coverage1 = Unsafe.Add(ref coverageBase, 1); |
|
|
|
float coverage2 = Unsafe.Add(ref coverageBase, 2); |
|
|
|
float coverage3 = Unsafe.Add(ref coverageBase, 3); |
|
|
|
|
|
|
|
// We need to create a Vector512<float> containing the current four coverage values |
|
|
|
// taking up each quarter of the Vector512<float> and then clamp them. |
|
|
|
Vector512<float> 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<float>.Zero, coverageVector), vOne); |
|
|
|
|
|
|
|
Vector512<float> blended = PorterDuffFunctions.<#=blender_composer#>(backgroundBase, sourceBase, opacity); |
|
|
|
destinationBase = PorterDuffFunctions.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); |
|
|
|
amountBase = ref Unsafe.Add(ref amountBase, 4); |
|
|
|
coverageBase = ref Unsafe.Add(ref coverageBase, 4); |
|
|
|
} |
|
|
|
|
|
|
|
int remainder = Numerics.Modulo4(destination.Length); |
|
|
|
if (remainder != 0) |
|
|
|
{ |
|
|
|
for (int i = destination.Length - remainder; i < destination.Length; i++) |
|
|
|
{ |
|
|
|
Vector4 blended = PorterDuffFunctions.<#=blender_composer#>(background[i], source[i], Numerics.Clamp(amount[i], 0, 1F)); |
|
|
|
destination[i] = PorterDuffFunctions.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<float> |
|
|
|
ref Vector256<float> destinationBase = ref Unsafe.As<Vector4, Vector256<float>>(ref MemoryMarshal.GetReference(destination)); |
|
|
|
ref Vector256<float> destinationLast = ref Unsafe.Add(ref destinationBase, (uint)destination.Length / 2u); |
|
|
|
|
|
|
|
ref Vector256<float> backgroundBase = ref Unsafe.As<Vector4, Vector256<float>>(ref MemoryMarshal.GetReference(background)); |
|
|
|
ref Vector256<float> sourceBase = ref Unsafe.As<Vector4, Vector256<float>>(ref MemoryMarshal.GetReference(source)); |
|
|
|
ref float amountBase = ref MemoryMarshal.GetReference(amount); |
|
|
|
ref float coverageBase = ref MemoryMarshal.GetReference(coverage); |
|
|
|
|
|
|
|
Vector256<float> vOne = Vector256.Create(1F); |
|
|
|
|
|
|
|
while (Unsafe.IsAddressLessThan(ref destinationBase, ref destinationLast)) |
|
|
|
{ |
|
|
|
// We need to create a Vector256<float> containing the current and next amount values |
|
|
|
// taking up each half of the Vector256<float> and then clamp them. |
|
|
|
Vector256<float> opacity = Vector256.Create( |
|
|
|
Vector128.Create(amountBase), |
|
|
|
Vector128.Create(Unsafe.Add(ref amountBase, 1))); |
|
|
|
opacity = Avx.Min(Avx.Max(Vector256<float>.Zero, opacity), vOne); |
|
|
|
|
|
|
|
// We need to create a Vector256<float> containing the current and next coverage values |
|
|
|
// taking up each half of the Vector256<float> and then clamp them. |
|
|
|
Vector256<float> coverageVector = Vector256.Create( |
|
|
|
Vector128.Create(coverageBase), |
|
|
|
Vector128.Create(Unsafe.Add(ref coverageBase, 1))); |
|
|
|
coverageVector = Avx.Min(Avx.Max(Vector256<float>.Zero, coverageVector), vOne); |
|
|
|
|
|
|
|
Vector256<float> blended = PorterDuffFunctions.<#=blender_composer#>(backgroundBase, sourceBase, opacity); |
|
|
|
destinationBase = PorterDuffFunctions.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); |
|
|
|
amountBase = ref Unsafe.Add(ref amountBase, 2); |
|
|
|
coverageBase = ref Unsafe.Add(ref coverageBase, 2); |
|
|
|
} |
|
|
|
|
|
|
|
if (Numerics.Modulo2(destination.Length) != 0) |
|
|
|
{ |
|
|
|
// Vector4 fits neatly in pairs. Any overlap has to be equal to 1. |
|
|
|
int i = destination.Length - 1; |
|
|
|
Vector4 blended = PorterDuffFunctions.<#=blender_composer#>(background[i], source[i], Numerics.Clamp(amount[i], 0, 1F)); |
|
|
|
destination[i] = PorterDuffFunctions.BlendWithCoverage(background[i], blended, Numerics.Clamp(coverage[i], 0, 1F)); |
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
for (int i = 0; i < destination.Length; i++) |
|
|
|
{ |
|
|
|
Vector4 blended = PorterDuffFunctions.<#=blender_composer#>(background[i], source[i], Numerics.Clamp(amount[i], 0, 1F)); |
|
|
|
destination[i] = PorterDuffFunctions.BlendWithCoverage(background[i], blended, Numerics.Clamp(coverage[i], 0, 1F)); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/// <inheritdoc /> |
|
|
|
protected override void BlendWithCoverageFunction(Span<Vector4> destination, ReadOnlySpan<Vector4> background, Vector4 source, ReadOnlySpan<float> amount, ReadOnlySpan<float> coverage) |
|
|
|
{ |
|
|
|
if (Avx512F.IsSupported && destination.Length >= 4) |
|
|
|
{ |
|
|
|
// Divide by 4 as 4 elements per Vector4 and 16 per Vector512<float> |
|
|
|
ref Vector512<float> destinationBase = ref Unsafe.As<Vector4, Vector512<float>>(ref MemoryMarshal.GetReference(destination)); |
|
|
|
ref Vector512<float> destinationLast = ref Unsafe.Add(ref destinationBase, (uint)destination.Length / 4u); |
|
|
|
|
|
|
|
ref Vector512<float> backgroundBase = ref Unsafe.As<Vector4, Vector512<float>>(ref MemoryMarshal.GetReference(background)); |
|
|
|
ref float amountBase = ref MemoryMarshal.GetReference(amount); |
|
|
|
ref float coverageBase = ref MemoryMarshal.GetReference(coverage); |
|
|
|
|
|
|
|
Vector512<float> 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<float> vOne = Vector512.Create(1F); |
|
|
|
|
|
|
|
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); |
|
|
|
|
|
|
|
// We need to create a Vector512<float> containing the current four amount values |
|
|
|
// taking up each quarter of the Vector512<float> and then clamp them. |
|
|
|
Vector512<float> 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<float>.Zero, opacity), vOne); |
|
|
|
|
|
|
|
float coverage0 = coverageBase; |
|
|
|
float coverage1 = Unsafe.Add(ref coverageBase, 1); |
|
|
|
float coverage2 = Unsafe.Add(ref coverageBase, 2); |
|
|
|
float coverage3 = Unsafe.Add(ref coverageBase, 3); |
|
|
|
|
|
|
|
// We need to create a Vector512<float> containing the current four coverage values |
|
|
|
// taking up each quarter of the Vector512<float> and then clamp them. |
|
|
|
Vector512<float> 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<float>.Zero, coverageVector), vOne); |
|
|
|
|
|
|
|
Vector512<float> blended = PorterDuffFunctions.<#=blender_composer#>(backgroundBase, sourceBase, opacity); |
|
|
|
destinationBase = PorterDuffFunctions.BlendWithCoverage(backgroundBase, blended, coverageVector); |
|
|
|
destinationBase = ref Unsafe.Add(ref destinationBase, 1); |
|
|
|
backgroundBase = ref Unsafe.Add(ref backgroundBase, 1); |
|
|
|
amountBase = ref Unsafe.Add(ref amountBase, 4); |
|
|
|
coverageBase = ref Unsafe.Add(ref coverageBase, 4); |
|
|
|
} |
|
|
|
|
|
|
|
int remainder = Numerics.Modulo4(destination.Length); |
|
|
|
if (remainder != 0) |
|
|
|
{ |
|
|
|
for (int i = destination.Length - remainder; i < destination.Length; i++) |
|
|
|
{ |
|
|
|
Vector4 blended = PorterDuffFunctions.<#=blender_composer#>(background[i], source, Numerics.Clamp(amount[i], 0, 1F)); |
|
|
|
destination[i] = PorterDuffFunctions.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<float> |
|
|
|
ref Vector256<float> destinationBase = ref Unsafe.As<Vector4, Vector256<float>>(ref MemoryMarshal.GetReference(destination)); |
|
|
|
ref Vector256<float> destinationLast = ref Unsafe.Add(ref destinationBase, (uint)destination.Length / 2u); |
|
|
|
|
|
|
|
ref Vector256<float> backgroundBase = ref Unsafe.As<Vector4, Vector256<float>>(ref MemoryMarshal.GetReference(background)); |
|
|
|
ref float amountBase = ref MemoryMarshal.GetReference(amount); |
|
|
|
ref float coverageBase = ref MemoryMarshal.GetReference(coverage); |
|
|
|
|
|
|
|
Vector256<float> sourceBase = Vector256.Create(source.X, source.Y, source.Z, source.W, source.X, source.Y, source.Z, source.W); |
|
|
|
Vector256<float> vOne = Vector256.Create(1F); |
|
|
|
|
|
|
|
while (Unsafe.IsAddressLessThan(ref destinationBase, ref destinationLast)) |
|
|
|
{ |
|
|
|
// We need to create a Vector256<float> containing the current and next amount values |
|
|
|
// taking up each half of the Vector256<float> and then clamp them. |
|
|
|
Vector256<float> opacity = Vector256.Create( |
|
|
|
Vector128.Create(amountBase), |
|
|
|
Vector128.Create(Unsafe.Add(ref amountBase, 1))); |
|
|
|
opacity = Avx.Min(Avx.Max(Vector256<float>.Zero, opacity), vOne); |
|
|
|
|
|
|
|
// We need to create a Vector256<float> containing the current and next coverage values |
|
|
|
// taking up each half of the Vector256<float> and then clamp them. |
|
|
|
Vector256<float> coverageVector = Vector256.Create( |
|
|
|
Vector128.Create(coverageBase), |
|
|
|
Vector128.Create(Unsafe.Add(ref coverageBase, 1))); |
|
|
|
coverageVector = Avx.Min(Avx.Max(Vector256<float>.Zero, coverageVector), vOne); |
|
|
|
|
|
|
|
Vector256<float> blended = PorterDuffFunctions.<#=blender_composer#>(backgroundBase, sourceBase, opacity); |
|
|
|
destinationBase = PorterDuffFunctions.BlendWithCoverage(backgroundBase, blended, coverageVector); |
|
|
|
destinationBase = ref Unsafe.Add(ref destinationBase, 1); |
|
|
|
backgroundBase = ref Unsafe.Add(ref backgroundBase, 1); |
|
|
|
amountBase = ref Unsafe.Add(ref amountBase, 2); |
|
|
|
coverageBase = ref Unsafe.Add(ref coverageBase, 2); |
|
|
|
} |
|
|
|
|
|
|
|
if (Numerics.Modulo2(destination.Length) != 0) |
|
|
|
{ |
|
|
|
// Vector4 fits neatly in pairs. Any overlap has to be equal to 1. |
|
|
|
int i = destination.Length - 1; |
|
|
|
Vector4 blended = PorterDuffFunctions.<#=blender_composer#>(background[i], source, Numerics.Clamp(amount[i], 0, 1F)); |
|
|
|
destination[i] = PorterDuffFunctions.BlendWithCoverage(background[i], blended, Numerics.Clamp(coverage[i], 0, 1F)); |
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
for (int i = 0; i < destination.Length; i++) |
|
|
|
{ |
|
|
|
Vector4 blended = PorterDuffFunctions.<#=blender_composer#>(background[i], source, Numerics.Clamp(amount[i], 0, 1F)); |
|
|
|
destination[i] = PorterDuffFunctions.BlendWithCoverage(background[i], blended, Numerics.Clamp(coverage[i], 0, 1F)); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
<# |
|
|
|
|