diff --git a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterAvx.cs b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterAvx.cs index d7b619fca9..429b8677b6 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterAvx.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterAvx.cs @@ -25,8 +25,13 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components { } + /// + /// Gets a value indicating whether this converter is supported on current hardware. + /// + public static bool IsSupported => Avx.IsSupported; + /// - public override bool IsAvailable => Avx.IsSupported; + public override bool IsAvailable => IsSupported; } } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterBase.cs b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterBase.cs index 34b48c2fe6..8048f3233d 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterBase.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterBase.cs @@ -93,73 +93,116 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// private static JpegColorConverterBase[] CreateConverters() { - var converters = new List(); + // 5 color types with 2 supported precisions: 8 bit & 12 bit + const int colorConvertersCount = 5 * 2; + + var converters = new JpegColorConverterBase[colorConvertersCount]; // 8-bit converters - converters.AddRange(GetYCbCrConverters(8)); - converters.AddRange(GetYccKConverters(8)); - converters.AddRange(GetCmykConverters(8)); - converters.AddRange(GetGrayScaleConverters(8)); - converters.AddRange(GetRgbConverters(8)); + converters[0] = GetYCbCrConverter(8); + converters[1] = GetYccKConverter(8); + converters[2] = GetCmykConverter(8); + converters[3] = GetGrayScaleConverter(8); + converters[4] = GetRgbConverter(8); // 12-bit converters - converters.AddRange(GetYCbCrConverters(12)); - converters.AddRange(GetYccKConverters(12)); - converters.AddRange(GetCmykConverters(12)); - converters.AddRange(GetGrayScaleConverters(12)); - converters.AddRange(GetRgbConverters(12)); + converters[5] = GetYCbCrConverter(12); + converters[6] = GetYccKConverter(12); + converters[7] = GetCmykConverter(12); + converters[8] = GetGrayScaleConverter(12); + converters[9] = GetRgbConverter(12); - return converters.Where(x => x.IsAvailable).ToArray(); + return converters; } /// /// Returns the s for the YCbCr colorspace. /// - private static IEnumerable GetYCbCrConverters(int precision) + private static JpegColorConverterBase GetYCbCrConverter(int precision) { - yield return new YCbCrAvx(precision); - yield return new YCbCrVector(precision); - yield return new YCbCrScalar(precision); + if (JpegColorConverterAvx.IsSupported) + { + return new YCbCrAvx(precision); + } + + if (JpegColorConverterVector.IsSupported) + { + return new YCbCrVector(precision); + } + + return new YCbCrScalar(precision); } /// /// Returns the s for the YccK colorspace. /// - private static IEnumerable GetYccKConverters(int precision) + private static JpegColorConverterBase GetYccKConverter(int precision) { - yield return new YccKAvx(precision); - yield return new YccKVector(precision); - yield return new YccKScalar(precision); + if (JpegColorConverterAvx.IsSupported) + { + return new YccKAvx(precision); + } + + if (JpegColorConverterVector.IsSupported) + { + return new YccKVector(precision); + } + + return new YccKScalar(precision); } /// /// Returns the s for the CMYK colorspace. /// - private static IEnumerable GetCmykConverters(int precision) + private static JpegColorConverterBase GetCmykConverter(int precision) { - yield return new CmykAvx(precision); - yield return new CmykVector(precision); - yield return new CmykScalar(precision); + if (JpegColorConverterAvx.IsSupported) + { + return new CmykAvx(precision); + } + + if (JpegColorConverterVector.IsSupported) + { + return new CmykVector(precision); + } + + return new CmykScalar(precision); } /// /// Returns the s for the gray scale colorspace. /// - private static IEnumerable GetGrayScaleConverters(int precision) + private static JpegColorConverterBase GetGrayScaleConverter(int precision) { - yield return new GrayscaleAvx(precision); - yield return new GrayScaleVector(precision); - yield return new GrayscaleScalar(precision); + if (JpegColorConverterAvx.IsSupported) + { + return new GrayscaleAvx(precision); + } + + if (JpegColorConverterVector.IsSupported) + { + return new GrayScaleVector(precision); + } + + return new GrayscaleScalar(precision); } /// /// Returns the s for the RGB colorspace. /// - private static IEnumerable GetRgbConverters(int precision) + private static JpegColorConverterBase GetRgbConverter(int precision) { - yield return new RgbAvx(precision); - yield return new RgbVector(precision); - yield return new RgbScalar(precision); + if (JpegColorConverterAvx.IsSupported) + { + return new RgbAvx(precision); + } + + if (JpegColorConverterVector.IsSupported) + { + return new RgbScalar(precision); + } + + return new GrayscaleScalar(precision); } /// diff --git a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterVector.cs b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterVector.cs index 3c8b16943b..92d388fc8f 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterVector.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterVector.cs @@ -26,8 +26,13 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components { } + /// + /// Gets a value indicating whether this converter is supported on current hardware. + /// + public static bool IsSupported => Vector.IsHardwareAccelerated && Vector.Count % 4 == 0; + /// - public sealed override bool IsAvailable => Vector.IsHardwareAccelerated && Vector.Count % 4 == 0; + public sealed override bool IsAvailable => IsSupported; /// public sealed override void ConvertToRgbInplace(in ComponentValues values) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanScanEncoder.cs b/src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanScanEncoder.cs index 4268f862c2..7274b51961 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanScanEncoder.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanScanEncoder.cs @@ -149,7 +149,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder { case JpegEncodingColor.YCbCrRatio444: case JpegEncodingColor.Rgb: - this.EncodeThreeComponentScanBaselineInterleaved444(frame, converter, cancellationToken); + this.EncodeThreeComponentBaselineInterleavedScanNoSubsampling(frame, converter, cancellationToken); break; default: this.EncodeScanBaselineInterleaved(frame, converter, cancellationToken); @@ -310,12 +310,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder } /// - /// Encodes scan in baseline interleaved mode with exactly 3 components with 4:4:4 sampling. + /// Encodes scan in baseline interleaved mode with exactly 3 components with no subsampling. /// /// Frame to encode. /// Converter from color to spectral. /// The token to request cancellation. - private void EncodeThreeComponentScanBaselineInterleaved444(JpegFrame frame, SpectralConverter converter, CancellationToken cancellationToken) + private void EncodeThreeComponentBaselineInterleavedScanNoSubsampling(JpegFrame frame, SpectralConverter converter, CancellationToken cancellationToken) where TPixel : unmanaged, IPixel { nint mcusPerColumn = frame.McusPerColumn; diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpegFeatures.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpegFeatures.cs index 6844883486..a593f0489a 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpegFeatures.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpegFeatures.cs @@ -84,16 +84,16 @@ Intel Core i7-6700K CPU 4.00GHz (Skylake), 1 CPU, 8 logical and 4 physical cores | Method | TargetColorSpace | Quality | Mean | Error | StdDev | |---------- |----------------- |-------- |----------:|----------:|----------:| -| Benchmark | Luminance | 75 | 4.575 ms | 0.0233 ms | 0.0207 ms | -| Benchmark | Rgb | 75 | 12.477 ms | 0.1051 ms | 0.0932 ms | -| Benchmark | YCbCrRatio420 | 75 | 6.421 ms | 0.0464 ms | 0.0434 ms | -| Benchmark | YCbCrRatio444 | 75 | 8.449 ms | 0.1246 ms | 0.1166 ms | -| Benchmark | Luminance | 90 | 4.863 ms | 0.0120 ms | 0.0106 ms | -| Benchmark | Rgb | 90 | 13.287 ms | 0.0548 ms | 0.0513 ms | -| Benchmark | YCbCrRatio420 | 90 | 7.012 ms | 0.0533 ms | 0.0499 ms | -| Benchmark | YCbCrRatio444 | 90 | 8.916 ms | 0.1285 ms | 0.1202 ms | -| Benchmark | Luminance | 100 | 6.665 ms | 0.0136 ms | 0.0113 ms | -| Benchmark | Rgb | 100 | 19.734 ms | 0.0477 ms | 0.0446 ms | -| Benchmark | YCbCrRatio420 | 100 | 10.541 ms | 0.0925 ms | 0.0865 ms | -| Benchmark | YCbCrRatio444 | 100 | 15.587 ms | 0.1695 ms | 0.1586 ms | +| Benchmark | Luminance | 75 | 4.618 ms | 0.0263 ms | 0.0233 ms | +| Benchmark | Rgb | 75 | 12.543 ms | 0.0650 ms | 0.0608 ms | +| Benchmark | YCbCrRatio420 | 75 | 6.639 ms | 0.0778 ms | 0.1256 ms | +| Benchmark | YCbCrRatio444 | 75 | 8.590 ms | 0.0570 ms | 0.0505 ms | +| Benchmark | Luminance | 90 | 4.902 ms | 0.0307 ms | 0.0288 ms | +| Benchmark | Rgb | 90 | 13.447 ms | 0.0468 ms | 0.0415 ms | +| Benchmark | YCbCrRatio420 | 90 | 7.218 ms | 0.0586 ms | 0.0548 ms | +| Benchmark | YCbCrRatio444 | 90 | 9.150 ms | 0.0779 ms | 0.0729 ms | +| Benchmark | Luminance | 100 | 6.731 ms | 0.0325 ms | 0.0304 ms | +| Benchmark | Rgb | 100 | 19.831 ms | 0.1009 ms | 0.0788 ms | +| Benchmark | YCbCrRatio420 | 100 | 10.541 ms | 0.0423 ms | 0.0396 ms | +| Benchmark | YCbCrRatio444 | 100 | 15.345 ms | 0.3276 ms | 0.3065 ms | */