From acf5aed3edcda47dc92df1ad2e0582576d52cd2d Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Wed, 20 Sep 2017 01:53:59 +0200 Subject: [PATCH 1/5] organizing color converster code --- .../JpegColorConverter.FromCmyk.cs | 4 +- .../JpegColorConverter.FromGrayScale.cs | 4 +- .../JpegColorConverter.FromRgb.cs | 4 +- .../JpegColorConverter.FromYCbCr.cs | 93 ++++++++++++++++++ .../JpegColorConverter.FromYCbCrBasic.cs | 48 ++++++++++ .../JpegColorConverter.FromYCbCrSimd.cs} | 96 +------------------ .../JpegColorConverter.FromYccK.cs | 4 +- .../JpegColorConverter.cs | 61 +++++++++++- .../Common/Decoder/JpegImagePostProcessor.cs | 8 +- .../Image/{ => Jpeg}/DecodeJpeg.cs | 5 +- .../Image/{ => Jpeg}/DecodeJpegMultiple.cs | 9 +- .../Image/{ => Jpeg}/EncodeJpeg.cs | 4 +- .../Image/{ => Jpeg}/EncodeJpegMultiple.cs | 3 +- .../Image/Jpeg/YCbCrColorConversion.cs | 36 +++++++ .../Formats/Jpg/JpegColorConverterTests.cs | 30 +++++- .../Formats/Jpg/JpegProfilingBenchmarks.cs | 16 +++- 16 files changed, 299 insertions(+), 126 deletions(-) rename src/ImageSharp/Formats/Jpeg/Common/Decoder/{ => ColorConverters}/JpegColorConverter.FromCmyk.cs (89%) rename src/ImageSharp/Formats/Jpeg/Common/Decoder/{ => ColorConverters}/JpegColorConverter.FromGrayScale.cs (86%) rename src/ImageSharp/Formats/Jpeg/Common/Decoder/{ => ColorConverters}/JpegColorConverter.FromRgb.cs (88%) create mode 100644 src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromYCbCr.cs create mode 100644 src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromYCbCrBasic.cs rename src/ImageSharp/Formats/Jpeg/Common/Decoder/{JpegColorConverter.FromYCbCr.cs => ColorConverters/JpegColorConverter.FromYCbCrSimd.cs} (57%) rename src/ImageSharp/Formats/Jpeg/Common/Decoder/{ => ColorConverters}/JpegColorConverter.FromYccK.cs (91%) rename src/ImageSharp/Formats/Jpeg/Common/Decoder/{ => ColorConverters}/JpegColorConverter.cs (73%) rename tests/ImageSharp.Benchmarks/Image/{ => Jpeg}/DecodeJpeg.cs (94%) rename tests/ImageSharp.Benchmarks/Image/{ => Jpeg}/DecodeJpegMultiple.cs (81%) rename tests/ImageSharp.Benchmarks/Image/{ => Jpeg}/EncodeJpeg.cs (94%) rename tests/ImageSharp.Benchmarks/Image/{ => Jpeg}/EncodeJpegMultiple.cs (94%) create mode 100644 tests/ImageSharp.Benchmarks/Image/Jpeg/YCbCrColorConversion.cs 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(); From 134fa595ed13eb0d2bef997236b6961edfa1425b Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Wed, 20 Sep 2017 02:48:39 +0200 Subject: [PATCH 2/5] JpegColorConverter.FromYCbCrSimdAvx2 works! --- src/ImageSharp/Common/Tuples/Vector4Pair.cs | 5 ++ .../Formats/Jpeg/Common/Block8x8.cs | 3 + .../Formats/Jpeg/Common/Block8x8F.CopyTo.cs | 5 +- .../JpegColorConverter.FromCmyk.cs | 5 +- .../JpegColorConverter.FromGrayScale.cs | 5 +- .../JpegColorConverter.FromRgb.cs | 5 +- .../JpegColorConverter.FromYCbCrBasic.cs | 5 +- .../JpegColorConverter.FromYCbCrSimd.cs | 5 +- ...> JpegColorConverter.FromYCbCrSimdAvx2.cs} | 35 ++++++++--- .../JpegColorConverter.FromYccK.cs | 7 ++- .../ColorConverters/JpegColorConverter.cs | 11 +++- .../Formats/Jpeg/Common/SizeExtensions.cs | 3 + .../Color/Bulk/PackFromVector4.cs | 2 +- tests/ImageSharp.Benchmarks/Config.cs | 4 +- .../General/ArrayCopy.cs | 2 +- .../Image/EncodeBmpMultiple.cs | 2 +- .../Image/Jpeg/DecodeJpeg.cs | 2 +- .../Image/Jpeg/DecodeJpegMultiple.cs | 2 +- .../Image/Jpeg/EncodeJpegMultiple.cs | 2 +- .../Image/Jpeg/YCbCrColorConversion.cs | 62 +++++++++++++++++-- .../Formats/Jpg/JpegColorConverterTests.cs | 2 + 21 files changed, 141 insertions(+), 33 deletions(-) rename src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/{JpegColorConverter.FromYCbCr.cs => JpegColorConverter.FromYCbCrSimdAvx2.cs} (77%) diff --git a/src/ImageSharp/Common/Tuples/Vector4Pair.cs b/src/ImageSharp/Common/Tuples/Vector4Pair.cs index 4f43c9811..309d5e2e5 100644 --- a/src/ImageSharp/Common/Tuples/Vector4Pair.cs +++ b/src/ImageSharp/Common/Tuples/Vector4Pair.cs @@ -71,5 +71,10 @@ namespace SixLabors.ImageSharp.Common.Tuples v *= new Vector(1 / 255f); self = v; } + + public override string ToString() + { + return $"{this.A}, {this.B}"; + } } } \ No newline at end of file diff --git a/src/ImageSharp/Formats/Jpeg/Common/Block8x8.cs b/src/ImageSharp/Formats/Jpeg/Common/Block8x8.cs index 96ed0a8c9..1066cfa80 100644 --- a/src/ImageSharp/Formats/Jpeg/Common/Block8x8.cs +++ b/src/ImageSharp/Formats/Jpeg/Common/Block8x8.cs @@ -1,3 +1,6 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + using System; using System.Diagnostics; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/Formats/Jpeg/Common/Block8x8F.CopyTo.cs b/src/ImageSharp/Formats/Jpeg/Common/Block8x8F.CopyTo.cs index c1c5cfcde..39a6bee2e 100644 --- a/src/ImageSharp/Formats/Jpeg/Common/Block8x8F.CopyTo.cs +++ b/src/ImageSharp/Formats/Jpeg/Common/Block8x8F.CopyTo.cs @@ -1,4 +1,7 @@ -using System.Numerics; +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Numerics; using System.Runtime.CompilerServices; using SixLabors.ImageSharp.Memory; diff --git a/src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromCmyk.cs b/src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromCmyk.cs index b67d73fd4..86d595784 100644 --- a/src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromCmyk.cs +++ b/src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromCmyk.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; using System.Numerics; namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters diff --git a/src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromGrayScale.cs b/src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromGrayScale.cs index ffc3f80df..5c720e61c 100644 --- a/src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromGrayScale.cs +++ b/src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromGrayScale.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; using System.Numerics; namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters diff --git a/src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromRgb.cs b/src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromRgb.cs index fb6bf91ff..7f01eedad 100644 --- a/src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromRgb.cs +++ b/src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromRgb.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; using System.Numerics; namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters diff --git a/src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromYCbCrBasic.cs b/src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromYCbCrBasic.cs index 88b190675..ddd2197d4 100644 --- a/src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromYCbCrBasic.cs +++ b/src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromYCbCrBasic.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; using System.Numerics; namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters diff --git a/src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimd.cs b/src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimd.cs index 9d985dca6..a7fc136af 100644 --- a/src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimd.cs +++ b/src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimd.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; using System.Numerics; using System.Runtime.CompilerServices; using SixLabors.ImageSharp.Common.Tuples; diff --git a/src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromYCbCr.cs b/src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimdAvx2.cs similarity index 77% rename from src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromYCbCr.cs rename to src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimdAvx2.cs index 7fa6c92e9..77e74c32b 100644 --- a/src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromYCbCr.cs +++ b/src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimdAvx2.cs @@ -1,8 +1,12 @@ -using System; +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; using System.Numerics; using System.Runtime.CompilerServices; using SixLabors.ImageSharp.Common.Tuples; +// ReSharper disable ImpureMethodCallOnReadonlyValueField namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters { internal abstract partial class JpegColorConverter @@ -14,7 +18,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters { } - public static bool IsAvailable => Vector.IsHardwareAccelerated && Vector.Count == 8; + public static bool IsAvailable => Vector.IsHardwareAccelerated && SimdUtils.IsAvx2CompatibleArchitecture; public override void ConvertToRGBA(ComponentValues values, Span result) { @@ -56,6 +60,16 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters // Walking 8 elements at one step: int n = result.Length / 8; + var rr = default(Vector4Pair); + var gg = default(Vector4Pair); + var bb = default(Vector4Pair); + + ref Vector rrRefAsVector = ref Unsafe.As>(ref rr); + ref Vector ggRefAsVector = ref Unsafe.As>(ref gg); + ref Vector bbRefAsVector = ref Unsafe.As>(ref bb); + + var scale = new Vector(1 / 255f); + for (int i = 0; i < n; i++) { // y = yVals[i]; @@ -73,15 +87,16 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters 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); + r = r.FastRound(); + g = g.FastRound(); + b = b.FastRound(); + r *= scale; + g *= scale; + b *= scale; - rr.RoundAndDownscaleAvx2(); - gg.RoundAndDownscaleAvx2(); - bb.RoundAndDownscaleAvx2(); + rrRefAsVector = r; + ggRefAsVector = g; + bbRefAsVector = b; // 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); diff --git a/src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromYccK.cs b/src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromYccK.cs index 22e524c70..6d8e6ef5a 100644 --- a/src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromYccK.cs +++ b/src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromYccK.cs @@ -1,11 +1,14 @@ -using System; +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; using System.Numerics; namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters { internal abstract partial class JpegColorConverter { - internal class FromYccK : ColorConverters.JpegColorConverter + internal class FromYccK : JpegColorConverter { public FromYccK() : base(JpegColorSpace.Ycck) diff --git a/src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.cs b/src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.cs index 0bdb8ff7b..e0abc3215 100644 --- a/src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.cs +++ b/src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.cs @@ -1,3 +1,6 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + using System; using System.Collections.Generic; using System.Linq; @@ -17,7 +20,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters /// private static readonly JpegColorConverter[] Converters = { - new FromYCbCrSimd(), new FromYccK(), new FromCmyk(), new FromGrayScale(), new FromRgb() + GetYCbCrConverter(), new FromYccK(), new FromCmyk(), new FromGrayScale(), new FromRgb() }; /// @@ -54,6 +57,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters /// The destination buffer of values public abstract void ConvertToRGBA(ComponentValues values, Span result); + /// + /// Returns the for the YCbCr colorspace that matches the current CPU architecture. + /// + private static JpegColorConverter GetYCbCrConverter() => + FromYCbCrSimdAvx2.IsAvailable ? (JpegColorConverter)new FromYCbCrSimdAvx2() : new FromYCbCrSimd(); + /// /// A stack-only struct to reference the input buffers using -s. /// diff --git a/src/ImageSharp/Formats/Jpeg/Common/SizeExtensions.cs b/src/ImageSharp/Formats/Jpeg/Common/SizeExtensions.cs index b9bfe425a..f6b02bbaf 100644 --- a/src/ImageSharp/Formats/Jpeg/Common/SizeExtensions.cs +++ b/src/ImageSharp/Formats/Jpeg/Common/SizeExtensions.cs @@ -1,3 +1,6 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + using System.Numerics; using SixLabors.Primitives; diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs index e88981959..83c2a2ee8 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs @@ -8,7 +8,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Color.Bulk using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; - [Config(typeof(Config.Short))] + [Config(typeof(Config.ShortClr))] public abstract class PackFromVector4 where TPixel : struct, IPixel { diff --git a/tests/ImageSharp.Benchmarks/Config.cs b/tests/ImageSharp.Benchmarks/Config.cs index 9577bebd3..17ce3a07d 100644 --- a/tests/ImageSharp.Benchmarks/Config.cs +++ b/tests/ImageSharp.Benchmarks/Config.cs @@ -17,9 +17,9 @@ namespace SixLabors.ImageSharp.Benchmarks this.Add(new BenchmarkDotNet.Diagnosers.MemoryDiagnoser()); } - public class Short : Config + public class ShortClr : Config { - public Short() + public ShortClr() { this.Add( Job.Clr.WithLaunchCount(1) diff --git a/tests/ImageSharp.Benchmarks/General/ArrayCopy.cs b/tests/ImageSharp.Benchmarks/General/ArrayCopy.cs index ddfa0f08b..ac6b3f93c 100644 --- a/tests/ImageSharp.Benchmarks/General/ArrayCopy.cs +++ b/tests/ImageSharp.Benchmarks/General/ArrayCopy.cs @@ -10,7 +10,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General using BenchmarkDotNet.Attributes; - [Config(typeof(Config.Short))] + [Config(typeof(Config.ShortClr))] public class ArrayCopy { [Params(10, 100, 1000, 10000)] diff --git a/tests/ImageSharp.Benchmarks/Image/EncodeBmpMultiple.cs b/tests/ImageSharp.Benchmarks/Image/EncodeBmpMultiple.cs index e83712ffc..c509d3555 100644 --- a/tests/ImageSharp.Benchmarks/Image/EncodeBmpMultiple.cs +++ b/tests/ImageSharp.Benchmarks/Image/EncodeBmpMultiple.cs @@ -13,7 +13,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Image using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Formats.Bmp; - [Config(typeof(Config.Short))] + [Config(typeof(Config.ShortClr))] public class EncodeBmpMultiple : MultiImageBenchmarkBase.WithImagesPreloaded { protected override IEnumerable InputImageSubfoldersOrFiles => new[] { "Bmp/", "Jpg/baseline" }; diff --git a/tests/ImageSharp.Benchmarks/Image/Jpeg/DecodeJpeg.cs b/tests/ImageSharp.Benchmarks/Image/Jpeg/DecodeJpeg.cs index 6d1354ca2..6cb5f8a21 100644 --- a/tests/ImageSharp.Benchmarks/Image/Jpeg/DecodeJpeg.cs +++ b/tests/ImageSharp.Benchmarks/Image/Jpeg/DecodeJpeg.cs @@ -18,7 +18,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Image.Jpeg using CoreSize = SixLabors.Primitives.Size; - [Config(typeof(Config.Short))] + [Config(typeof(Config.ShortClr))] public class DecodeJpeg : BenchmarkBase { private byte[] jpegBytes; diff --git a/tests/ImageSharp.Benchmarks/Image/Jpeg/DecodeJpegMultiple.cs b/tests/ImageSharp.Benchmarks/Image/Jpeg/DecodeJpegMultiple.cs index d5eb5a20c..bc60c5669 100644 --- a/tests/ImageSharp.Benchmarks/Image/Jpeg/DecodeJpegMultiple.cs +++ b/tests/ImageSharp.Benchmarks/Image/Jpeg/DecodeJpegMultiple.cs @@ -11,7 +11,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Image.Jpeg using CoreImage = SixLabors.ImageSharp.Image; - [Config(typeof(Config.Short))] + [Config(typeof(Config.ShortClr))] public class DecodeJpegMultiple : MultiImageBenchmarkBase { protected override IEnumerable InputImageSubfoldersOrFiles => new[] diff --git a/tests/ImageSharp.Benchmarks/Image/Jpeg/EncodeJpegMultiple.cs b/tests/ImageSharp.Benchmarks/Image/Jpeg/EncodeJpegMultiple.cs index 27144ff6f..4d28f5a19 100644 --- a/tests/ImageSharp.Benchmarks/Image/Jpeg/EncodeJpegMultiple.cs +++ b/tests/ImageSharp.Benchmarks/Image/Jpeg/EncodeJpegMultiple.cs @@ -12,7 +12,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Image.Jpeg using SixLabors.ImageSharp.Formats.Jpeg; - [Config(typeof(Config.Short))] // It's long enough to iterate through multiple files + [Config(typeof(Config.ShortClr))] // It's long enough to iterate through multiple files public class EncodeJpegMultiple : MultiImageBenchmarkBase.WithImagesPreloaded { protected override IEnumerable InputImageSubfoldersOrFiles => new[] { "Bmp/", "Jpg/baseline" }; diff --git a/tests/ImageSharp.Benchmarks/Image/Jpeg/YCbCrColorConversion.cs b/tests/ImageSharp.Benchmarks/Image/Jpeg/YCbCrColorConversion.cs index b76a79588..eced38803 100644 --- a/tests/ImageSharp.Benchmarks/Image/Jpeg/YCbCrColorConversion.cs +++ b/tests/ImageSharp.Benchmarks/Image/Jpeg/YCbCrColorConversion.cs @@ -1,15 +1,64 @@ namespace SixLabors.ImageSharp.Benchmarks.Image.Jpeg { using System; + using System.Numerics; + + using BenchmarkDotNet.Attributes; using SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder; + using SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters; using SixLabors.ImageSharp.Memory; - - using JpegColorConverter = SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters.JpegColorConverter; - + + [Config(typeof(Config.ShortClr))] public class YCbCrColorConversion { - private static JpegColorConverter.ComponentValues CreateRandomValues( + private Buffer2D[] input; + + private Vector4[] output; + + public const int Count = 64; + + [GlobalSetup] + public void Setup() + { + this.input = CreateRandomValues(3, Count); + this.output = new Vector4[Count]; + } + + [GlobalCleanup] + public void Cleanup() + { + foreach (Buffer2D buffer in this.input) + { + buffer.Dispose(); + } + } + + [Benchmark(Baseline = true)] + public void Scalar() + { + var values = new JpegColorConverter.ComponentValues(this.input, 0); + + JpegColorConverter.FromYCbCrBasic.ConvertCore(values, this.output); + } + + [Benchmark] + public void SimdVector4() + { + var values = new JpegColorConverter.ComponentValues(this.input, 0); + + JpegColorConverter.FromYCbCrSimd.ConvertCore(values, this.output); + } + + [Benchmark] + public void SimdAvx2() + { + var values = new JpegColorConverter.ComponentValues(this.input, 0); + + JpegColorConverter.FromYCbCrSimdAvx2.ConvertCore(values, this.output); + } + + private static Buffer2D[] CreateRandomValues( int componentCount, int inputBufferLength, float minVal = 0f, @@ -29,8 +78,9 @@ // no need to dispose when buffer is not array owner buffers[i] = new Buffer2D(values, values.Length, 1); } - return new JpegColorConverter.ComponentValues(buffers, 0); - } + return buffers; + } + } } \ 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 239d9d8d9..46f137f81 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs @@ -89,6 +89,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg return; } + //JpegColorConverter.FromYCbCrSimdAvx2.LogPlz = s => this.Output.WriteLine(s); + ValidateConversion( new JpegColorConverter.FromYCbCrSimdAvx2(), 3, From 4eeacb0e7dfcf38f48bad2feb8683e5bdf249df6 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Wed, 20 Sep 2017 03:27:23 +0200 Subject: [PATCH 3/5] benchmark 128 elements --- .../ImageSharp.Benchmarks/Image/Jpeg/YCbCrColorConversion.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/ImageSharp.Benchmarks/Image/Jpeg/YCbCrColorConversion.cs b/tests/ImageSharp.Benchmarks/Image/Jpeg/YCbCrColorConversion.cs index eced38803..33f380759 100644 --- a/tests/ImageSharp.Benchmarks/Image/Jpeg/YCbCrColorConversion.cs +++ b/tests/ImageSharp.Benchmarks/Image/Jpeg/YCbCrColorConversion.cs @@ -16,7 +16,7 @@ private Vector4[] output; - public const int Count = 64; + public const int Count = 128; [GlobalSetup] public void Setup() @@ -55,7 +55,7 @@ { var values = new JpegColorConverter.ComponentValues(this.input, 0); - JpegColorConverter.FromYCbCrSimdAvx2.ConvertCore(values, this.output); + JpegColorConverter.FromYCbCrSimdAvx2.ConvertCore16(values, this.output); } private static Buffer2D[] CreateRandomValues( From c9dd2d5f1457c0ed3fe38bc8bec0f271ab9776b2 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Wed, 20 Sep 2017 03:28:34 +0200 Subject: [PATCH 4/5] build fix --- tests/ImageSharp.Benchmarks/Image/Jpeg/YCbCrColorConversion.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ImageSharp.Benchmarks/Image/Jpeg/YCbCrColorConversion.cs b/tests/ImageSharp.Benchmarks/Image/Jpeg/YCbCrColorConversion.cs index 33f380759..93420aacf 100644 --- a/tests/ImageSharp.Benchmarks/Image/Jpeg/YCbCrColorConversion.cs +++ b/tests/ImageSharp.Benchmarks/Image/Jpeg/YCbCrColorConversion.cs @@ -55,7 +55,7 @@ { var values = new JpegColorConverter.ComponentValues(this.input, 0); - JpegColorConverter.FromYCbCrSimdAvx2.ConvertCore16(values, this.output); + JpegColorConverter.FromYCbCrSimdAvx2.ConvertCore(values, this.output); } private static Buffer2D[] CreateRandomValues( From b99967fac21cddb9b3882890410092f3ad4fe472 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Thu, 21 Sep 2017 02:44:48 +0200 Subject: [PATCH 5/5] comment out the profiling benchmark --- tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs index fc6124d12..6652db577 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());