Skip to content

Commit c58be60

Browse files
Add additional PD tests
1 parent b4ff1e4 commit c58be60

File tree

3 files changed

+119
-6
lines changed

3 files changed

+119
-6
lines changed

src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ public static Vector4 Subtract(Vector4 backdrop, Vector4 source)
102102
/// <returns>The <see cref="Vector256{Single}"/>.</returns>
103103
[MethodImpl(MethodImplOptions.AggressiveInlining)]
104104
public static Vector256<float> Subtract(Vector256<float> backdrop, Vector256<float> source)
105-
=> Avx.Min(Vector256.Create(1F), Avx.Subtract(backdrop, source));
105+
=> Avx.Max(Vector256<float>.Zero, Avx.Subtract(backdrop, source));
106106

107107
/// <summary>
108108
/// Returns the result of the "Screen" compositing equation.

tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffFunctionsTests.cs

Lines changed: 102 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders;
1010

1111
public class PorterDuffFunctionsTests
1212
{
13+
private static readonly ApproximateFloatComparer FloatComparer = new(.000001F);
14+
1315
public static TheoryData<TestVector4, TestVector4, float, TestVector4> NormalBlendFunctionData { get; } = new()
1416
{
1517
{ new TestVector4(1, 1, 1, 1), new TestVector4(1, 1, 1, 1), 1, new TestVector4(1, 1, 1, 1) },
@@ -33,7 +35,7 @@ public void NormalBlendFunction256(TestVector4 back, TestVector4 source, float a
3335

3436
Vector256<float> expected256 = Vector256.Create(expected.X, expected.Y, expected.Z, expected.W, expected.X, expected.Y, expected.Z, expected.W);
3537
Vector256<float> actual = PorterDuffFunctions.NormalSrcOver(back256, source256, Vector256.Create(amount));
36-
Assert.Equal(expected256, actual);
38+
Assert.Equal(expected256, actual, FloatComparer);
3739
}
3840

3941
public static TheoryData<TestVector4, TestVector4, float, TestVector4> MultiplyFunctionData { get; } = new()
@@ -51,21 +53,45 @@ public void MultiplyFunction(TestVector4 back, TestVector4 source, float amount,
5153
VectorAssert.Equal(expected, actual, 5);
5254
}
5355

56+
[Theory]
57+
[MemberData(nameof(MultiplyFunctionData))]
58+
public void MultiplyFunction256(TestVector4 back, TestVector4 source, float amount, TestVector4 expected)
59+
{
60+
Vector256<float> back256 = Vector256.Create(back.X, back.Y, back.Z, back.W, back.X, back.Y, back.Z, back.W);
61+
Vector256<float> source256 = Vector256.Create(source.X, source.Y, source.Z, source.W, source.X, source.Y, source.Z, source.W);
62+
63+
Vector256<float> expected256 = Vector256.Create(expected.X, expected.Y, expected.Z, expected.W, expected.X, expected.Y, expected.Z, expected.W);
64+
Vector256<float> actual = PorterDuffFunctions.MultiplySrcOver(back256, source256, Vector256.Create(amount));
65+
Assert.Equal(expected256, actual, FloatComparer);
66+
}
67+
5468
public static TheoryData<TestVector4, TestVector4, float, TestVector4> AddFunctionData { get; } = new()
5569
{
5670
{ new TestVector4(1, 1, 1, 1), new TestVector4(1, 1, 1, 1), 1, new TestVector4(1, 1, 1, 1) },
57-
{ new TestVector4(1, 1, 1, 1), new TestVector4(0, 0, 0, .8f), .5f, new TestVector4(.6f, .6f, .6f, 1f) },
58-
{ new TestVector4(0.2f, 0.2f, 0.2f, 0.3f), new TestVector4(0.3f, 0.3f, 0.3f, 0.2f), .5f, new TestVector4(.2075676f, .2075676f, .2075676f, .37f) }
71+
{ new TestVector4(1, 1, 1, 1), new TestVector4(0, 0, 0, .8f), .5f, new TestVector4(1, 1, 1, 1) },
72+
{ new TestVector4(0.2f, 0.2f, 0.2f, 0.3f), new TestVector4(0.3f, 0.3f, 0.3f, 0.2f), .5f, new TestVector4(0.24324325f, 0.24324325f, 0.24324325f, .37f) }
5973
};
6074

6175
[Theory]
6276
[MemberData(nameof(AddFunctionData))]
6377
public void AddFunction(TestVector4 back, TestVector4 source, float amount, TestVector4 expected)
6478
{
65-
Vector4 actual = PorterDuffFunctions.MultiplySrcOver((Vector4)back, source, amount);
79+
Vector4 actual = PorterDuffFunctions.AddSrcOver((Vector4)back, source, amount);
6680
VectorAssert.Equal(expected, actual, 5);
6781
}
6882

83+
[Theory]
84+
[MemberData(nameof(AddFunctionData))]
85+
public void AddFunction256(TestVector4 back, TestVector4 source, float amount, TestVector4 expected)
86+
{
87+
Vector256<float> back256 = Vector256.Create(back.X, back.Y, back.Z, back.W, back.X, back.Y, back.Z, back.W);
88+
Vector256<float> source256 = Vector256.Create(source.X, source.Y, source.Z, source.W, source.X, source.Y, source.Z, source.W);
89+
90+
Vector256<float> expected256 = Vector256.Create(expected.X, expected.Y, expected.Z, expected.W, expected.X, expected.Y, expected.Z, expected.W);
91+
Vector256<float> actual = PorterDuffFunctions.AddSrcOver(back256, source256, Vector256.Create(amount));
92+
Assert.Equal(expected256, actual, FloatComparer);
93+
}
94+
6995
public static TheoryData<TestVector4, TestVector4, float, TestVector4> SubtractFunctionData { get; } = new()
7096
{
7197
{ new TestVector4(1, 1, 1, 1), new TestVector4(1, 1, 1, 1), 1, new TestVector4(0, 0, 0, 1) },
@@ -81,6 +107,18 @@ public void SubtractFunction(TestVector4 back, TestVector4 source, float amount,
81107
VectorAssert.Equal(expected, actual, 5);
82108
}
83109

110+
[Theory]
111+
[MemberData(nameof(SubtractFunctionData))]
112+
public void SubtractFunction256(TestVector4 back, TestVector4 source, float amount, TestVector4 expected)
113+
{
114+
Vector256<float> back256 = Vector256.Create(back.X, back.Y, back.Z, back.W, back.X, back.Y, back.Z, back.W);
115+
Vector256<float> source256 = Vector256.Create(source.X, source.Y, source.Z, source.W, source.X, source.Y, source.Z, source.W);
116+
117+
Vector256<float> expected256 = Vector256.Create(expected.X, expected.Y, expected.Z, expected.W, expected.X, expected.Y, expected.Z, expected.W);
118+
Vector256<float> actual = PorterDuffFunctions.SubtractSrcOver(back256, source256, Vector256.Create(amount));
119+
Assert.Equal(expected256, actual, FloatComparer);
120+
}
121+
84122
public static TheoryData<TestVector4, TestVector4, float, TestVector4> ScreenFunctionData { get; } = new()
85123
{
86124
{ new TestVector4(1, 1, 1, 1), new TestVector4(1, 1, 1, 1), 1, new TestVector4(1, 1, 1, 1) },
@@ -96,6 +134,18 @@ public void ScreenFunction(TestVector4 back, TestVector4 source, float amount, T
96134
VectorAssert.Equal(expected, actual, 5);
97135
}
98136

137+
[Theory]
138+
[MemberData(nameof(ScreenFunctionData))]
139+
public void ScreenFunction256(TestVector4 back, TestVector4 source, float amount, TestVector4 expected)
140+
{
141+
Vector256<float> back256 = Vector256.Create(back.X, back.Y, back.Z, back.W, back.X, back.Y, back.Z, back.W);
142+
Vector256<float> source256 = Vector256.Create(source.X, source.Y, source.Z, source.W, source.X, source.Y, source.Z, source.W);
143+
144+
Vector256<float> expected256 = Vector256.Create(expected.X, expected.Y, expected.Z, expected.W, expected.X, expected.Y, expected.Z, expected.W);
145+
Vector256<float> actual = PorterDuffFunctions.ScreenSrcOver(back256, source256, Vector256.Create(amount));
146+
Assert.Equal(expected256, actual, FloatComparer);
147+
}
148+
99149
public static TheoryData<TestVector4, TestVector4, float, TestVector4> DarkenFunctionData { get; } = new()
100150
{
101151
{ new TestVector4(1, 1, 1, 1), new TestVector4(1, 1, 1, 1), 1, new TestVector4(1, 1, 1, 1) },
@@ -111,6 +161,18 @@ public void DarkenFunction(TestVector4 back, TestVector4 source, float amount, T
111161
VectorAssert.Equal(expected, actual, 5);
112162
}
113163

164+
[Theory]
165+
[MemberData(nameof(DarkenFunctionData))]
166+
public void DarkenFunction256(TestVector4 back, TestVector4 source, float amount, TestVector4 expected)
167+
{
168+
Vector256<float> back256 = Vector256.Create(back.X, back.Y, back.Z, back.W, back.X, back.Y, back.Z, back.W);
169+
Vector256<float> source256 = Vector256.Create(source.X, source.Y, source.Z, source.W, source.X, source.Y, source.Z, source.W);
170+
171+
Vector256<float> expected256 = Vector256.Create(expected.X, expected.Y, expected.Z, expected.W, expected.X, expected.Y, expected.Z, expected.W);
172+
Vector256<float> actual = PorterDuffFunctions.DarkenSrcOver(back256, source256, Vector256.Create(amount));
173+
Assert.Equal(expected256, actual, FloatComparer);
174+
}
175+
114176
public static TheoryData<TestVector4, TestVector4, float, TestVector4> LightenFunctionData { get; } = new()
115177
{
116178
{ new TestVector4(1, 1, 1, 1), new TestVector4(1, 1, 1, 1), 1, new TestVector4(1, 1, 1, 1) },
@@ -126,6 +188,18 @@ public void LightenFunction(TestVector4 back, TestVector4 source, float amount,
126188
VectorAssert.Equal(expected, actual, 5);
127189
}
128190

191+
[Theory]
192+
[MemberData(nameof(LightenFunctionData))]
193+
public void LightenFunction256(TestVector4 back, TestVector4 source, float amount, TestVector4 expected)
194+
{
195+
Vector256<float> back256 = Vector256.Create(back.X, back.Y, back.Z, back.W, back.X, back.Y, back.Z, back.W);
196+
Vector256<float> source256 = Vector256.Create(source.X, source.Y, source.Z, source.W, source.X, source.Y, source.Z, source.W);
197+
198+
Vector256<float> expected256 = Vector256.Create(expected.X, expected.Y, expected.Z, expected.W, expected.X, expected.Y, expected.Z, expected.W);
199+
Vector256<float> actual = PorterDuffFunctions.LightenSrcOver(back256, source256, Vector256.Create(amount));
200+
Assert.Equal(expected256, actual, FloatComparer);
201+
}
202+
129203
public static TheoryData<TestVector4, TestVector4, float, TestVector4> OverlayFunctionData { get; } = new()
130204
{
131205
{ new TestVector4(1, 1, 1, 1), new TestVector4(1, 1, 1, 1), 1, new TestVector4(1, 1, 1, 1) },
@@ -141,6 +215,18 @@ public void OverlayFunction(TestVector4 back, TestVector4 source, float amount,
141215
VectorAssert.Equal(expected, actual, 5);
142216
}
143217

218+
[Theory]
219+
[MemberData(nameof(OverlayFunctionData))]
220+
public void OverlayFunction256(TestVector4 back, TestVector4 source, float amount, TestVector4 expected)
221+
{
222+
Vector256<float> back256 = Vector256.Create(back.X, back.Y, back.Z, back.W, back.X, back.Y, back.Z, back.W);
223+
Vector256<float> source256 = Vector256.Create(source.X, source.Y, source.Z, source.W, source.X, source.Y, source.Z, source.W);
224+
225+
Vector256<float> expected256 = Vector256.Create(expected.X, expected.Y, expected.Z, expected.W, expected.X, expected.Y, expected.Z, expected.W);
226+
Vector256<float> actual = PorterDuffFunctions.OverlaySrcOver(back256, source256, Vector256.Create(amount));
227+
Assert.Equal(expected256, actual, FloatComparer);
228+
}
229+
144230
public static TheoryData<TestVector4, TestVector4, float, TestVector4> HardLightFunctionData { get; } = new()
145231
{
146232
{ new TestVector4(1, 1, 1, 1), new TestVector4(1, 1, 1, 1), 1, new TestVector4(1, 1, 1, 1) },
@@ -155,4 +241,16 @@ public void HardLightFunction(TestVector4 back, TestVector4 source, float amount
155241
Vector4 actual = PorterDuffFunctions.HardLightSrcOver((Vector4)back, source, amount);
156242
VectorAssert.Equal(expected, actual, 5);
157243
}
244+
245+
[Theory]
246+
[MemberData(nameof(HardLightFunctionData))]
247+
public void HardLightFunction256(TestVector4 back, TestVector4 source, float amount, TestVector4 expected)
248+
{
249+
Vector256<float> back256 = Vector256.Create(back.X, back.Y, back.Z, back.W, back.X, back.Y, back.Z, back.W);
250+
Vector256<float> source256 = Vector256.Create(source.X, source.Y, source.Z, source.W, source.X, source.Y, source.Z, source.W);
251+
252+
Vector256<float> expected256 = Vector256.Create(expected.X, expected.Y, expected.Z, expected.W, expected.X, expected.Y, expected.Z, expected.W);
253+
Vector256<float> actual = PorterDuffFunctions.HardLightSrcOver(back256, source256, Vector256.Create(amount));
254+
Assert.Equal(expected256, actual, FloatComparer);
255+
}
158256
}

tests/ImageSharp.Tests/TestUtilities/ApproximateFloatComparer.cs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
// Copyright (c) Six Labors.
22
// Licensed under the Six Labors Split License.
33

4+
using System.Diagnostics.CodeAnalysis;
45
using System.Numerics;
6+
using System.Runtime.Intrinsics;
57
using SixLabors.ImageSharp.PixelFormats;
68

79
namespace SixLabors.ImageSharp.Tests;
@@ -14,7 +16,8 @@ namespace SixLabors.ImageSharp.Tests;
1416
IEqualityComparer<Vector2>,
1517
IEqualityComparer<IPixel>,
1618
IEqualityComparer<Vector4>,
17-
IEqualityComparer<ColorMatrix>
19+
IEqualityComparer<ColorMatrix>,
20+
IEqualityComparer<Vector256<float>>
1821
{
1922
private readonly float epsilon;
2023

@@ -72,4 +75,16 @@ public bool Equals(ColorMatrix x, ColorMatrix y)
7275

7376
/// <inheritdoc/>
7477
public int GetHashCode(ColorMatrix obj) => obj.GetHashCode();
78+
79+
public bool Equals(Vector256<float> x, Vector256<float> y)
80+
=> this.Equals(x.GetElement(0), y.GetElement(0))
81+
&& this.Equals(x.GetElement(1), y.GetElement(1))
82+
&& this.Equals(x.GetElement(2), y.GetElement(2))
83+
&& this.Equals(x.GetElement(3), y.GetElement(3))
84+
&& this.Equals(x.GetElement(4), y.GetElement(4))
85+
&& this.Equals(x.GetElement(5), y.GetElement(5))
86+
&& this.Equals(x.GetElement(6), y.GetElement(6))
87+
&& this.Equals(x.GetElement(7), y.GetElement(7));
88+
89+
public int GetHashCode([DisallowNull] Vector256<float> obj) => obj.GetHashCode();
7590
}

0 commit comments

Comments
 (0)