diff --git a/src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegColorConverter.FromCmyk.cs b/src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromCmyk.cs similarity index 89% rename from src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegColorConverter.FromCmyk.cs rename to src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromCmyk.cs index 908ffb85e..b67d73fd4 100644 --- a/src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegColorConverter.FromCmyk.cs +++ b/src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromCmyk.cs @@ -1,11 +1,11 @@ using System; using System.Numerics; -namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder +namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters { internal abstract partial class JpegColorConverter { - internal class FromCmyk : JpegColorConverter + internal class FromCmyk : ColorConverters.JpegColorConverter { public FromCmyk() : base(JpegColorSpace.Cmyk) diff --git a/src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegColorConverter.FromGrayScale.cs b/src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromGrayScale.cs similarity index 86% rename from src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegColorConverter.FromGrayScale.cs rename to src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromGrayScale.cs index 2b19eebac..ffc3f80df 100644 --- a/src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegColorConverter.FromGrayScale.cs +++ b/src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromGrayScale.cs @@ -1,11 +1,11 @@ using System; using System.Numerics; -namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder +namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters { internal abstract partial class JpegColorConverter { - internal class FromGrayScale : JpegColorConverter + internal class FromGrayScale : ColorConverters.JpegColorConverter { public FromGrayScale() : base(JpegColorSpace.GrayScale) diff --git a/src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegColorConverter.FromRgb.cs b/src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromRgb.cs similarity index 88% rename from src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegColorConverter.FromRgb.cs rename to src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromRgb.cs index c4a30ea3e..fb6bf91ff 100644 --- a/src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegColorConverter.FromRgb.cs +++ b/src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromRgb.cs @@ -1,11 +1,11 @@ using System; using System.Numerics; -namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder +namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters { internal abstract partial class JpegColorConverter { - internal class FromRgb : JpegColorConverter + internal class FromRgb : ColorConverters.JpegColorConverter { public FromRgb() : base(JpegColorSpace.RGB) diff --git a/src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromYCbCr.cs b/src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromYCbCr.cs new file mode 100644 index 000000000..7fa6c92e9 --- /dev/null +++ b/src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromYCbCr.cs @@ -0,0 +1,93 @@ +using System; +using System.Numerics; +using System.Runtime.CompilerServices; +using SixLabors.ImageSharp.Common.Tuples; + +namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters +{ + internal abstract partial class JpegColorConverter + { + internal class FromYCbCrSimdAvx2 : ColorConverters.JpegColorConverter + { + public FromYCbCrSimdAvx2() + : base(JpegColorSpace.YCbCr) + { + } + + public static bool IsAvailable => Vector.IsHardwareAccelerated && Vector.Count == 8; + + public override void ConvertToRGBA(ComponentValues values, Span result) + { + int remainder = result.Length % 8; + int simdCount = result.Length - remainder; + if (simdCount > 0) + { + ConvertCore(values.Slice(0, simdCount), result.Slice(0, simdCount)); + } + + FromYCbCrBasic.ConvertCore(values.Slice(simdCount, remainder), result.Slice(simdCount, remainder)); + } + + /// + /// SIMD convert using buffers of sizes divisable by 8. + /// + internal static void ConvertCore(ComponentValues values, Span result) + { + // This implementation is actually AVX specific. + // An AVX register is capable of storing 8 float-s. + if (!IsAvailable) + { + throw new InvalidOperationException( + "JpegColorConverter.FromYCbCrSimd256 can be used only on architecture having 256 byte floating point SIMD registers!"); + } + + ref Vector yBase = + ref Unsafe.As>(ref values.Component0.DangerousGetPinnableReference()); + ref Vector cbBase = + ref Unsafe.As>(ref values.Component1.DangerousGetPinnableReference()); + ref Vector crBase = + ref Unsafe.As>(ref values.Component2.DangerousGetPinnableReference()); + + ref Vector4Octet resultBase = + ref Unsafe.As(ref result.DangerousGetPinnableReference()); + + var chromaOffset = new Vector(-128f); + + // Walking 8 elements at one step: + int n = result.Length / 8; + + for (int i = 0; i < n; i++) + { + // y = yVals[i]; + // cb = cbVals[i] - 128F; + // cr = crVals[i] - 128F; + Vector y = Unsafe.Add(ref yBase, i); + Vector cb = Unsafe.Add(ref cbBase, i) + chromaOffset; + Vector cr = Unsafe.Add(ref crBase, i) + chromaOffset; + + // r = y + (1.402F * cr); + // g = y - (0.344136F * cb) - (0.714136F * cr); + // b = y + (1.772F * cb); + // Adding & multiplying 8 elements at one time: + Vector r = y + (cr * new Vector(1.402F)); + Vector g = y - (cb * new Vector(0.344136F)) - (cr * new Vector(0.714136F)); + Vector b = y + (cb * new Vector(1.772F)); + + // Vector has no .Clamp(), need to switch to Vector4 for the next operation: + // TODO: Is it worth to use Vector at all? + Vector4Pair rr = Unsafe.As, Vector4Pair>(ref r); + Vector4Pair gg = Unsafe.As, Vector4Pair>(ref g); + Vector4Pair bb = Unsafe.As, Vector4Pair>(ref b); + + rr.RoundAndDownscaleAvx2(); + gg.RoundAndDownscaleAvx2(); + bb.RoundAndDownscaleAvx2(); + + // Collect (r0,r1...r8) (g0,g1...g8) (b0,b1...b8) vector values in the expected (r0,g0,g1,1), (r1,g1,g2,1) ... order: + ref Vector4Octet destination = ref Unsafe.Add(ref resultBase, i); + destination.Collect(ref rr, ref gg, ref bb); + } + } + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromYCbCrBasic.cs b/src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromYCbCrBasic.cs new file mode 100644 index 000000000..88b190675 --- /dev/null +++ b/src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromYCbCrBasic.cs @@ -0,0 +1,48 @@ +using System; +using System.Numerics; + +namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters +{ + internal abstract partial class JpegColorConverter + { + internal class FromYCbCrBasic : ColorConverters.JpegColorConverter + { + public FromYCbCrBasic() + : base(JpegColorSpace.YCbCr) + { + } + + public override void ConvertToRGBA(ComponentValues values, Span result) + { + ConvertCore(values, result); + } + + internal static void ConvertCore(ComponentValues values, Span result) + { + // TODO: We can optimize a lot here with Vector and SRCS.Unsafe()! + ReadOnlySpan yVals = values.Component0; + ReadOnlySpan cbVals = values.Component1; + ReadOnlySpan crVals = values.Component2; + + var v = new Vector4(0, 0, 0, 1); + + var scale = new Vector4(1 / 255F, 1 / 255F, 1 / 255F, 1F); + + for (int i = 0; i < result.Length; i++) + { + float y = yVals[i]; + float cb = cbVals[i] - 128F; + float cr = crVals[i] - 128F; + + v.X = MathF.Round(y + (1.402F * cr), MidpointRounding.AwayFromZero); + v.Y = MathF.Round(y - (0.344136F * cb) - (0.714136F * cr), MidpointRounding.AwayFromZero); + v.Z = MathF.Round(y + (1.772F * cb), MidpointRounding.AwayFromZero); + + v *= scale; + + result[i] = v; + } + } + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegColorConverter.FromYCbCr.cs b/src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimd.cs similarity index 57% rename from src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegColorConverter.FromYCbCr.cs rename to src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimd.cs index b988695e1..9d985dca6 100644 --- a/src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegColorConverter.FromYCbCr.cs +++ b/src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimd.cs @@ -3,51 +3,11 @@ using System.Numerics; using System.Runtime.CompilerServices; using SixLabors.ImageSharp.Common.Tuples; -namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder +namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters { internal abstract partial class JpegColorConverter { - internal class FromYCbCrBasic : JpegColorConverter - { - public FromYCbCrBasic() - : base(JpegColorSpace.YCbCr) - { - } - - public override void ConvertToRGBA(ComponentValues values, Span result) - { - ConvertCore(values, result); - } - - internal static void ConvertCore(ComponentValues values, Span result) - { - // TODO: We can optimize a lot here with Vector and SRCS.Unsafe()! - ReadOnlySpan yVals = values.Component0; - ReadOnlySpan cbVals = values.Component1; - ReadOnlySpan crVals = values.Component2; - - var v = new Vector4(0, 0, 0, 1); - - var scale = new Vector4(1 / 255F, 1 / 255F, 1 / 255F, 1F); - - for (int i = 0; i < result.Length; i++) - { - float y = yVals[i]; - float cb = cbVals[i] - 128F; - float cr = crVals[i] - 128F; - - v.X = MathF.Round(y + (1.402F * cr), MidpointRounding.AwayFromZero); - v.Y = MathF.Round(y - (0.344136F * cb) - (0.714136F * cr), MidpointRounding.AwayFromZero); - v.Z = MathF.Round(y + (1.772F * cb), MidpointRounding.AwayFromZero); - - v *= scale; - - result[i] = v; - } - } - } - - internal class FromYCbCrSimd : JpegColorConverter + internal class FromYCbCrSimd : ColorConverters.JpegColorConverter { public FromYCbCrSimd() : base(JpegColorSpace.YCbCr) @@ -147,58 +107,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder destination.Collect(ref r, ref g, ref b); } } - - private struct Vector4Octet - { -#pragma warning disable SA1132 // Do not combine fields - public Vector4 V0, V1, V2, V3, V4, V5, V6, V7; - - /// - /// Collect (r0,r1...r8) (g0,g1...g8) (b0,b1...b8) vector values in the expected (r0,g0,g1,1), (r1,g1,g2,1) ... order. - /// - public void Collect(ref Vector4Pair r, ref Vector4Pair g, ref Vector4Pair b) - { - this.V0.X = r.A.X; - this.V0.Y = g.A.X; - this.V0.Z = b.A.X; - this.V0.W = 1f; - - this.V1.X = r.A.Y; - this.V1.Y = g.A.Y; - this.V1.Z = b.A.Y; - this.V1.W = 1f; - - this.V2.X = r.A.Z; - this.V2.Y = g.A.Z; - this.V2.Z = b.A.Z; - this.V2.W = 1f; - - this.V3.X = r.A.W; - this.V3.Y = g.A.W; - this.V3.Z = b.A.W; - this.V3.W = 1f; - - this.V4.X = r.B.X; - this.V4.Y = g.B.X; - this.V4.Z = b.B.X; - this.V4.W = 1f; - - this.V5.X = r.B.Y; - this.V5.Y = g.B.Y; - this.V5.Z = b.B.Y; - this.V5.W = 1f; - - this.V6.X = r.B.Z; - this.V6.Y = g.B.Z; - this.V6.Z = b.B.Z; - this.V6.W = 1f; - - this.V7.X = r.B.W; - this.V7.Y = g.B.W; - this.V7.Z = b.B.W; - this.V7.W = 1f; - } - } } } } \ No newline at end of file diff --git a/src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegColorConverter.FromYccK.cs b/src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromYccK.cs similarity index 91% rename from src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegColorConverter.FromYccK.cs rename to src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromYccK.cs index 7e6edbdce..22e524c70 100644 --- a/src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegColorConverter.FromYccK.cs +++ b/src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromYccK.cs @@ -1,11 +1,11 @@ using System; using System.Numerics; -namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder +namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters { internal abstract partial class JpegColorConverter { - internal class FromYccK : JpegColorConverter + internal class FromYccK : ColorConverters.JpegColorConverter { public FromYccK() : base(JpegColorSpace.Ycck) diff --git a/src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegColorConverter.cs b/src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.cs similarity index 73% rename from src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegColorConverter.cs rename to src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.cs index 1c2dda01f..0bdb8ff7b 100644 --- a/src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegColorConverter.cs +++ b/src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.cs @@ -2,10 +2,10 @@ using System; using System.Collections.Generic; using System.Linq; using System.Numerics; - +using SixLabors.ImageSharp.Common.Tuples; using SixLabors.ImageSharp.Memory; -namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder +namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters { /// /// Encapsulates the conversion of Jpeg channels to RGBA values packed in buffer. @@ -15,7 +15,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder /// /// The avalilable converters /// - private static readonly JpegColorConverter[] Converters = { new FromYCbCrSimd(), new FromYccK(), new FromCmyk(), new FromGrayScale(), new FromRgb() }; + private static readonly JpegColorConverter[] Converters = + { + new FromYCbCrSimd(), new FromYccK(), new FromCmyk(), new FromGrayScale(), new FromRgb() + }; /// /// Initializes a new instance of the class. @@ -133,5 +136,57 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder return new ComponentValues(this.ComponentCount, c0, c1, c2, c3); } } + + internal struct Vector4Octet + { +#pragma warning disable SA1132 // Do not combine fields + public Vector4 V0, V1, V2, V3, V4, V5, V6, V7; + + /// + /// Collect (r0,r1...r8) (g0,g1...g8) (b0,b1...b8) vector values in the expected (r0,g0,g1,1), (r1,g1,g2,1) ... order. + /// + public void Collect(ref Vector4Pair r, ref Vector4Pair g, ref Vector4Pair b) + { + this.V0.X = r.A.X; + this.V0.Y = g.A.X; + this.V0.Z = b.A.X; + this.V0.W = 1f; + + this.V1.X = r.A.Y; + this.V1.Y = g.A.Y; + this.V1.Z = b.A.Y; + this.V1.W = 1f; + + this.V2.X = r.A.Z; + this.V2.Y = g.A.Z; + this.V2.Z = b.A.Z; + this.V2.W = 1f; + + this.V3.X = r.A.W; + this.V3.Y = g.A.W; + this.V3.Z = b.A.W; + this.V3.W = 1f; + + this.V4.X = r.B.X; + this.V4.Y = g.B.X; + this.V4.Z = b.B.X; + this.V4.W = 1f; + + this.V5.X = r.B.Y; + this.V5.Y = g.B.Y; + this.V5.Z = b.B.Y; + this.V5.W = 1f; + + this.V6.X = r.B.Z; + this.V6.Y = g.B.Z; + this.V6.Z = b.B.Z; + this.V6.W = 1f; + + this.V7.X = r.B.W; + this.V7.Y = g.B.W; + this.V7.Z = b.B.W; + this.V7.W = 1f; + } + } } } \ No newline at end of file diff --git a/src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegImagePostProcessor.cs b/src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegImagePostProcessor.cs index 84867d276..125ec5272 100644 --- a/src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegImagePostProcessor.cs +++ b/src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegImagePostProcessor.cs @@ -37,9 +37,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder private readonly Buffer rgbaBuffer; /// - /// The corresponding to the current determined by . + /// The corresponding to the current determined by . /// - private JpegColorConverter colorConverter; + private ColorConverters.JpegColorConverter colorConverter; /// /// Initializes a new instance of the class. @@ -54,7 +54,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder this.ComponentProcessors = rawJpeg.Components.Select(c => new JpegComponentPostProcessor(this, c)).ToArray(); this.rgbaBuffer = new Buffer(rawJpeg.ImageSizeInPixels.Width); - this.colorConverter = JpegColorConverter.GetConverter(rawJpeg.ColorSpace); + this.colorConverter = ColorConverters.JpegColorConverter.GetConverter(rawJpeg.ColorSpace); } /// @@ -148,7 +148,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder { int y = yy - this.PixelRowCounter; - var values = new JpegColorConverter.ComponentValues(buffers, y); + var values = new ColorConverters.JpegColorConverter.ComponentValues(buffers, y); this.colorConverter.ConvertToRGBA(values, this.rgbaBuffer); Span destRow = destination.GetPixelRowSpan(yy); diff --git a/tests/ImageSharp.Benchmarks/Image/DecodeJpeg.cs b/tests/ImageSharp.Benchmarks/Image/Jpeg/DecodeJpeg.cs similarity index 94% rename from tests/ImageSharp.Benchmarks/Image/DecodeJpeg.cs rename to tests/ImageSharp.Benchmarks/Image/Jpeg/DecodeJpeg.cs index 60bf49eba..6d1354ca2 100644 --- a/tests/ImageSharp.Benchmarks/Image/DecodeJpeg.cs +++ b/tests/ImageSharp.Benchmarks/Image/Jpeg/DecodeJpeg.cs @@ -3,19 +3,18 @@ // Licensed under the Apache License, Version 2.0. // -namespace SixLabors.ImageSharp.Benchmarks.Image +namespace SixLabors.ImageSharp.Benchmarks.Image.Jpeg { using System.Drawing; using System.IO; using BenchmarkDotNet.Attributes; - using BenchmarkDotNet.Attributes.Jobs; using SixLabors.ImageSharp.Formats.Jpeg.GolangPort; using SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort; using SixLabors.ImageSharp.Tests; - using CoreImage = ImageSharp.Image; + using CoreImage = SixLabors.ImageSharp.Image; using CoreSize = SixLabors.Primitives.Size; diff --git a/tests/ImageSharp.Benchmarks/Image/DecodeJpegMultiple.cs b/tests/ImageSharp.Benchmarks/Image/Jpeg/DecodeJpegMultiple.cs similarity index 81% rename from tests/ImageSharp.Benchmarks/Image/DecodeJpegMultiple.cs rename to tests/ImageSharp.Benchmarks/Image/Jpeg/DecodeJpegMultiple.cs index 0577c294e..d5eb5a20c 100644 --- a/tests/ImageSharp.Benchmarks/Image/DecodeJpegMultiple.cs +++ b/tests/ImageSharp.Benchmarks/Image/Jpeg/DecodeJpegMultiple.cs @@ -3,18 +3,13 @@ // Licensed under the Apache License, Version 2.0. // -namespace SixLabors.ImageSharp.Benchmarks.Image +namespace SixLabors.ImageSharp.Benchmarks.Image.Jpeg { using System.Collections.Generic; - using System.IO; using BenchmarkDotNet.Attributes; - using ImageSharp.Formats; - using ImageSharp.Formats.Jpeg.GolangPort; - using ImageSharp.PixelFormats; - using SixLabors.ImageSharp.Formats.Jpeg; - using CoreImage = ImageSharp.Image; + using CoreImage = SixLabors.ImageSharp.Image; [Config(typeof(Config.Short))] public class DecodeJpegMultiple : MultiImageBenchmarkBase diff --git a/tests/ImageSharp.Benchmarks/Image/EncodeJpeg.cs b/tests/ImageSharp.Benchmarks/Image/Jpeg/EncodeJpeg.cs similarity index 94% rename from tests/ImageSharp.Benchmarks/Image/EncodeJpeg.cs rename to tests/ImageSharp.Benchmarks/Image/Jpeg/EncodeJpeg.cs index 48fd6e9e7..15861bd61 100644 --- a/tests/ImageSharp.Benchmarks/Image/EncodeJpeg.cs +++ b/tests/ImageSharp.Benchmarks/Image/Jpeg/EncodeJpeg.cs @@ -3,7 +3,7 @@ // Licensed under the Apache License, Version 2.0. // -namespace SixLabors.ImageSharp.Benchmarks.Image +namespace SixLabors.ImageSharp.Benchmarks.Image.Jpeg { using System.Drawing; using System.Drawing.Imaging; @@ -11,7 +11,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Image using BenchmarkDotNet.Attributes; - using CoreImage = ImageSharp.Image; + using CoreImage = SixLabors.ImageSharp.Image; public class EncodeJpeg : BenchmarkBase { diff --git a/tests/ImageSharp.Benchmarks/Image/EncodeJpegMultiple.cs b/tests/ImageSharp.Benchmarks/Image/Jpeg/EncodeJpegMultiple.cs similarity index 94% rename from tests/ImageSharp.Benchmarks/Image/EncodeJpegMultiple.cs rename to tests/ImageSharp.Benchmarks/Image/Jpeg/EncodeJpegMultiple.cs index efd69d329..27144ff6f 100644 --- a/tests/ImageSharp.Benchmarks/Image/EncodeJpegMultiple.cs +++ b/tests/ImageSharp.Benchmarks/Image/Jpeg/EncodeJpegMultiple.cs @@ -3,14 +3,13 @@ // Licensed under the Apache License, Version 2.0. // -namespace SixLabors.ImageSharp.Benchmarks.Image +namespace SixLabors.ImageSharp.Benchmarks.Image.Jpeg { using System.Collections.Generic; using System.Drawing.Imaging; using BenchmarkDotNet.Attributes; - using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Formats.Jpeg; [Config(typeof(Config.Short))] // It's long enough to iterate through multiple files diff --git a/tests/ImageSharp.Benchmarks/Image/Jpeg/YCbCrColorConversion.cs b/tests/ImageSharp.Benchmarks/Image/Jpeg/YCbCrColorConversion.cs new file mode 100644 index 000000000..b76a79588 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/Image/Jpeg/YCbCrColorConversion.cs @@ -0,0 +1,36 @@ +namespace SixLabors.ImageSharp.Benchmarks.Image.Jpeg +{ + using System; + + using SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder; + using SixLabors.ImageSharp.Memory; + + using JpegColorConverter = SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters.JpegColorConverter; + + public class YCbCrColorConversion + { + private static JpegColorConverter.ComponentValues CreateRandomValues( + int componentCount, + int inputBufferLength, + float minVal = 0f, + float maxVal = 255f) + { + var rnd = new Random(42); + Buffer2D[] buffers = new Buffer2D[componentCount]; + for (int i = 0; i < componentCount; i++) + { + float[] values = new float[inputBufferLength]; + + for (int j = 0; j < inputBufferLength; j++) + { + values[j] = (float)rnd.NextDouble() * (maxVal - minVal) + minVal; + } + + // no need to dispose when buffer is not array owner + buffers[i] = new Buffer2D(values, values.Length, 1); + } + return new JpegColorConverter.ComponentValues(buffers, 0); + } + + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs index 0197dd917..239d9d8d9 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs @@ -12,6 +12,8 @@ using Xunit.Abstractions; namespace SixLabors.ImageSharp.Tests.Formats.Jpg { + using SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters; + public class JpegColorConverterTests { private const float Precision = 0.1f / 255; @@ -68,9 +70,35 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg [MemberData(nameof(CommonConversionData))] public void FromYCbCrSimd(int inputBufferLength, int resultBufferLength, int seed) { - ValidateConversion(new JpegColorConverter.FromYCbCrSimd(), 3, inputBufferLength, resultBufferLength, seed, ValidateYCbCr); + ValidateConversion( + new JpegColorConverter.FromYCbCrSimd(), + 3, + inputBufferLength, + resultBufferLength, + seed, + ValidateYCbCr); + } + + [Theory] + [MemberData(nameof(CommonConversionData))] + public void FromYCbCrSimdAvx2(int inputBufferLength, int resultBufferLength, int seed) + { + if (!SimdUtils.IsAvx2CompatibleArchitecture) + { + this.Output.WriteLine("No AVX2 present, skipping test!"); + return; + } + + ValidateConversion( + new JpegColorConverter.FromYCbCrSimdAvx2(), + 3, + inputBufferLength, + resultBufferLength, + seed, + ValidateYCbCr); } + [Theory] [MemberData(nameof(CommonConversionData))] public void ConvertFromYCbCr_WithDefaultConverter(int inputBufferLength, int resultBufferLength, int seed) diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs index baa31f674..fc6124d12 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs @@ -34,8 +34,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg TestImages.Jpeg.Baseline.Jpeg444, }; - //[Theory] // Benchmark, enable manually - //[MemberData(nameof(DecodeJpegData))] + [Theory] // Benchmark, enable manually + [MemberData(nameof(DecodeJpegData))] public void DecodeJpeg_Original(string fileName) { this.DecodeJpegBenchmarkImpl(fileName, new OrigJpegDecoder()); @@ -50,6 +50,12 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg private void DecodeJpegBenchmarkImpl(string fileName, IImageDecoder decoder) { + // do not run this on CI even by accident + if (TestEnvironment.RunsOnCI) + { + return; + } + const int ExecutionCount = 30; if (!Vector.IsHardwareAccelerated) @@ -78,6 +84,12 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg // [InlineData(30, 100, JpegSubsample.Ratio444)] public void EncodeJpeg(int executionCount, int quality, JpegSubsample subsample) { + // do not run this on CI even by accident + if (TestEnvironment.RunsOnCI) + { + return; + } + string[] testFiles = TestImages.Bmp.All .Concat(new[] { TestImages.Jpeg.Baseline.Calliphora, TestImages.Jpeg.Baseline.Cmyk }) .ToArray();