diff --git a/.runsettings b/.runsettings
new file mode 100644
index 0000000000..ca48342bd6
--- /dev/null
+++ b/.runsettings
@@ -0,0 +1,7 @@
+
+
+
+
+ category!=failing
+
+
diff --git a/Directory.Build.props b/Directory.Build.props
index c4610d0ed3..bb97810a8f 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -15,6 +15,7 @@
$(MSBuildThisFileDirectory)artifacts/
$(SixLaborsProjectCategory)/$(MSBuildProjectName)
https://github.com/SixLabors/ImageSharp/
+ $(MSBuildThisFileDirectory)/.runsettings
diff --git a/Directory.Build.targets b/Directory.Build.targets
index 4e7ab9e6b7..2a7d25b977 100644
--- a/Directory.Build.targets
+++ b/Directory.Build.targets
@@ -18,22 +18,18 @@
-
+
-
+
-
-
+
diff --git a/ImageSharp.sln b/ImageSharp.sln
index 7458916add..abb9619955 100644
--- a/ImageSharp.sln
+++ b/ImageSharp.sln
@@ -9,6 +9,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
.gitattributes = .gitattributes
.gitignore = .gitignore
.gitmodules = .gitmodules
+ .runsettings = .runsettings
ci-build.ps1 = ci-build.ps1
ci-pack.ps1 = ci-pack.ps1
ci-test.ps1 = ci-test.ps1
diff --git a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs
index eb29c44050..454440f634 100644
--- a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs
+++ b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs
@@ -171,7 +171,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
var fileHeader = new BmpFileHeader(
type: BmpConstants.TypeMarkers.Bitmap,
- fileSize: BmpFileHeader.Size + infoHeaderSize + infoHeader.ImageSize,
+ fileSize: BmpFileHeader.Size + infoHeaderSize + colorPaletteSize + infoHeader.ImageSize,
reserved: 0,
offset: BmpFileHeader.Size + infoHeaderSize + colorPaletteSize);
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.cs
index 10cbee5e6f..6a336ad2b4 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.cs
@@ -10,86 +10,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
{
internal partial struct Block8x8F
{
- ///
- /// Fallback method to transpose a block into the destination block on non AVX supported CPUs.
- ///
- /// The destination block
- [MethodImpl(InliningOptions.ShortMethod)]
- public void TransposeIntoFallback(ref Block8x8F d)
- {
- d.V0L.X = V0L.X;
- d.V1L.X = V0L.Y;
- d.V2L.X = V0L.Z;
- d.V3L.X = V0L.W;
- d.V4L.X = V0R.X;
- d.V5L.X = V0R.Y;
- d.V6L.X = V0R.Z;
- d.V7L.X = V0R.W;
-
- d.V0L.Y = V1L.X;
- d.V1L.Y = V1L.Y;
- d.V2L.Y = V1L.Z;
- d.V3L.Y = V1L.W;
- d.V4L.Y = V1R.X;
- d.V5L.Y = V1R.Y;
- d.V6L.Y = V1R.Z;
- d.V7L.Y = V1R.W;
-
- d.V0L.Z = V2L.X;
- d.V1L.Z = V2L.Y;
- d.V2L.Z = V2L.Z;
- d.V3L.Z = V2L.W;
- d.V4L.Z = V2R.X;
- d.V5L.Z = V2R.Y;
- d.V6L.Z = V2R.Z;
- d.V7L.Z = V2R.W;
-
- d.V0L.W = V3L.X;
- d.V1L.W = V3L.Y;
- d.V2L.W = V3L.Z;
- d.V3L.W = V3L.W;
- d.V4L.W = V3R.X;
- d.V5L.W = V3R.Y;
- d.V6L.W = V3R.Z;
- d.V7L.W = V3R.W;
-
- d.V0R.X = V4L.X;
- d.V1R.X = V4L.Y;
- d.V2R.X = V4L.Z;
- d.V3R.X = V4L.W;
- d.V4R.X = V4R.X;
- d.V5R.X = V4R.Y;
- d.V6R.X = V4R.Z;
- d.V7R.X = V4R.W;
-
- d.V0R.Y = V5L.X;
- d.V1R.Y = V5L.Y;
- d.V2R.Y = V5L.Z;
- d.V3R.Y = V5L.W;
- d.V4R.Y = V5R.X;
- d.V5R.Y = V5R.Y;
- d.V6R.Y = V5R.Z;
- d.V7R.Y = V5R.W;
-
- d.V0R.Z = V6L.X;
- d.V1R.Z = V6L.Y;
- d.V2R.Z = V6L.Z;
- d.V3R.Z = V6L.W;
- d.V4R.Z = V6R.X;
- d.V5R.Z = V6R.Y;
- d.V6R.Z = V6R.Z;
- d.V7R.Z = V6R.W;
-
- d.V0R.W = V7L.X;
- d.V1R.W = V7L.Y;
- d.V2R.W = V7L.Z;
- d.V3R.W = V7L.W;
- d.V4R.W = V7R.X;
- d.V5R.W = V7R.Y;
- d.V6R.W = V7R.Z;
- d.V7R.W = V7R.W;
- }
-
///
/// Level shift by +maximum/2, clip to [0, maximum]
///
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.tt b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.tt
index f47d9106ee..26cd5c2ac4 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.tt
+++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.tt
@@ -23,38 +23,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
{
internal partial struct Block8x8F
{
- ///
- /// Fallback method to transpose a block into the destination block on non AVX supported CPUs.
- ///
- /// The destination block
- [MethodImpl(InliningOptions.ShortMethod)]
- public void TransposeIntoFallback(ref Block8x8F d)
- {
- <#
- PushIndent(" ");
-
- for (int i = 0; i < 8; i++)
- {
- char destCoord = coordz[i % 4];
- char destSide = (i / 4) % 2 == 0 ? 'L' : 'R';
-
- for (int j = 0; j < 8; j++)
- {
- if(i > 0 && j == 0){
- WriteLine("");
- }
-
- char srcCoord = coordz[j % 4];
- char srcSide = (j / 4) % 2 == 0 ? 'L' : 'R';
-
- var expression = $"d.V{j}{destSide}.{destCoord} = V{i}{srcSide}.{srcCoord};\r\n";
- Write(expression);
- }
- }
- PopIndent();
- #>
- }
-
///
/// Level shift by +maximum/2, clip to [0, maximum]
///
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs
index 547e116230..ccdba48857 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs
@@ -611,87 +611,146 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
#if SUPPORTS_RUNTIME_INTRINSICS
if (Avx.IsSupported)
{
- this.TransposeIntoAvx(ref d);
+ // https://stackoverflow.com/questions/25622745/transpose-an-8x8-float-using-avx-avx2/25627536#25627536
+ Vector256 r0 = Avx.InsertVector128(
+ Unsafe.As>(ref this.V0L).ToVector256(),
+ Unsafe.As>(ref this.V4L),
+ 1);
+
+ Vector256 r1 = Avx.InsertVector128(
+ Unsafe.As>(ref this.V1L).ToVector256(),
+ Unsafe.As>(ref this.V5L),
+ 1);
+
+ Vector256 r2 = Avx.InsertVector128(
+ Unsafe.As>(ref this.V2L).ToVector256(),
+ Unsafe.As>(ref this.V6L),
+ 1);
+
+ Vector256 r3 = Avx.InsertVector128(
+ Unsafe.As>(ref this.V3L).ToVector256(),
+ Unsafe.As>(ref this.V7L),
+ 1);
+
+ Vector256 r4 = Avx.InsertVector128(
+ Unsafe.As>(ref this.V0R).ToVector256(),
+ Unsafe.As>(ref this.V4R),
+ 1);
+
+ Vector256 r5 = Avx.InsertVector128(
+ Unsafe.As>(ref this.V1R).ToVector256(),
+ Unsafe.As>(ref this.V5R),
+ 1);
+
+ Vector256 r6 = Avx.InsertVector128(
+ Unsafe.As>(ref this.V2R).ToVector256(),
+ Unsafe.As>(ref this.V6R),
+ 1);
+
+ Vector256 r7 = Avx.InsertVector128(
+ Unsafe.As>(ref this.V3R).ToVector256(),
+ Unsafe.As>(ref this.V7R),
+ 1);
+
+ Vector256 t0 = Avx.UnpackLow(r0, r1);
+ Vector256 t2 = Avx.UnpackLow(r2, r3);
+ Vector256 v = Avx.Shuffle(t0, t2, 0x4E);
+ Unsafe.As>(ref d.V0L) = Avx.Blend(t0, v, 0xCC);
+ Unsafe.As>(ref d.V1L) = Avx.Blend(t2, v, 0x33);
+
+ Vector256 t4 = Avx.UnpackLow(r4, r5);
+ Vector256 t6 = Avx.UnpackLow(r6, r7);
+ v = Avx.Shuffle(t4, t6, 0x4E);
+ Unsafe.As>(ref d.V4L) = Avx.Blend(t4, v, 0xCC);
+ Unsafe.As>(ref d.V5L) = Avx.Blend(t6, v, 0x33);
+
+ Vector256 t1 = Avx.UnpackHigh(r0, r1);
+ Vector256 t3 = Avx.UnpackHigh(r2, r3);
+ v = Avx.Shuffle(t1, t3, 0x4E);
+ Unsafe.As>(ref d.V2L) = Avx.Blend(t1, v, 0xCC);
+ Unsafe.As>(ref d.V3L) = Avx.Blend(t3, v, 0x33);
+
+ Vector256 t5 = Avx.UnpackHigh(r4, r5);
+ Vector256 t7 = Avx.UnpackHigh(r6, r7);
+ v = Avx.Shuffle(t5, t7, 0x4E);
+ Unsafe.As>(ref d.V6L) = Avx.Blend(t5, v, 0xCC);
+ Unsafe.As>(ref d.V7L) = Avx.Blend(t7, v, 0x33);
}
else
#endif
{
- this.TransposeIntoFallback(ref d);
+ d.V0L.X = this.V0L.X;
+ d.V1L.X = this.V0L.Y;
+ d.V2L.X = this.V0L.Z;
+ d.V3L.X = this.V0L.W;
+ d.V4L.X = this.V0R.X;
+ d.V5L.X = this.V0R.Y;
+ d.V6L.X = this.V0R.Z;
+ d.V7L.X = this.V0R.W;
+
+ d.V0L.Y = this.V1L.X;
+ d.V1L.Y = this.V1L.Y;
+ d.V2L.Y = this.V1L.Z;
+ d.V3L.Y = this.V1L.W;
+ d.V4L.Y = this.V1R.X;
+ d.V5L.Y = this.V1R.Y;
+ d.V6L.Y = this.V1R.Z;
+ d.V7L.Y = this.V1R.W;
+
+ d.V0L.Z = this.V2L.X;
+ d.V1L.Z = this.V2L.Y;
+ d.V2L.Z = this.V2L.Z;
+ d.V3L.Z = this.V2L.W;
+ d.V4L.Z = this.V2R.X;
+ d.V5L.Z = this.V2R.Y;
+ d.V6L.Z = this.V2R.Z;
+ d.V7L.Z = this.V2R.W;
+
+ d.V0L.W = this.V3L.X;
+ d.V1L.W = this.V3L.Y;
+ d.V2L.W = this.V3L.Z;
+ d.V3L.W = this.V3L.W;
+ d.V4L.W = this.V3R.X;
+ d.V5L.W = this.V3R.Y;
+ d.V6L.W = this.V3R.Z;
+ d.V7L.W = this.V3R.W;
+
+ d.V0R.X = this.V4L.X;
+ d.V1R.X = this.V4L.Y;
+ d.V2R.X = this.V4L.Z;
+ d.V3R.X = this.V4L.W;
+ d.V4R.X = this.V4R.X;
+ d.V5R.X = this.V4R.Y;
+ d.V6R.X = this.V4R.Z;
+ d.V7R.X = this.V4R.W;
+
+ d.V0R.Y = this.V5L.X;
+ d.V1R.Y = this.V5L.Y;
+ d.V2R.Y = this.V5L.Z;
+ d.V3R.Y = this.V5L.W;
+ d.V4R.Y = this.V5R.X;
+ d.V5R.Y = this.V5R.Y;
+ d.V6R.Y = this.V5R.Z;
+ d.V7R.Y = this.V5R.W;
+
+ d.V0R.Z = this.V6L.X;
+ d.V1R.Z = this.V6L.Y;
+ d.V2R.Z = this.V6L.Z;
+ d.V3R.Z = this.V6L.W;
+ d.V4R.Z = this.V6R.X;
+ d.V5R.Z = this.V6R.Y;
+ d.V6R.Z = this.V6R.Z;
+ d.V7R.Z = this.V6R.W;
+
+ d.V0R.W = this.V7L.X;
+ d.V1R.W = this.V7L.Y;
+ d.V2R.W = this.V7L.Z;
+ d.V3R.W = this.V7L.W;
+ d.V4R.W = this.V7R.X;
+ d.V5R.W = this.V7R.Y;
+ d.V6R.W = this.V7R.Z;
+ d.V7R.W = this.V7R.W;
}
}
-
-#if SUPPORTS_RUNTIME_INTRINSICS
- ///
- /// AVX-only variant for executing .
- ///
- ///
- [MethodImpl(InliningOptions.ShortMethod)]
- public void TransposeIntoAvx(ref Block8x8F d)
- {
- Vector256 r0 = Avx.InsertVector128(
- Unsafe.As>(ref this.V0L).ToVector256(),
- Unsafe.As>(ref this.V4L),
- 1);
-
- Vector256 r1 = Avx.InsertVector128(
- Unsafe.As>(ref this.V1L).ToVector256(),
- Unsafe.As>(ref this.V5L),
- 1);
-
- Vector256 r2 = Avx.InsertVector128(
- Unsafe.As>(ref this.V2L).ToVector256(),
- Unsafe.As>(ref this.V6L),
- 1);
-
- Vector256 r3 = Avx.InsertVector128(
- Unsafe.As>(ref this.V3L).ToVector256(),
- Unsafe.As>(ref this.V7L),
- 1);
-
- Vector256 r4 = Avx.InsertVector128(
- Unsafe.As>(ref this.V0R).ToVector256(),
- Unsafe.As>(ref this.V4R),
- 1);
-
- Vector256 r5 = Avx.InsertVector128(
- Unsafe.As>(ref this.V1R).ToVector256(),
- Unsafe.As>(ref this.V5R),
- 1);
-
- Vector256 r6 = Avx.InsertVector128(
- Unsafe.As>(ref this.V2R).ToVector256(),
- Unsafe.As>(ref this.V6R),
- 1);
-
- Vector256 r7 = Avx.InsertVector128(
- Unsafe.As>(ref this.V3R).ToVector256(),
- Unsafe.As>(ref this.V7R),
- 1);
-
- Vector256 t0 = Avx.UnpackLow(r0, r1);
- Vector256 t2 = Avx.UnpackLow(r2, r3);
- Vector256 v = Avx.Shuffle(t0, t2, 0x4E);
- Unsafe.As>(ref d.V0L) = Avx.Blend(t0, v, 0xCC);
- Unsafe.As>(ref d.V1L) = Avx.Blend(t2, v, 0x33);
-
- Vector256 t4 = Avx.UnpackLow(r4, r5);
- Vector256 t6 = Avx.UnpackLow(r6, r7);
- v = Avx.Shuffle(t4, t6, 0x4E);
- Unsafe.As>(ref d.V4L) = Avx.Blend(t4, v, 0xCC);
- Unsafe.As>(ref d.V5L) = Avx.Blend(t6, v, 0x33);
-
- Vector256 t1 = Avx.UnpackHigh(r0, r1);
- Vector256 t3 = Avx.UnpackHigh(r2, r3);
- v = Avx.Shuffle(t1, t3, 0x4E);
- Unsafe.As>(ref d.V2L) = Avx.Blend(t1, v, 0xCC);
- Unsafe.As>(ref d.V3L) = Avx.Blend(t3, v, 0x33);
-
- Vector256 t5 = Avx.UnpackHigh(r4, r5);
- Vector256 t7 = Avx.UnpackHigh(r6, r7);
- v = Avx.Shuffle(t5, t7, 0x4E);
- Unsafe.As>(ref d.V6L) = Avx.Blend(t5, v, 0xCC);
- Unsafe.As>(ref d.V7L) = Avx.Blend(t7, v, 0x33);
- }
-#endif
}
}
diff --git a/src/ImageSharp/Processing/Processors/Normalization/GlobalHistogramEqualizationProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Normalization/GlobalHistogramEqualizationProcessor{TPixel}.cs
index 19514c4b6f..274376671b 100644
--- a/src/ImageSharp/Processing/Processors/Normalization/GlobalHistogramEqualizationProcessor{TPixel}.cs
+++ b/src/ImageSharp/Processing/Processors/Normalization/GlobalHistogramEqualizationProcessor{TPixel}.cs
@@ -106,15 +106,23 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization
}
///
+#if NETSTANDARD2_0
+ // https://github.com/SixLabors/ImageSharp/issues/1204
+ [MethodImpl(MethodImplOptions.NoOptimization)]
+#else
[MethodImpl(InliningOptions.ShortMethod)]
+#endif
public void Invoke(int y)
{
ref int histogramBase = ref MemoryMarshal.GetReference(this.histogramBuffer.GetSpan());
ref TPixel pixelBase = ref MemoryMarshal.GetReference(this.source.GetPixelRowSpan(y));
+ int levels = this.luminanceLevels;
for (int x = 0; x < this.bounds.Width; x++)
{
- int luminance = GetLuminance(Unsafe.Add(ref pixelBase, x), this.luminanceLevels);
+ // TODO: We should bulk convert here.
+ var vector = Unsafe.Add(ref pixelBase, x).ToVector4();
+ int luminance = ImageMaths.GetBT709Luminance(ref vector, levels);
Unsafe.Add(ref histogramBase, luminance)++;
}
}
@@ -147,18 +155,27 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization
}
///
+#if NETSTANDARD2_0
+ // https://github.com/SixLabors/ImageSharp/issues/1204
+ [MethodImpl(MethodImplOptions.NoOptimization)]
+#else
[MethodImpl(InliningOptions.ShortMethod)]
+#endif
public void Invoke(int y)
{
ref int cdfBase = ref MemoryMarshal.GetReference(this.cdfBuffer.GetSpan());
ref TPixel pixelBase = ref MemoryMarshal.GetReference(this.source.GetPixelRowSpan(y));
+ int levels = this.luminanceLevels;
+ float noOfPixelsMinusCdfMin = this.numberOfPixelsMinusCdfMin;
for (int x = 0; x < this.bounds.Width; x++)
{
+ // TODO: We should bulk convert here.
ref TPixel pixel = ref Unsafe.Add(ref pixelBase, x);
- int luminance = GetLuminance(pixel, this.luminanceLevels);
- float luminanceEqualized = Unsafe.Add(ref cdfBase, luminance) / this.numberOfPixelsMinusCdfMin;
- pixel.FromVector4(new Vector4(luminanceEqualized, luminanceEqualized, luminanceEqualized, pixel.ToVector4().W));
+ var vector = pixel.ToVector4();
+ int luminance = ImageMaths.GetBT709Luminance(ref vector, levels);
+ float luminanceEqualized = Unsafe.Add(ref cdfBase, luminance) / noOfPixelsMinusCdfMin;
+ pixel.FromVector4(new Vector4(luminanceEqualized, luminanceEqualized, luminanceEqualized, vector.W));
}
}
}
diff --git a/tests/Directory.Build.targets b/tests/Directory.Build.targets
index 335f3d106c..1f699c9dd1 100644
--- a/tests/Directory.Build.targets
+++ b/tests/Directory.Build.targets
@@ -26,18 +26,19 @@
-
+
-
-
-
-
+
+
+
+
+
-
+
-
+
diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_Transpose.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_Transpose.cs
index ae1b23df92..1d103cd1a0 100644
--- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_Transpose.cs
+++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_Transpose.cs
@@ -6,25 +6,17 @@ using SixLabors.ImageSharp.Formats.Jpeg.Components;
namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg.BlockOperations
{
+ [Config(typeof(Config.HwIntrinsics_SSE_AVX))]
public class Block8x8F_Transpose
{
private static readonly Block8x8F Source = Create8x8FloatData();
- [Benchmark(Baseline=true)]
- public void TransposeIntoVector4()
- {
- var dest = default(Block8x8F);
- Source.TransposeIntoFallback(ref dest);
- }
-
-#if SUPPORTS_RUNTIME_INTRINSICS
[Benchmark]
- public void TransposeIntoAvx()
+ public void TransposeInto()
{
var dest = default(Block8x8F);
- Source.TransposeIntoAvx(ref dest);
+ Source.TransposeInto(ref dest);
}
-#endif
private static Block8x8F Create8x8FloatData()
{
diff --git a/tests/ImageSharp.Benchmarks/Config.HwIntrinsics.cs b/tests/ImageSharp.Benchmarks/Config.HwIntrinsics.cs
new file mode 100644
index 0000000000..e860c5491f
--- /dev/null
+++ b/tests/ImageSharp.Benchmarks/Config.HwIntrinsics.cs
@@ -0,0 +1,81 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+#if SUPPORTS_RUNTIME_INTRINSICS
+using System.Runtime.Intrinsics.X86;
+#endif
+using BenchmarkDotNet.Environments;
+using BenchmarkDotNet.Jobs;
+
+namespace SixLabors.ImageSharp.Benchmarks
+{
+ public partial class Config
+ {
+ private const string On = "1";
+ private const string Off = "0";
+
+ // See https://github.com/SixLabors/ImageSharp/pull/1229#discussion_r440477861
+ // * EnableHWIntrinsic
+ // * EnableSSE
+ // * EnableSSE2
+ // * EnableAES
+ // * EnablePCLMULQDQ
+ // * EnableSSE3
+ // * EnableSSSE3
+ // * EnableSSE41
+ // * EnableSSE42
+ // * EnablePOPCNT
+ // * EnableAVX
+ // * EnableFMA
+ // * EnableAVX2
+ // * EnableBMI1
+ // * EnableBMI2
+ // * EnableLZCNT
+ //
+ // `FeatureSIMD` ends up impacting all SIMD support(including `System.Numerics`) but not things
+ // like `LZCNT`, `BMI1`, or `BMI2`
+ // `EnableSSE3_4` is a legacy switch that exists for compat and is basically the same as `EnableSSE3`
+ private const string EnableAES = "COMPlus_EnableAES";
+ private const string EnableAVX = "COMPlus_EnableAVX";
+ private const string EnableAVX2 = "COMPlus_EnableAVX2";
+ private const string EnableBMI1 = "COMPlus_EnableBMI1";
+ private const string EnableBMI2 = "COMPlus_EnableBMI2";
+ private const string EnableFMA = "COMPlus_EnableFMA";
+ private const string EnableHWIntrinsic = "COMPlus_EnableHWIntrinsic";
+ private const string EnableLZCNT = "COMPlus_EnableLZCNT";
+ private const string EnablePCLMULQDQ = "COMPlus_EnablePCLMULQDQ";
+ private const string EnablePOPCNT = "COMPlus_EnablePOPCNT";
+ private const string EnableSSE = "COMPlus_EnableSSE";
+ private const string EnableSSE2 = "COMPlus_EnableSSE2";
+ private const string EnableSSE3 = "COMPlus_EnableSSE3";
+ private const string EnableSSE3_4 = "COMPlus_EnableSSE3_4";
+ private const string EnableSSE41 = "COMPlus_EnableSSE41";
+ private const string EnableSSE42 = "COMPlus_EnableSSE42";
+ private const string EnableSSSE3 = "COMPlus_EnableSSSE3";
+ private const string FeatureSIMD = "COMPlus_FeatureSIMD";
+
+ public class HwIntrinsics_SSE_AVX : Config
+ {
+ public HwIntrinsics_SSE_AVX()
+ {
+#if SUPPORTS_RUNTIME_INTRINSICS
+ if (Avx.IsSupported)
+ {
+ this.AddJob(Job.Default.WithRuntime(CoreRuntime.Core31)
+ .WithId("AVX").AsBaseline());
+ }
+
+ if (Sse.IsSupported)
+ {
+ this.AddJob(Job.Default.WithRuntime(CoreRuntime.Core31)
+ .WithEnvironmentVariables(new EnvironmentVariable(EnableAVX, Off))
+ .WithId("SSE"));
+ }
+#endif
+ this.AddJob(Job.Default.WithRuntime(CoreRuntime.Core31)
+ .WithEnvironmentVariables(new EnvironmentVariable(EnableHWIntrinsic, Off))
+ .WithId("No HwIntrinsics"));
+ }
+ }
+ }
+}
diff --git a/tests/ImageSharp.Benchmarks/Config.cs b/tests/ImageSharp.Benchmarks/Config.cs
index f9240779b9..53271f522d 100644
--- a/tests/ImageSharp.Benchmarks/Config.cs
+++ b/tests/ImageSharp.Benchmarks/Config.cs
@@ -12,7 +12,7 @@ using BenchmarkDotNet.Jobs;
namespace SixLabors.ImageSharp.Benchmarks
{
- public class Config : ManualConfig
+ public partial class Config : ManualConfig
{
public Config()
{
diff --git a/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs
index 3f767620a6..f98fa3c7f3 100644
--- a/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs
@@ -39,22 +39,32 @@ namespace SixLabors.ImageSharp.Tests.Formats.Bmp
};
[Theory]
- [WithFileCollection(nameof(MiscBmpFiles), PixelTypes.Rgba32, false)]
- [WithFileCollection(nameof(MiscBmpFiles), PixelTypes.Rgba32, true)]
- public void BmpDecoder_CanDecode_MiscellaneousBitmaps(TestImageProvider provider, bool enforceDiscontiguousBuffers)
+ [WithFileCollection(nameof(MiscBmpFiles), PixelTypes.Rgba32)]
+ public void BmpDecoder_CanDecode_MiscellaneousBitmaps(TestImageProvider provider)
where TPixel : unmanaged, IPixel
+ {
+ using Image image = provider.GetImage(BmpDecoder);
+ image.DebugSave(provider);
+
+ if (TestEnvironment.IsWindows)
+ {
+ image.CompareToOriginal(provider);
+ }
+ }
+
+ [Theory]
+ [WithFileCollection(nameof(MiscBmpFiles), PixelTypes.Rgba32)]
+ public void BmpDecoder_CanDecode_MiscellaneousBitmaps_WithLimitedAllocatorBufferCapacity(
+ TestImageProvider provider)
{
static void RunTest(string providerDump, string nonContiguousBuffersStr)
{
- TestImageProvider provider = BasicSerializer.Deserialize>(providerDump);
+ TestImageProvider provider = BasicSerializer.Deserialize>(providerDump);
- if (!string.IsNullOrEmpty(nonContiguousBuffersStr))
- {
- provider.LimitAllocatorBufferCapacity().InPixelsSqrt(100);
- }
+ provider.LimitAllocatorBufferCapacity().InPixelsSqrt(100);
- using Image image = provider.GetImage(BmpDecoder);
- image.DebugSave(provider, testOutputDetails: nonContiguousBuffersStr);
+ using Image image = provider.GetImage(BmpDecoder);
+ image.DebugSave(provider, nonContiguousBuffersStr);
if (TestEnvironment.IsWindows)
{
@@ -66,7 +76,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Bmp
RemoteExecutor.Invoke(
RunTest,
providerDump,
- enforceDiscontiguousBuffers ? "Disco" : string.Empty)
+ "Disco")
.Dispose();
}
@@ -348,7 +358,9 @@ namespace SixLabors.ImageSharp.Tests.Formats.Bmp
using (Image image = provider.GetImage(BmpDecoder))
{
image.DebugSave(provider);
- image.CompareToOriginal(provider);
+
+ // Do not validate. Reference files will fail validation.
+ image.CompareToOriginal(provider, new MagickReferenceDecoder(false));
}
}
diff --git a/tests/ImageSharp.Tests/Formats/Bmp/BmpEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Bmp/BmpEncoderTests.cs
index b05486e356..83b67a01af 100644
--- a/tests/ImageSharp.Tests/Formats/Bmp/BmpEncoderTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Bmp/BmpEncoderTests.cs
@@ -10,7 +10,7 @@ using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
using SixLabors.ImageSharp.Processing.Processors.Quantization;
using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison;
-
+using SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs;
using Xunit;
using Xunit.Abstractions;
@@ -200,10 +200,18 @@ namespace SixLabors.ImageSharp.Tests.Formats.Bmp
Quantizer = new WuQuantizer()
};
string actualOutputFile = provider.Utility.SaveTestOutputFile(image, "bmp", encoder, appendPixelTypeToFileName: false);
+
+ // Use the default decoder to test our encoded image. This verifies the content.
+ // We do not verify the reference image though as some are invalid.
IImageDecoder referenceDecoder = TestEnvironment.GetReferenceDecoder(actualOutputFile);
using (var referenceImage = Image.Load(actualOutputFile, referenceDecoder))
{
- referenceImage.CompareToReferenceOutput(ImageComparer.TolerantPercentage(0.01f), provider, extension: "bmp", appendPixelTypeToFileName: false);
+ referenceImage.CompareToReferenceOutput(
+ ImageComparer.TolerantPercentage(0.01f),
+ provider,
+ extension: "bmp",
+ appendPixelTypeToFileName: false,
+ decoder: new MagickReferenceDecoder(false));
}
}
}
@@ -226,10 +234,18 @@ namespace SixLabors.ImageSharp.Tests.Formats.Bmp
Quantizer = new OctreeQuantizer()
};
string actualOutputFile = provider.Utility.SaveTestOutputFile(image, "bmp", encoder, appendPixelTypeToFileName: false);
+
+ // Use the default decoder to test our encoded image. This verifies the content.
+ // We do not verify the reference image though as some are invalid.
IImageDecoder referenceDecoder = TestEnvironment.GetReferenceDecoder(actualOutputFile);
using (var referenceImage = Image.Load(actualOutputFile, referenceDecoder))
{
- referenceImage.CompareToReferenceOutput(ImageComparer.TolerantPercentage(0.01f), provider, extension: "bmp", appendPixelTypeToFileName: false);
+ referenceImage.CompareToReferenceOutput(
+ ImageComparer.TolerantPercentage(0.01f),
+ provider,
+ extension: "bmp",
+ appendPixelTypeToFileName: false,
+ decoder: new MagickReferenceDecoder(false));
}
}
}
diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs
index 63aae5c559..eb2643b8cd 100644
--- a/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs
@@ -198,17 +198,18 @@ namespace SixLabors.ImageSharp.Tests.Formats.Gif
[Theory]
[WithFile(TestImages.Gif.Giphy, PixelTypes.Rgba32)]
[WithFile(TestImages.Gif.Kumin, PixelTypes.Rgba32)]
- public void GifDecoder_CanDecode_WithLimitedAllocatorBufferCapacity(TestImageProvider provider)
- where TPixel : unmanaged, IPixel
+ public void GifDecoder_CanDecode_WithLimitedAllocatorBufferCapacity(
+ TestImageProvider provider)
{
static void RunTest(string providerDump, string nonContiguousBuffersStr)
{
- TestImageProvider provider = BasicSerializer.Deserialize>(providerDump);
+ TestImageProvider provider
+ = BasicSerializer.Deserialize>(providerDump);
provider.LimitAllocatorBufferCapacity().InPixelsSqrt(100);
- using Image image = provider.GetImage(GifDecoder);
- image.DebugSave(provider);
+ using Image image = provider.GetImage(GifDecoder);
+ image.DebugSave(provider, nonContiguousBuffersStr);
image.CompareToOriginal(provider);
}
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.cs
index 73a68063c0..5482380885 100644
--- a/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.cs
@@ -5,10 +5,9 @@
// #define BENCHMARKING
using System;
using System.Diagnostics;
-
using SixLabors.ImageSharp.Formats.Jpeg.Components;
using SixLabors.ImageSharp.Tests.Formats.Jpg.Utils;
-
+using SixLabors.ImageSharp.Tests.TestUtilities;
using Xunit;
using Xunit.Abstractions;
@@ -163,42 +162,29 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
}
[Fact]
- public void TransposeIntoFallback()
+ public void TransposeInto()
{
- float[] expected = Create8x8FloatData();
- ReferenceImplementations.Transpose8x8(expected);
-
- var source = default(Block8x8F);
- source.LoadFrom(Create8x8FloatData());
-
- var dest = default(Block8x8F);
- source.TransposeIntoFallback(ref dest);
-
- float[] actual = new float[64];
- dest.ScaledCopyTo(actual);
-
- Assert.Equal(expected, actual);
- }
+ static void RunTest()
+ {
+ float[] expected = Create8x8FloatData();
+ ReferenceImplementations.Transpose8x8(expected);
-#if SUPPORTS_RUNTIME_INTRINSICS
- [Fact]
- public void TransposeIntoAvx()
- {
- float[] expected = Create8x8FloatData();
- ReferenceImplementations.Transpose8x8(expected);
+ var source = default(Block8x8F);
+ source.LoadFrom(Create8x8FloatData());
- var source = default(Block8x8F);
- source.LoadFrom(Create8x8FloatData());
+ var dest = default(Block8x8F);
+ source.TransposeInto(ref dest);
- var dest = default(Block8x8F);
- source.TransposeIntoAvx(ref dest);
+ float[] actual = new float[64];
+ dest.ScaledCopyTo(actual);
- float[] actual = new float[64];
- dest.ScaledCopyTo(actual);
+ Assert.Equal(expected, actual);
+ }
- Assert.Equal(expected, actual);
+ FeatureTestRunner.RunWithHwIntrinsicsFeature(
+ RunTest,
+ HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX);
}
-#endif
private class BufferHolder
{
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Progressive.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Progressive.cs
index e29d8f158b..98421ca5d4 100644
--- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Progressive.cs
+++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Progressive.cs
@@ -14,22 +14,32 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
public const string DecodeProgressiveJpegOutputName = "DecodeProgressiveJpeg";
[Theory]
- [WithFileCollection(nameof(ProgressiveTestJpegs), PixelTypes.Rgba32, false)]
- [WithFile(TestImages.Jpeg.Progressive.Progress, PixelTypes.Rgba32, true)]
- public void DecodeProgressiveJpeg(TestImageProvider provider, bool enforceDiscontiguousBuffers)
+ [WithFileCollection(nameof(ProgressiveTestJpegs), PixelTypes.Rgba32)]
+ public void DecodeProgressiveJpeg(TestImageProvider provider)
where TPixel : unmanaged, IPixel
+ {
+ using Image image = provider.GetImage(JpegDecoder);
+ image.DebugSave(provider);
+
+ provider.Utility.TestName = DecodeProgressiveJpegOutputName;
+ image.CompareToReferenceOutput(
+ GetImageComparer(provider),
+ provider,
+ appendPixelTypeToFileName: false);
+ }
+
+ [Theory]
+ [WithFile(TestImages.Jpeg.Progressive.Progress, PixelTypes.Rgba32)]
+ public void DecodeProgressiveJpeg_WithLimitedAllocatorBufferCapacity(TestImageProvider provider)
{
static void RunTest(string providerDump, string nonContiguousBuffersStr)
{
- TestImageProvider provider =
- BasicSerializer.Deserialize>(providerDump);
+ TestImageProvider provider =
+ BasicSerializer.Deserialize>(providerDump);
- if (!string.IsNullOrEmpty(nonContiguousBuffersStr))
- {
- provider.LimitAllocatorBufferCapacity().InBytesSqrt(200);
- }
+ provider.LimitAllocatorBufferCapacity().InBytesSqrt(200);
- using Image image = provider.GetImage(JpegDecoder);
+ using Image image = provider.GetImage(JpegDecoder);
image.DebugSave(provider, nonContiguousBuffersStr);
provider.Utility.TestName = DecodeProgressiveJpegOutputName;
@@ -44,8 +54,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
RemoteExecutor.Invoke(
RunTest,
providerDump,
- enforceDiscontiguousBuffers ? "Disco" : string.Empty)
- .Dispose();
+ "Disco")
+ .Dispose();
}
}
}
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs
index 78218aec90..0884215491 100644
--- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs
@@ -129,10 +129,10 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
[Theory]
[InlineData(TestImages.Jpeg.Baseline.Jpeg420Small, 0)]
[InlineData(TestImages.Jpeg.Issues.ExifGetString750Transform, 1)]
- [InlineData(TestImages.Jpeg.Issues.ExifGetString750Transform, 10)]
+ [InlineData(TestImages.Jpeg.Issues.ExifGetString750Transform, 15)]
[InlineData(TestImages.Jpeg.Issues.ExifGetString750Transform, 30)]
[InlineData(TestImages.Jpeg.Issues.BadRstProgressive518, 1)]
- [InlineData(TestImages.Jpeg.Issues.BadRstProgressive518, 10)]
+ [InlineData(TestImages.Jpeg.Issues.BadRstProgressive518, 15)]
[InlineData(TestImages.Jpeg.Issues.BadRstProgressive518, 30)]
public async Task Decode_IsCancellable(string fileName, int cancellationDelayMs)
{
diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs
index 5b6adfe1af..2164975df0 100644
--- a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs
@@ -404,16 +404,15 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png
[Theory]
[WithFile(TestImages.Png.Splash, PixelTypes.Rgba32)]
[WithFile(TestImages.Png.Bike, PixelTypes.Rgba32)]
- public void PngDecoder_CanDecode_WithLimitedAllocatorBufferCapacity(TestImageProvider provider)
- where TPixel : unmanaged, IPixel
+ public void PngDecoder_CanDecode_WithLimitedAllocatorBufferCapacity(TestImageProvider provider)
{
static void RunTest(string providerDump, string nonContiguousBuffersStr)
{
- TestImageProvider provider = BasicSerializer.Deserialize>(providerDump);
+ TestImageProvider provider = BasicSerializer.Deserialize>(providerDump);
provider.LimitAllocatorBufferCapacity().InPixelsSqrt(100);
- using Image image = provider.GetImage(PngDecoder);
+ using Image image = provider.GetImage(PngDecoder);
image.DebugSave(provider, testOutputDetails: nonContiguousBuffersStr);
image.CompareToOriginal(provider);
}
diff --git a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs
index b9f5f16fa5..9ba956d722 100644
--- a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs
@@ -2,13 +2,8 @@
// Licensed under the Apache License, Version 2.0.
// ReSharper disable InconsistentNaming
-using System.Diagnostics;
using System.IO;
using System.Linq;
-#if SUPPORTS_RUNTIME_INTRINSICS
-using System.Runtime.Intrinsics.X86;
-#endif
-using Microsoft.DotNet.RemoteExecutor;
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.Metadata;
@@ -16,7 +11,6 @@ using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Processors.Quantization;
using SixLabors.ImageSharp.Tests.TestUtilities;
using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison;
-
using Xunit;
namespace SixLabors.ImageSharp.Tests.Formats.Png
@@ -536,16 +530,12 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png
[Theory]
[WithTestPatternImages(100, 100, PixelTypes.Rgba32)]
- public void EncodeWorksWithoutSsse3Intrinsics(TestImageProvider provider)
- where TPixel : unmanaged, IPixel
+ public void EncodeWorksWithoutSsse3Intrinsics(TestImageProvider provider)
{
- static void RunTest(string providerDump)
+ static void RunTest(string serialized)
{
- TestImageProvider provider =
- BasicSerializer.Deserialize>(providerDump);
-#if SUPPORTS_RUNTIME_INTRINSICS
- Assert.False(Ssse3.IsSupported);
-#endif
+ TestImageProvider provider =
+ FeatureTestRunner.Deserialize>(serialized);
foreach (PngInterlaceMode interlaceMode in InterlaceMode)
{
@@ -560,19 +550,10 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png
}
}
- string providerDump = BasicSerializer.Serialize(provider);
-
- var processStartInfo = new ProcessStartInfo();
- processStartInfo.Environment[TestEnvironment.Features.EnableSSE3] = TestEnvironment.Features.Off;
-
- RemoteExecutor.Invoke(
+ FeatureTestRunner.RunWithHwIntrinsicsFeature(
RunTest,
- providerDump,
- new RemoteInvokeOptions
- {
- StartInfo = processStartInfo
- })
- .Dispose();
+ HwIntrinsics.DisableSSSE3,
+ provider);
}
private static void TestPngEncoderCore(
diff --git a/tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs
index 5fb15541ec..edb43aa126 100644
--- a/tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs
@@ -747,16 +747,15 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga
[Theory]
[WithFile(Bit24BottomLeft, PixelTypes.Rgba32)]
[WithFile(Bit32BottomLeft, PixelTypes.Rgba32)]
- public void TgaDecoder_CanDecode_WithLimitedAllocatorBufferCapacity(TestImageProvider provider)
- where TPixel : unmanaged, IPixel
+ public void TgaDecoder_CanDecode_WithLimitedAllocatorBufferCapacity(TestImageProvider provider)
{
static void RunTest(string providerDump, string nonContiguousBuffersStr)
{
- TestImageProvider provider = BasicSerializer.Deserialize>(providerDump);
+ TestImageProvider provider = BasicSerializer.Deserialize>(providerDump);
provider.LimitAllocatorBufferCapacity().InPixelsSqrt(100);
- using Image image = provider.GetImage(TgaDecoder);
+ using Image image = provider.GetImage(TgaDecoder);
image.DebugSave(provider, testOutputDetails: nonContiguousBuffersStr);
if (TestEnvironment.IsWindows)
diff --git a/tests/ImageSharp.Tests/Formats/Tga/TgaTestUtils.cs b/tests/ImageSharp.Tests/Formats/Tga/TgaTestUtils.cs
index 0f76d99317..58ed31e610 100644
--- a/tests/ImageSharp.Tests/Formats/Tga/TgaTestUtils.cs
+++ b/tests/ImageSharp.Tests/Formats/Tga/TgaTestUtils.cs
@@ -18,7 +18,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga
Image image,
bool useExactComparer = true,
float compareTolerance = 0.01f)
- where TPixel : unmanaged, IPixel
+ where TPixel : unmanaged, ImageSharp.PixelFormats.IPixel
{
string path = TestImageProvider.GetFilePathOrNull(provider);
if (path == null)
@@ -39,7 +39,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga
}
public static Image DecodeWithMagick(Configuration configuration, FileInfo fileInfo)
- where TPixel : unmanaged, IPixel
+ where TPixel : unmanaged, ImageSharp.PixelFormats.IPixel
{
using (var magickImage = new MagickImage(fileInfo))
{
@@ -48,7 +48,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga
Assert.True(result.TryGetSinglePixelSpan(out Span resultPixels));
- using (IPixelCollection pixels = magickImage.GetPixelsUnsafe())
+ using (IUnsafePixelCollection pixels = magickImage.GetPixelsUnsafe())
{
byte[] data = pixels.ToByteArray(PixelMapping.RGBA);
diff --git a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj
index ba849ab251..07ade97d5d 100644
--- a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj
+++ b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj
@@ -20,6 +20,7 @@
+
diff --git a/tests/ImageSharp.Tests/Processing/Processors/Convolution/BokehBlurTest.cs b/tests/ImageSharp.Tests/Processing/Processors/Convolution/BokehBlurTest.cs
index 50b8782e47..6c48cf843d 100644
--- a/tests/ImageSharp.Tests/Processing/Processors/Convolution/BokehBlurTest.cs
+++ b/tests/ImageSharp.Tests/Processing/Processors/Convolution/BokehBlurTest.cs
@@ -138,21 +138,10 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Convolution
public void BokehBlurFilterProcessor(TestImageProvider provider, BokehBlurInfo value)
where TPixel : unmanaged, IPixel
{
- static void RunTest(string providerDump, string infoDump)
- {
- TestImageProvider provider =
- BasicSerializer.Deserialize>(providerDump);
- BokehBlurInfo value = BasicSerializer.Deserialize(infoDump);
-
- provider.RunValidatingProcessorTest(
- x => x.BokehBlur(value.Radius, value.Components, value.Gamma),
- testOutputDetails: value.ToString(),
- appendPixelTypeToFileName: false);
- }
-
- RemoteExecutor
- .Invoke(RunTest, BasicSerializer.Serialize(provider), BasicSerializer.Serialize(value))
- .Dispose();
+ provider.RunValidatingProcessorTest(
+ x => x.BokehBlur(value.Radius, value.Components, value.Gamma),
+ testOutputDetails: value.ToString(),
+ appendPixelTypeToFileName: false);
}
[Theory]
@@ -164,18 +153,9 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Convolution
public void BokehBlurFilterProcessor_WorksWithAllPixelTypes(TestImageProvider provider)
where TPixel : unmanaged, IPixel
{
- static void RunTest(string providerDump)
- {
- TestImageProvider provider =
- BasicSerializer.Deserialize>(providerDump);
- provider.RunValidatingProcessorTest(
+ provider.RunValidatingProcessorTest(
x => x.BokehBlur(8, 2, 3),
appendSourceFileOrDescription: false);
- }
-
- RemoteExecutor
- .Invoke(RunTest, BasicSerializer.Serialize(provider))
- .Dispose();
}
[Theory]
@@ -183,26 +163,15 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Convolution
public void BokehBlurFilterProcessor_Bounded(TestImageProvider provider, BokehBlurInfo value)
where TPixel : unmanaged, IPixel
{
- static void RunTest(string providerDump, string infoDump)
- {
- TestImageProvider provider =
- BasicSerializer.Deserialize>(providerDump);
- BokehBlurInfo value = BasicSerializer.Deserialize(infoDump);
-
- provider.RunValidatingProcessorTest(
- x =>
- {
- Size size = x.GetCurrentSize();
- var bounds = new Rectangle(10, 10, size.Width / 2, size.Height / 2);
- x.BokehBlur(value.Radius, value.Components, value.Gamma, bounds);
- },
- testOutputDetails: value.ToString(),
- appendPixelTypeToFileName: false);
- }
-
- RemoteExecutor
- .Invoke(RunTest, BasicSerializer.Serialize(provider), BasicSerializer.Serialize(value))
- .Dispose();
+ provider.RunValidatingProcessorTest(
+ x =>
+ {
+ Size size = x.GetCurrentSize();
+ var bounds = new Rectangle(10, 10, size.Width / 2, size.Height / 2);
+ x.BokehBlur(value.Radius, value.Components, value.Gamma, bounds);
+ },
+ testOutputDetails: value.ToString(),
+ appendPixelTypeToFileName: false);
}
[Theory]
diff --git a/tests/ImageSharp.Tests/TestUtilities/FeatureTesting/FeatureTestRunner.cs b/tests/ImageSharp.Tests/TestUtilities/FeatureTesting/FeatureTestRunner.cs
new file mode 100644
index 0000000000..eb1714baad
--- /dev/null
+++ b/tests/ImageSharp.Tests/TestUtilities/FeatureTesting/FeatureTestRunner.cs
@@ -0,0 +1,266 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using Microsoft.DotNet.RemoteExecutor;
+using Xunit.Abstractions;
+
+namespace SixLabors.ImageSharp.Tests.TestUtilities
+{
+ ///
+ /// Allows the testing against specific feature sets.
+ ///
+ public static class FeatureTestRunner
+ {
+ private static readonly char[] SplitChars = new[] { ',', ' ' };
+
+ ///
+ /// Allows the deserialization of parameters passed to the feature test.
+ ///
+ ///
+ /// This is required because does not allow
+ /// marshalling of fields so we cannot pass a wrapped
+ /// allowing automatic deserialization.
+ ///
+ ///
+ ///
+ /// The type to deserialize to.
+ /// The string value to deserialize.
+ /// The value.
+ public static T Deserialize(string value)
+ where T : IXunitSerializable
+ => BasicSerializer.Deserialize(value);
+
+ ///
+ /// Runs the given test within an environment
+ /// where the given features.
+ ///
+ /// The test action to run.
+ /// The intrinsics features.
+ public static void RunWithHwIntrinsicsFeature(
+ Action action,
+ HwIntrinsics intrinsics)
+ {
+ if (!RemoteExecutor.IsSupported)
+ {
+ return;
+ }
+
+ foreach (KeyValuePair intrinsic in intrinsics.ToFeatureKeyValueCollection())
+ {
+ var processStartInfo = new ProcessStartInfo();
+ if (intrinsic.Key != HwIntrinsics.AllowAll)
+ {
+ processStartInfo.Environment[$"COMPlus_{intrinsic.Value}"] = "0";
+
+ RemoteExecutor.Invoke(
+ action,
+ new RemoteInvokeOptions
+ {
+ StartInfo = processStartInfo
+ })
+ .Dispose();
+ }
+ else
+ {
+ // Since we are running using the default architecture there is no
+ // point creating the overhead of running the action in a separate process.
+ action();
+ }
+ }
+ }
+
+ ///
+ /// Runs the given test within an environment
+ /// where the given features.
+ ///
+ ///
+ /// The test action to run.
+ /// The parameter passed will be a string representing the currently testing .
+ /// The intrinsics features.
+ public static void RunWithHwIntrinsicsFeature(
+ Action action,
+ HwIntrinsics intrinsics)
+ {
+ if (!RemoteExecutor.IsSupported)
+ {
+ return;
+ }
+
+ foreach (KeyValuePair intrinsic in intrinsics.ToFeatureKeyValueCollection())
+ {
+ var processStartInfo = new ProcessStartInfo();
+ if (intrinsic.Key != HwIntrinsics.AllowAll)
+ {
+ processStartInfo.Environment[$"COMPlus_{intrinsic.Value}"] = "0";
+
+ RemoteExecutor.Invoke(
+ action,
+ intrinsic.Key.ToString(),
+ new RemoteInvokeOptions
+ {
+ StartInfo = processStartInfo
+ })
+ .Dispose();
+ }
+ else
+ {
+ // Since we are running using the default architecture there is no
+ // point creating the overhead of running the action in a separate process.
+ action(intrinsic.Key.ToString());
+ }
+ }
+ }
+
+ ///
+ /// Runs the given test within an environment
+ /// where the given features.
+ ///
+ /// The test action to run.
+ /// The intrinsics features.
+ /// The value to pass as a parameter to the test action.
+ public static void RunWithHwIntrinsicsFeature(
+ Action action,
+ HwIntrinsics intrinsics,
+ T serializable)
+ where T : IXunitSerializable
+ {
+ if (!RemoteExecutor.IsSupported)
+ {
+ return;
+ }
+
+ foreach (KeyValuePair intrinsic in intrinsics.ToFeatureKeyValueCollection())
+ {
+ var processStartInfo = new ProcessStartInfo();
+ if (intrinsic.Key != HwIntrinsics.AllowAll)
+ {
+ processStartInfo.Environment[$"COMPlus_{intrinsic.Value}"] = "0";
+
+ RemoteExecutor.Invoke(
+ action,
+ BasicSerializer.Serialize(serializable),
+ new RemoteInvokeOptions
+ {
+ StartInfo = processStartInfo
+ })
+ .Dispose();
+ }
+ else
+ {
+ // Since we are running using the default architecture there is no
+ // point creating the overhead of running the action in a separate process.
+ action(BasicSerializer.Serialize(serializable));
+ }
+ }
+ }
+
+ ///
+ /// Runs the given test within an environment
+ /// where the given features.
+ ///
+ /// The test action to run.
+ /// The intrinsics features.
+ /// The value to pass as a parameter to the test action.
+ public static void RunWithHwIntrinsicsFeature(
+ Action action,
+ HwIntrinsics intrinsics,
+ T serializable)
+ where T : IXunitSerializable
+ {
+ if (!RemoteExecutor.IsSupported)
+ {
+ return;
+ }
+
+ foreach (KeyValuePair intrinsic in intrinsics.ToFeatureKeyValueCollection())
+ {
+ var processStartInfo = new ProcessStartInfo();
+ if (intrinsic.Key != HwIntrinsics.AllowAll)
+ {
+ processStartInfo.Environment[$"COMPlus_{intrinsic.Value}"] = "0";
+
+ RemoteExecutor.Invoke(
+ action,
+ BasicSerializer.Serialize(serializable),
+ intrinsic.Key.ToString(),
+ new RemoteInvokeOptions
+ {
+ StartInfo = processStartInfo
+ })
+ .Dispose();
+ }
+ else
+ {
+ // Since we are running using the default architecture there is no
+ // point creating the overhead of running the action in a separate process.
+ action(BasicSerializer.Serialize(serializable), intrinsic.Key.ToString());
+ }
+ }
+ }
+
+ internal static Dictionary ToFeatureKeyValueCollection(this HwIntrinsics intrinsics)
+ {
+ // Loop through and translate the given values into COMPlus equivaluents
+ var features = new Dictionary();
+ foreach (string intrinsic in intrinsics.ToString("G").Split(SplitChars, StringSplitOptions.RemoveEmptyEntries))
+ {
+ var key = (HwIntrinsics)Enum.Parse(typeof(HwIntrinsics), intrinsic);
+ switch (intrinsic)
+ {
+ case nameof(HwIntrinsics.DisableSIMD):
+ features.Add(key, "FeatureSIMD");
+ break;
+
+ case nameof(HwIntrinsics.AllowAll):
+
+ // Not a COMPlus value. We filter in calling method.
+ features.Add(key, nameof(HwIntrinsics.AllowAll));
+ break;
+
+ default:
+ features.Add(key, intrinsic.Replace("Disable", "Enable"));
+ break;
+ }
+ }
+
+ return features;
+ }
+ }
+
+ ///
+ /// See
+ ///
+ /// ends up impacting all SIMD support(including System.Numerics)
+ /// but not things like , , and .
+ ///
+ ///
+ [Flags]
+#pragma warning disable RCS1135 // Declare enum member with zero value (when enum has FlagsAttribute).
+ public enum HwIntrinsics
+#pragma warning restore RCS1135 // Declare enum member with zero value (when enum has FlagsAttribute).
+ {
+ // Use flags so we can pass multiple values without using params.
+ // Don't base on 0 or use inverse for All as that doesn't translate to string values.
+ DisableSIMD = 1 << 0,
+ DisableHWIntrinsic = 1 << 1,
+ DisableSSE = 1 << 2,
+ DisableSSE2 = 1 << 3,
+ DisableAES = 1 << 4,
+ DisablePCLMULQDQ = 1 << 5,
+ DisableSSE3 = 1 << 6,
+ DisableSSSE3 = 1 << 7,
+ DisableSSE41 = 1 << 8,
+ DisableSSE42 = 1 << 9,
+ DisablePOPCNT = 1 << 10,
+ DisableAVX = 1 << 11,
+ DisableFMA = 1 << 12,
+ DisableAVX2 = 1 << 13,
+ DisableBMI1 = 1 << 14,
+ DisableBMI2 = 1 << 15,
+ DisableLZCNT = 1 << 16,
+ AllowAll = 1 << 17
+ }
+}
diff --git a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs
index de8278a33e..d20e7d2a7e 100644
--- a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs
+++ b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs
@@ -7,6 +7,7 @@ using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using ImageMagick;
+using ImageMagick.Formats.Bmp;
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@@ -15,10 +16,22 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs
{
public class MagickReferenceDecoder : IImageDecoder
{
+ private readonly bool validate;
+
+ public MagickReferenceDecoder()
+ : this(true)
+ {
+ }
+
+ public MagickReferenceDecoder(bool validate)
+ {
+ this.validate = validate;
+ }
+
public static MagickReferenceDecoder Instance { get; } = new MagickReferenceDecoder();
private static void FromRgba32Bytes(Configuration configuration, Span rgbaBytes, IMemoryGroup destinationGroup)
- where TPixel : unmanaged, IPixel
+ where TPixel : unmanaged, ImageSharp.PixelFormats.IPixel
{
foreach (Memory m in destinationGroup)
{
@@ -33,7 +46,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs
}
private static void FromRgba64Bytes(Configuration configuration, Span rgbaBytes, IMemoryGroup destinationGroup)
- where TPixel : unmanaged, IPixel
+ where TPixel : unmanaged, ImageSharp.PixelFormats.IPixel
{
foreach (Memory m in destinationGroup)
{
@@ -48,17 +61,25 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs
}
public Task> DecodeAsync(Configuration configuration, Stream stream, CancellationToken cancellationToken)
- where TPixel : unmanaged, IPixel
+ where TPixel : unmanaged, ImageSharp.PixelFormats.IPixel
=> Task.FromResult(this.Decode(configuration, stream));
public Image Decode(Configuration configuration, Stream stream)
- where TPixel : unmanaged, IPixel
+ where TPixel : unmanaged, ImageSharp.PixelFormats.IPixel
{
- using var magickImage = new MagickImage(stream);
+ var bmpReadDefines = new BmpReadDefines
+ {
+ IgnoreFileSize = !this.validate
+ };
+
+ var settings = new MagickReadSettings();
+ settings.SetDefines(bmpReadDefines);
+
+ using var magickImage = new MagickImage(stream, settings);
var result = new Image(configuration, magickImage.Width, magickImage.Height);
MemoryGroup resultPixels = result.GetRootFramePixelBuffer().FastMemoryGroup;
- using (IPixelCollection pixels = magickImage.GetPixelsUnsafe())
+ using (IUnsafePixelCollection pixels = magickImage.GetPixelsUnsafe())
{
if (magickImage.Depth == 8)
{
diff --git a/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Features.cs b/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Features.cs
deleted file mode 100644
index 3568c1e5dc..0000000000
--- a/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Features.cs
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright (c) Six Labors.
-// Licensed under the Apache License, Version 2.0.
-
-namespace SixLabors.ImageSharp.Tests
-{
- public static partial class TestEnvironment
- {
- internal static class Features
- {
- public const string On = "1";
- public const string Off = "0";
-
- // See https://github.com/SixLabors/ImageSharp/pull/1229#discussion_r440477861
- // * EnableHWIntrinsic
- // * EnableSSE
- // * EnableSSE2
- // * EnableAES
- // * EnablePCLMULQDQ
- // * EnableSSE3
- // * EnableSSSE3
- // * EnableSSE41
- // * EnableSSE42
- // * EnablePOPCNT
- // * EnableAVX
- // * EnableFMA
- // * EnableAVX2
- // * EnableBMI1
- // * EnableBMI2
- // * EnableLZCNT
- //
- // `FeatureSIMD` ends up impacting all SIMD support(including `System.Numerics`) but not things
- // like `LZCNT`, `BMI1`, or `BMI2`
- // `EnableSSE3_4` is a legacy switch that exists for compat and is basically the same as `EnableSSE3`
- public const string EnableAES = "COMPlus_EnableAES";
- public const string EnableAVX = "COMPlus_EnableAVX";
- public const string EnableAVX2 = "COMPlus_EnableAVX2";
- public const string EnableBMI1 = "COMPlus_EnableBMI1";
- public const string EnableBMI2 = "COMPlus_EnableBMI2";
- public const string EnableFMA = "COMPlus_EnableFMA";
- public const string EnableHWIntrinsic = "COMPlus_EnableHWIntrinsic";
- public const string EnableLZCNT = "COMPlus_EnableLZCNT";
- public const string EnablePCLMULQDQ = "COMPlus_EnablePCLMULQDQ";
- public const string EnablePOPCNT = "COMPlus_EnablePOPCNT";
- public const string EnableSSE = "COMPlus_EnableSSE";
- public const string EnableSSE2 = "COMPlus_EnableSSE2";
- public const string EnableSSE3 = "COMPlus_EnableSSE3";
- public const string EnableSSE3_4 = "COMPlus_EnableSSE3_4";
- public const string EnableSSE41 = "COMPlus_EnableSSE41";
- public const string EnableSSE42 = "COMPlus_EnableSSE42";
- public const string EnableSSSE3 = "COMPlus_EnableSSSE3";
- public const string FeatureSIMD = "COMPlus_FeatureSIMD";
- }
- }
-}
diff --git a/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.cs b/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.cs
index 1375b5763e..48728faf0e 100644
--- a/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.cs
+++ b/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.cs
@@ -170,7 +170,10 @@ namespace SixLabors.ImageSharp.Tests
}
string testProjectConfigPath = TestAssemblyFile.FullName + ".config";
- File.Copy(testProjectConfigPath, remoteExecutorConfigPath);
+ if (File.Exists(testProjectConfigPath))
+ {
+ File.Copy(testProjectConfigPath, remoteExecutorConfigPath);
+ }
if (Is64BitProcess)
{
diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/FeatureTestRunnerTests.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/FeatureTestRunnerTests.cs
new file mode 100644
index 0000000000..646000120f
--- /dev/null
+++ b/tests/ImageSharp.Tests/TestUtilities/Tests/FeatureTestRunnerTests.cs
@@ -0,0 +1,296 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Numerics;
+#if SUPPORTS_RUNTIME_INTRINSICS
+using System.Runtime.Intrinsics.X86;
+#endif
+using Xunit;
+using Xunit.Abstractions;
+
+namespace SixLabors.ImageSharp.Tests.TestUtilities.Tests
+{
+ public class FeatureTestRunnerTests
+ {
+ public static TheoryData Intrinsics =>
+ new TheoryData
+ {
+ { HwIntrinsics.DisableAES | HwIntrinsics.AllowAll, new string[] { "EnableAES", "AllowAll" } },
+ { HwIntrinsics.DisableSIMD | HwIntrinsics.DisableHWIntrinsic, new string[] { "FeatureSIMD", "EnableHWIntrinsic" } },
+ { HwIntrinsics.DisableSSE42 | HwIntrinsics.DisableAVX, new string[] { "EnableSSE42", "EnableAVX" } }
+ };
+
+ [Theory]
+ [MemberData(nameof(Intrinsics))]
+ public void ToFeatureCollectionReturnsExpectedResult(HwIntrinsics expectedItrinsics, string[] expectedValues)
+ {
+ Dictionary features = expectedItrinsics.ToFeatureKeyValueCollection();
+ HwIntrinsics[] keys = features.Keys.ToArray();
+
+ HwIntrinsics actualIntrinsics = keys[0];
+ for (int i = 1; i < keys.Length; i++)
+ {
+ actualIntrinsics |= keys[i];
+ }
+
+ Assert.Equal(expectedItrinsics, actualIntrinsics);
+
+ IEnumerable actualValues = features.Select(x => x.Value);
+ Assert.Equal(expectedValues, actualValues);
+ }
+
+ [Fact]
+ public void AllowsAllHwIntrinsicFeatures()
+ {
+ if (!Vector.IsHardwareAccelerated)
+ {
+ return;
+ }
+
+ FeatureTestRunner.RunWithHwIntrinsicsFeature(
+ () => Assert.True(Vector.IsHardwareAccelerated),
+ HwIntrinsics.AllowAll);
+ }
+
+ [Fact]
+ public void CanLimitHwIntrinsicSIMDFeatures()
+ {
+ FeatureTestRunner.RunWithHwIntrinsicsFeature(
+ () => Assert.False(Vector.IsHardwareAccelerated),
+ HwIntrinsics.DisableSIMD);
+ }
+
+#if SUPPORTS_RUNTIME_INTRINSICS
+ [Fact]
+ public void CanLimitHwIntrinsicBaseFeatures()
+ {
+ static void AssertDisabled()
+ {
+ Assert.False(Sse.IsSupported);
+ Assert.False(Sse2.IsSupported);
+ Assert.False(Aes.IsSupported);
+ Assert.False(Pclmulqdq.IsSupported);
+ Assert.False(Sse3.IsSupported);
+ Assert.False(Ssse3.IsSupported);
+ Assert.False(Sse41.IsSupported);
+ Assert.False(Sse42.IsSupported);
+ Assert.False(Popcnt.IsSupported);
+ Assert.False(Avx.IsSupported);
+ Assert.False(Fma.IsSupported);
+ Assert.False(Avx2.IsSupported);
+ Assert.False(Bmi1.IsSupported);
+ Assert.False(Bmi2.IsSupported);
+ Assert.False(Lzcnt.IsSupported);
+ }
+
+ FeatureTestRunner.RunWithHwIntrinsicsFeature(
+ AssertDisabled,
+ HwIntrinsics.DisableHWIntrinsic);
+ }
+#endif
+
+ [Fact]
+ public void CanLimitHwIntrinsicFeaturesWithIntrinsicsParam()
+ {
+ static void AssertHwIntrinsicsFeatureDisabled(string intrinsic)
+ {
+ Assert.NotNull(intrinsic);
+
+ switch ((HwIntrinsics)Enum.Parse(typeof(HwIntrinsics), intrinsic))
+ {
+ case HwIntrinsics.DisableSIMD:
+ Assert.False(Vector.IsHardwareAccelerated);
+ break;
+#if SUPPORTS_RUNTIME_INTRINSICS
+ case HwIntrinsics.DisableHWIntrinsic:
+ Assert.False(Sse.IsSupported);
+ Assert.False(Sse2.IsSupported);
+ Assert.False(Aes.IsSupported);
+ Assert.False(Pclmulqdq.IsSupported);
+ Assert.False(Sse3.IsSupported);
+ Assert.False(Ssse3.IsSupported);
+ Assert.False(Sse41.IsSupported);
+ Assert.False(Sse42.IsSupported);
+ Assert.False(Popcnt.IsSupported);
+ Assert.False(Avx.IsSupported);
+ Assert.False(Fma.IsSupported);
+ Assert.False(Avx2.IsSupported);
+ Assert.False(Bmi1.IsSupported);
+ Assert.False(Bmi2.IsSupported);
+ Assert.False(Lzcnt.IsSupported);
+ break;
+ case HwIntrinsics.DisableSSE:
+ Assert.False(Sse.IsSupported);
+ break;
+ case HwIntrinsics.DisableSSE2:
+ Assert.False(Sse2.IsSupported);
+ break;
+ case HwIntrinsics.DisableAES:
+ Assert.False(Aes.IsSupported);
+ break;
+ case HwIntrinsics.DisablePCLMULQDQ:
+ Assert.False(Pclmulqdq.IsSupported);
+ break;
+ case HwIntrinsics.DisableSSE3:
+ Assert.False(Sse3.IsSupported);
+ break;
+ case HwIntrinsics.DisableSSSE3:
+ Assert.False(Ssse3.IsSupported);
+ break;
+ case HwIntrinsics.DisableSSE41:
+ Assert.False(Sse41.IsSupported);
+ break;
+ case HwIntrinsics.DisableSSE42:
+ Assert.False(Sse42.IsSupported);
+ break;
+ case HwIntrinsics.DisablePOPCNT:
+ Assert.False(Popcnt.IsSupported);
+ break;
+ case HwIntrinsics.DisableAVX:
+ Assert.False(Avx.IsSupported);
+ break;
+ case HwIntrinsics.DisableFMA:
+ Assert.False(Fma.IsSupported);
+ break;
+ case HwIntrinsics.DisableAVX2:
+ Assert.False(Avx2.IsSupported);
+ break;
+ case HwIntrinsics.DisableBMI1:
+ Assert.False(Bmi1.IsSupported);
+ break;
+ case HwIntrinsics.DisableBMI2:
+ Assert.False(Bmi2.IsSupported);
+ break;
+ case HwIntrinsics.DisableLZCNT:
+ Assert.False(Lzcnt.IsSupported);
+ break;
+#endif
+ }
+ }
+
+ foreach (HwIntrinsics intrinsic in (HwIntrinsics[])Enum.GetValues(typeof(HwIntrinsics)))
+ {
+ FeatureTestRunner.RunWithHwIntrinsicsFeature(AssertHwIntrinsicsFeatureDisabled, intrinsic);
+ }
+ }
+
+ [Fact]
+ public void CanLimitHwIntrinsicFeaturesWithSerializableParam()
+ {
+ static void AssertHwIntrinsicsFeatureDisabled(string serializable)
+ {
+ Assert.NotNull(serializable);
+ Assert.NotNull(FeatureTestRunner.Deserialize(serializable));
+
+#if SUPPORTS_RUNTIME_INTRINSICS
+ Assert.False(Sse.IsSupported);
+#endif
+ }
+
+ FeatureTestRunner.RunWithHwIntrinsicsFeature(
+ AssertHwIntrinsicsFeatureDisabled,
+ HwIntrinsics.DisableSSE,
+ new FakeSerializable());
+ }
+
+ [Fact]
+ public void CanLimitHwIntrinsicFeaturesWithSerializableAndIntrinsicsParams()
+ {
+ static void AssertHwIntrinsicsFeatureDisabled(string serializable, string intrinsic)
+ {
+ Assert.NotNull(serializable);
+ Assert.NotNull(FeatureTestRunner.Deserialize(serializable));
+
+ switch ((HwIntrinsics)Enum.Parse(typeof(HwIntrinsics), intrinsic))
+ {
+ case HwIntrinsics.DisableSIMD:
+ Assert.False(Vector.IsHardwareAccelerated, nameof(Vector.IsHardwareAccelerated));
+ break;
+#if SUPPORTS_RUNTIME_INTRINSICS
+ case HwIntrinsics.DisableHWIntrinsic:
+ Assert.False(Sse.IsSupported);
+ Assert.False(Sse2.IsSupported);
+ Assert.False(Aes.IsSupported);
+ Assert.False(Pclmulqdq.IsSupported);
+ Assert.False(Sse3.IsSupported);
+ Assert.False(Ssse3.IsSupported);
+ Assert.False(Sse41.IsSupported);
+ Assert.False(Sse42.IsSupported);
+ Assert.False(Popcnt.IsSupported);
+ Assert.False(Avx.IsSupported);
+ Assert.False(Fma.IsSupported);
+ Assert.False(Avx2.IsSupported);
+ Assert.False(Bmi1.IsSupported);
+ Assert.False(Bmi2.IsSupported);
+ Assert.False(Lzcnt.IsSupported);
+ break;
+ case HwIntrinsics.DisableSSE:
+ Assert.False(Sse.IsSupported);
+ break;
+ case HwIntrinsics.DisableSSE2:
+ Assert.False(Sse2.IsSupported);
+ break;
+ case HwIntrinsics.DisableAES:
+ Assert.False(Aes.IsSupported);
+ break;
+ case HwIntrinsics.DisablePCLMULQDQ:
+ Assert.False(Pclmulqdq.IsSupported);
+ break;
+ case HwIntrinsics.DisableSSE3:
+ Assert.False(Sse3.IsSupported);
+ break;
+ case HwIntrinsics.DisableSSSE3:
+ Assert.False(Ssse3.IsSupported);
+ break;
+ case HwIntrinsics.DisableSSE41:
+ Assert.False(Sse41.IsSupported);
+ break;
+ case HwIntrinsics.DisableSSE42:
+ Assert.False(Sse42.IsSupported);
+ break;
+ case HwIntrinsics.DisablePOPCNT:
+ Assert.False(Popcnt.IsSupported);
+ break;
+ case HwIntrinsics.DisableAVX:
+ Assert.False(Avx.IsSupported);
+ break;
+ case HwIntrinsics.DisableFMA:
+ Assert.False(Fma.IsSupported);
+ break;
+ case HwIntrinsics.DisableAVX2:
+ Assert.False(Avx2.IsSupported);
+ break;
+ case HwIntrinsics.DisableBMI1:
+ Assert.False(Bmi1.IsSupported);
+ break;
+ case HwIntrinsics.DisableBMI2:
+ Assert.False(Bmi2.IsSupported);
+ break;
+ case HwIntrinsics.DisableLZCNT:
+ Assert.False(Lzcnt.IsSupported);
+ break;
+#endif
+ }
+ }
+
+ foreach (HwIntrinsics intrinsic in (HwIntrinsics[])Enum.GetValues(typeof(HwIntrinsics)))
+ {
+ FeatureTestRunner.RunWithHwIntrinsicsFeature(AssertHwIntrinsicsFeatureDisabled, intrinsic, new FakeSerializable());
+ }
+ }
+
+ public class FakeSerializable : IXunitSerializable
+ {
+ public void Deserialize(IXunitSerializationInfo info)
+ {
+ }
+
+ public void Serialize(IXunitSerializationInfo info)
+ {
+ }
+ }
+ }
+}
diff --git a/tests/coverlet.runsettings b/tests/coverlet.runsettings
index ee408a5f04..cffce3540b 100644
--- a/tests/coverlet.runsettings
+++ b/tests/coverlet.runsettings
@@ -1,5 +1,9 @@
+
+
+ category!=failing
+