Browse Source

JpegColorConverter.FromYCbCrSimdAvx2 works!

af/merge-core
Anton Firszov 9 years ago
parent
commit
134fa595ed
  1. 5
      src/ImageSharp/Common/Tuples/Vector4Pair.cs
  2. 3
      src/ImageSharp/Formats/Jpeg/Common/Block8x8.cs
  3. 5
      src/ImageSharp/Formats/Jpeg/Common/Block8x8F.CopyTo.cs
  4. 5
      src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromCmyk.cs
  5. 5
      src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromGrayScale.cs
  6. 5
      src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromRgb.cs
  7. 5
      src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromYCbCrBasic.cs
  8. 5
      src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimd.cs
  9. 35
      src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimdAvx2.cs
  10. 7
      src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromYccK.cs
  11. 11
      src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.cs
  12. 3
      src/ImageSharp/Formats/Jpeg/Common/SizeExtensions.cs
  13. 2
      tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs
  14. 4
      tests/ImageSharp.Benchmarks/Config.cs
  15. 2
      tests/ImageSharp.Benchmarks/General/ArrayCopy.cs
  16. 2
      tests/ImageSharp.Benchmarks/Image/EncodeBmpMultiple.cs
  17. 2
      tests/ImageSharp.Benchmarks/Image/Jpeg/DecodeJpeg.cs
  18. 2
      tests/ImageSharp.Benchmarks/Image/Jpeg/DecodeJpegMultiple.cs
  19. 2
      tests/ImageSharp.Benchmarks/Image/Jpeg/EncodeJpegMultiple.cs
  20. 62
      tests/ImageSharp.Benchmarks/Image/Jpeg/YCbCrColorConversion.cs
  21. 2
      tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs

5
src/ImageSharp/Common/Tuples/Vector4Pair.cs

@ -71,5 +71,10 @@ namespace SixLabors.ImageSharp.Common.Tuples
v *= new Vector<float>(1 / 255f); v *= new Vector<float>(1 / 255f);
self = v; self = v;
} }
public override string ToString()
{
return $"{this.A}, {this.B}";
}
} }
} }

3
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;
using System.Diagnostics; using System.Diagnostics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;

5
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 System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Memory;

5
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; using System.Numerics;
namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters

5
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; using System.Numerics;
namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters

5
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; using System.Numerics;
namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters

5
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; using System.Numerics;
namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters

5
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.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Common.Tuples; using SixLabors.ImageSharp.Common.Tuples;

35
src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromYCbCr.cs → 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.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Common.Tuples; using SixLabors.ImageSharp.Common.Tuples;
// ReSharper disable ImpureMethodCallOnReadonlyValueField
namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters
{ {
internal abstract partial class JpegColorConverter internal abstract partial class JpegColorConverter
@ -14,7 +18,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters
{ {
} }
public static bool IsAvailable => Vector.IsHardwareAccelerated && Vector<float>.Count == 8; public static bool IsAvailable => Vector.IsHardwareAccelerated && SimdUtils.IsAvx2CompatibleArchitecture;
public override void ConvertToRGBA(ComponentValues values, Span<Vector4> result) public override void ConvertToRGBA(ComponentValues values, Span<Vector4> result)
{ {
@ -56,6 +60,16 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters
// Walking 8 elements at one step: // Walking 8 elements at one step:
int n = result.Length / 8; int n = result.Length / 8;
var rr = default(Vector4Pair);
var gg = default(Vector4Pair);
var bb = default(Vector4Pair);
ref Vector<float> rrRefAsVector = ref Unsafe.As<Vector4Pair, Vector<float>>(ref rr);
ref Vector<float> ggRefAsVector = ref Unsafe.As<Vector4Pair, Vector<float>>(ref gg);
ref Vector<float> bbRefAsVector = ref Unsafe.As<Vector4Pair, Vector<float>>(ref bb);
var scale = new Vector<float>(1 / 255f);
for (int i = 0; i < n; i++) for (int i = 0; i < n; i++)
{ {
// y = yVals[i]; // y = yVals[i];
@ -73,15 +87,16 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters
Vector<float> g = y - (cb * new Vector<float>(0.344136F)) - (cr * new Vector<float>(0.714136F)); Vector<float> g = y - (cb * new Vector<float>(0.344136F)) - (cr * new Vector<float>(0.714136F));
Vector<float> b = y + (cb * new Vector<float>(1.772F)); Vector<float> b = y + (cb * new Vector<float>(1.772F));
// Vector<float> has no .Clamp(), need to switch to Vector4 for the next operation: r = r.FastRound();
// TODO: Is it worth to use Vector<float> at all? g = g.FastRound();
Vector4Pair rr = Unsafe.As<Vector<float>, Vector4Pair>(ref r); b = b.FastRound();
Vector4Pair gg = Unsafe.As<Vector<float>, Vector4Pair>(ref g); r *= scale;
Vector4Pair bb = Unsafe.As<Vector<float>, Vector4Pair>(ref b); g *= scale;
b *= scale;
rr.RoundAndDownscaleAvx2(); rrRefAsVector = r;
gg.RoundAndDownscaleAvx2(); ggRefAsVector = g;
bb.RoundAndDownscaleAvx2(); 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: // 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); ref Vector4Octet destination = ref Unsafe.Add(ref resultBase, i);

7
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; using System.Numerics;
namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters
{ {
internal abstract partial class JpegColorConverter internal abstract partial class JpegColorConverter
{ {
internal class FromYccK : ColorConverters.JpegColorConverter internal class FromYccK : JpegColorConverter
{ {
public FromYccK() public FromYccK()
: base(JpegColorSpace.Ycck) : base(JpegColorSpace.Ycck)

11
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;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@ -17,7 +20,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters
/// </summary> /// </summary>
private static readonly JpegColorConverter[] Converters = private static readonly JpegColorConverter[] Converters =
{ {
new FromYCbCrSimd(), new FromYccK(), new FromCmyk(), new FromGrayScale(), new FromRgb() GetYCbCrConverter(), new FromYccK(), new FromCmyk(), new FromGrayScale(), new FromRgb()
}; };
/// <summary> /// <summary>
@ -54,6 +57,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters
/// <param name="result">The destination buffer of <see cref="Vector4"/> values</param> /// <param name="result">The destination buffer of <see cref="Vector4"/> values</param>
public abstract void ConvertToRGBA(ComponentValues values, Span<Vector4> result); public abstract void ConvertToRGBA(ComponentValues values, Span<Vector4> result);
/// <summary>
/// Returns the <see cref="JpegColorConverter"/> for the YCbCr colorspace that matches the current CPU architecture.
/// </summary>
private static JpegColorConverter GetYCbCrConverter() =>
FromYCbCrSimdAvx2.IsAvailable ? (JpegColorConverter)new FromYCbCrSimdAvx2() : new FromYCbCrSimd();
/// <summary> /// <summary>
/// A stack-only struct to reference the input buffers using <see cref="ReadOnlySpan{T}"/>-s. /// A stack-only struct to reference the input buffers using <see cref="ReadOnlySpan{T}"/>-s.
/// </summary> /// </summary>

3
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 System.Numerics;
using SixLabors.Primitives; using SixLabors.Primitives;

2
tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs

@ -8,7 +8,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Color.Bulk
using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
[Config(typeof(Config.Short))] [Config(typeof(Config.ShortClr))]
public abstract class PackFromVector4<TPixel> public abstract class PackFromVector4<TPixel>
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {

4
tests/ImageSharp.Benchmarks/Config.cs

@ -17,9 +17,9 @@ namespace SixLabors.ImageSharp.Benchmarks
this.Add(new BenchmarkDotNet.Diagnosers.MemoryDiagnoser()); this.Add(new BenchmarkDotNet.Diagnosers.MemoryDiagnoser());
} }
public class Short : Config public class ShortClr : Config
{ {
public Short() public ShortClr()
{ {
this.Add( this.Add(
Job.Clr.WithLaunchCount(1) Job.Clr.WithLaunchCount(1)

2
tests/ImageSharp.Benchmarks/General/ArrayCopy.cs

@ -10,7 +10,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General
using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Attributes;
[Config(typeof(Config.Short))] [Config(typeof(Config.ShortClr))]
public class ArrayCopy public class ArrayCopy
{ {
[Params(10, 100, 1000, 10000)] [Params(10, 100, 1000, 10000)]

2
tests/ImageSharp.Benchmarks/Image/EncodeBmpMultiple.cs

@ -13,7 +13,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Image
using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Formats.Bmp; using SixLabors.ImageSharp.Formats.Bmp;
[Config(typeof(Config.Short))] [Config(typeof(Config.ShortClr))]
public class EncodeBmpMultiple : MultiImageBenchmarkBase.WithImagesPreloaded public class EncodeBmpMultiple : MultiImageBenchmarkBase.WithImagesPreloaded
{ {
protected override IEnumerable<string> InputImageSubfoldersOrFiles => new[] { "Bmp/", "Jpg/baseline" }; protected override IEnumerable<string> InputImageSubfoldersOrFiles => new[] { "Bmp/", "Jpg/baseline" };

2
tests/ImageSharp.Benchmarks/Image/Jpeg/DecodeJpeg.cs

@ -18,7 +18,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Image.Jpeg
using CoreSize = SixLabors.Primitives.Size; using CoreSize = SixLabors.Primitives.Size;
[Config(typeof(Config.Short))] [Config(typeof(Config.ShortClr))]
public class DecodeJpeg : BenchmarkBase public class DecodeJpeg : BenchmarkBase
{ {
private byte[] jpegBytes; private byte[] jpegBytes;

2
tests/ImageSharp.Benchmarks/Image/Jpeg/DecodeJpegMultiple.cs

@ -11,7 +11,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Image.Jpeg
using CoreImage = SixLabors.ImageSharp.Image; using CoreImage = SixLabors.ImageSharp.Image;
[Config(typeof(Config.Short))] [Config(typeof(Config.ShortClr))]
public class DecodeJpegMultiple : MultiImageBenchmarkBase public class DecodeJpegMultiple : MultiImageBenchmarkBase
{ {
protected override IEnumerable<string> InputImageSubfoldersOrFiles => new[] protected override IEnumerable<string> InputImageSubfoldersOrFiles => new[]

2
tests/ImageSharp.Benchmarks/Image/Jpeg/EncodeJpegMultiple.cs

@ -12,7 +12,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Image.Jpeg
using SixLabors.ImageSharp.Formats.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 public class EncodeJpegMultiple : MultiImageBenchmarkBase.WithImagesPreloaded
{ {
protected override IEnumerable<string> InputImageSubfoldersOrFiles => new[] { "Bmp/", "Jpg/baseline" }; protected override IEnumerable<string> InputImageSubfoldersOrFiles => new[] { "Bmp/", "Jpg/baseline" };

62
tests/ImageSharp.Benchmarks/Image/Jpeg/YCbCrColorConversion.cs

@ -1,15 +1,64 @@
namespace SixLabors.ImageSharp.Benchmarks.Image.Jpeg namespace SixLabors.ImageSharp.Benchmarks.Image.Jpeg
{ {
using System; using System;
using System.Numerics;
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder; using SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder;
using SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters;
using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Memory;
using JpegColorConverter = SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters.JpegColorConverter; [Config(typeof(Config.ShortClr))]
public class YCbCrColorConversion public class YCbCrColorConversion
{ {
private static JpegColorConverter.ComponentValues CreateRandomValues( private Buffer2D<float>[] 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<float> 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<float>[] CreateRandomValues(
int componentCount, int componentCount,
int inputBufferLength, int inputBufferLength,
float minVal = 0f, float minVal = 0f,
@ -29,8 +78,9 @@
// no need to dispose when buffer is not array owner // no need to dispose when buffer is not array owner
buffers[i] = new Buffer2D<float>(values, values.Length, 1); buffers[i] = new Buffer2D<float>(values, values.Length, 1);
} }
return new JpegColorConverter.ComponentValues(buffers, 0);
}
return buffers;
}
} }
} }

2
tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs

@ -89,6 +89,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
return; return;
} }
//JpegColorConverter.FromYCbCrSimdAvx2.LogPlz = s => this.Output.WriteLine(s);
ValidateConversion( ValidateConversion(
new JpegColorConverter.FromYCbCrSimdAvx2(), new JpegColorConverter.FromYCbCrSimdAvx2(),
3, 3,

Loading…
Cancel
Save