Browse Source

Use FeatureTestRunner for all instruction sets

pull/3137/head
Erik White 1 month ago
parent
commit
5472d6918a
  1. 6
      src/ImageSharp/Formats/Png/PngCgbiProcessor.cs
  2. 93
      tests/ImageSharp.Tests/Formats/Png/PngCgbiProcessorTests.cs

6
src/ImageSharp/Formats/Png/PngCgbiProcessor.cs

@ -95,7 +95,7 @@ internal static class PngCgbiProcessor
pixel = new Rgba32(r, g, b, a);
}
internal static int ApplyTransformVector512(Span<byte> scanline, int pixelCount)
private static int ApplyTransformVector512(Span<byte> scanline, int pixelCount)
{
ref byte scanlineRef = ref MemoryMarshal.GetReference(scanline);
int i = 0;
@ -167,7 +167,7 @@ internal static class PngCgbiProcessor
return i;
}
internal static int ApplyTransformVector256(Span<byte> scanline, int startPixel, int pixelCount)
private static int ApplyTransformVector256(Span<byte> scanline, int startPixel, int pixelCount)
{
ref byte scanlineRef = ref MemoryMarshal.GetReference(scanline);
int i = startPixel;
@ -239,7 +239,7 @@ internal static class PngCgbiProcessor
return i;
}
internal static int ApplyTransformVector128(Span<byte> scanline, int startPixel, int pixelCount)
private static int ApplyTransformVector128(Span<byte> scanline, int startPixel, int pixelCount)
{
ref byte scanlineRef = ref MemoryMarshal.GetReference(scanline);
int i = startPixel;

93
tests/ImageSharp.Tests/Formats/Png/PngCgbiProcessorTests.cs

@ -4,6 +4,7 @@
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Tests.TestUtilities;
namespace SixLabors.ImageSharp.Tests.Formats.Png;
@ -24,10 +25,14 @@ public class PngCgbiProcessorTests
[InlineData(32)]
[InlineData(33)]
[InlineData(64)]
public void ApplyTransform_RgbWithAlpha_MatchesScalar(int pixelCount)
public void ApplyTransform_RgbWithAlpha_MatchesScalar(int pixelCount) =>
FeatureTestRunner.RunWithHwIntrinsicsFeature(
serialized => AssertApplyTransformMatchesScalar(FeatureTestRunner.Deserialize<int>(serialized)),
pixelCount,
HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX512F | HwIntrinsics.DisableAVX | HwIntrinsics.DisableHWIntrinsic);
private static void AssertApplyTransformMatchesScalar(int pixelCount)
{
// Drives the full V512/V256/V128/scalar dispatch, so it covers each
// path that is hardware-accelerated on the host plus the scalar tail.
byte[] input = CreateBgraScanline(pixelCount);
byte[] processorOutput = (byte[])input.Clone();
byte[] scalarOutput = (byte[])input.Clone();
@ -38,88 +43,6 @@ public class PngCgbiProcessorTests
Assert.Equal(scalarOutput, processorOutput);
}
[Theory]
[InlineData(0)]
[InlineData(1)]
[InlineData(3)]
[InlineData(4)]
[InlineData(7)]
[InlineData(8)]
[InlineData(15)]
[InlineData(16)]
[InlineData(17)]
[InlineData(31)]
[InlineData(32)]
[InlineData(33)]
[InlineData(64)]
public void ApplyTransformVector512_MatchesScalar(int pixelCount) =>
// Vector512 uses Vector512_.ShuffleNative which falls back to the software
// Vector512.Shuffle when Avx512BW is unavailable, so the body runs regardless
// of whether Vector512 is hardware-accelerated on the host.
AssertVectorMatchesScalar(
pixelCount,
scanline => PngCgbiProcessor.ApplyTransformVector512(scanline, scanline.Length / 4),
blockSize: 16);
[Theory]
[InlineData(0)]
[InlineData(1)]
[InlineData(3)]
[InlineData(4)]
[InlineData(7)]
[InlineData(8)]
[InlineData(15)]
[InlineData(16)]
[InlineData(17)]
[InlineData(31)]
[InlineData(32)]
[InlineData(64)]
public void ApplyTransformVector256_MatchesScalar(int pixelCount) => AssertVectorMatchesScalar(
pixelCount,
scanline => PngCgbiProcessor.ApplyTransformVector256(scanline, 0, scanline.Length / 4),
blockSize: 8);
[Theory]
[InlineData(0)]
[InlineData(1)]
[InlineData(3)]
[InlineData(4)]
[InlineData(7)]
[InlineData(8)]
[InlineData(15)]
[InlineData(16)]
[InlineData(64)]
public void ApplyTransformVector128_MatchesScalar(int pixelCount) => AssertVectorMatchesScalar(
pixelCount,
scanline => PngCgbiProcessor.ApplyTransformVector128(scanline, 0, scanline.Length / 4),
blockSize: 4);
private static void AssertVectorMatchesScalar(int pixelCount, Func<byte[], int> applyVector, int blockSize)
{
byte[] input = CreateBgraScanline(pixelCount);
byte[] vectorOutput = (byte[])input.Clone();
byte[] scalarOutput = (byte[])input.Clone();
int processed = applyVector(vectorOutput);
int expectedProcessed = (pixelCount / blockSize) * blockSize;
Assert.Equal(expectedProcessed, processed);
// The vector path is responsible for whole blocks only; remaining pixels are
// handled by the scalar tail in ApplyTransform. Run the scalar reference
// over every pixel and compare the prefix the vector path actually wrote.
ApplyCgbiTransformScalarReference(scalarOutput);
Span<byte> vectorProcessed = vectorOutput.AsSpan(0, processed * 4);
Span<byte> scalarProcessed = scalarOutput.AsSpan(0, processed * 4);
Assert.True(vectorProcessed.SequenceEqual(scalarProcessed), $"Mismatch at pixelCount={pixelCount}");
// Pixels past the vector's processed prefix must be untouched.
Span<byte> vectorTail = vectorOutput.AsSpan(processed * 4);
Span<byte> inputTail = input.AsSpan(processed * 4);
Assert.True(vectorTail.SequenceEqual(inputTail));
}
/// <summary>
/// Builds synthetic input for tests. Produces inputs that exercise all three alpha cases.
/// </summary>

Loading…
Cancel
Save