mirror of https://github.com/SixLabors/ImageSharp
35 changed files with 432 additions and 563 deletions
@ -1,18 +0,0 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters |
|||
{ |
|||
internal abstract partial class JpegColorConverter |
|||
{ |
|||
internal abstract class Avx2JpegColorConverter : VectorizedJpegColorConverter |
|||
{ |
|||
protected Avx2JpegColorConverter(JpegColorSpace colorSpace, int precision) |
|||
: base(colorSpace, precision, 8) |
|||
{ |
|||
} |
|||
|
|||
protected sealed override bool IsAvailable => SimdUtils.HasAvx2; |
|||
} |
|||
} |
|||
} |
|||
@ -1,18 +0,0 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters |
|||
{ |
|||
internal abstract partial class JpegColorConverter |
|||
{ |
|||
internal abstract class BasicJpegColorConverter : JpegColorConverter |
|||
{ |
|||
protected BasicJpegColorConverter(JpegColorSpace colorSpace, int precision) |
|||
: base(colorSpace, precision) |
|||
{ |
|||
} |
|||
|
|||
protected override bool IsAvailable => true; |
|||
} |
|||
} |
|||
} |
|||
@ -1,16 +1,15 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.Numerics; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters |
|||
{ |
|||
internal abstract partial class JpegColorConverter |
|||
internal abstract partial class JpegColorConverterBase |
|||
{ |
|||
internal sealed class FromCmykBasic : BasicJpegColorConverter |
|||
internal sealed class FromCmykScalar : ScalarJpegColorConverter |
|||
{ |
|||
public FromCmykBasic(int precision) |
|||
public FromCmykScalar(int precision) |
|||
: base(JpegColorSpace.Cmyk, precision) |
|||
{ |
|||
} |
|||
@ -1,53 +0,0 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.Numerics; |
|||
using System.Runtime.CompilerServices; |
|||
using System.Runtime.InteropServices; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters |
|||
{ |
|||
internal abstract partial class JpegColorConverter |
|||
{ |
|||
internal sealed class FromGrayscaleBasic : BasicJpegColorConverter |
|||
{ |
|||
public FromGrayscaleBasic(int precision) |
|||
: base(JpegColorSpace.Grayscale, precision) |
|||
{ |
|||
} |
|||
|
|||
public override void ConvertToRgbInplace(in ComponentValues values) => |
|||
ScaleValues(values.Component0, this.MaximumValue); |
|||
|
|||
internal static void ScaleValues(Span<float> values, float maxValue) |
|||
{ |
|||
Span<Vector4> vecValues = MemoryMarshal.Cast<float, Vector4>(values); |
|||
|
|||
var scaleVector = new Vector4(1 / maxValue); |
|||
|
|||
for (int i = 0; i < vecValues.Length; i++) |
|||
{ |
|||
vecValues[i] *= scaleVector; |
|||
} |
|||
|
|||
values = values.Slice(vecValues.Length * 4); |
|||
if (!values.IsEmpty) |
|||
{ |
|||
float scaleValue = 1f / maxValue; |
|||
values[0] *= scaleValue; |
|||
|
|||
if ((uint)values.Length > 1) |
|||
{ |
|||
values[1] *= scaleValue; |
|||
|
|||
if ((uint)values.Length > 2) |
|||
{ |
|||
values[2] *= scaleValue; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,34 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.Runtime.CompilerServices; |
|||
using System.Runtime.InteropServices; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters |
|||
{ |
|||
internal abstract partial class JpegColorConverterBase |
|||
{ |
|||
internal sealed class FromGrayscaleScalar : ScalarJpegColorConverter |
|||
{ |
|||
public FromGrayscaleScalar(int precision) |
|||
: base(JpegColorSpace.Grayscale, precision) |
|||
{ |
|||
} |
|||
|
|||
public override void ConvertToRgbInplace(in ComponentValues values) => |
|||
ConvertCoreInplace(values.Component0, this.MaximumValue); |
|||
|
|||
internal static void ConvertCoreInplace(Span<float> values, float maxValue) |
|||
{ |
|||
ref float valuesRef = ref MemoryMarshal.GetReference(values); |
|||
float scale = 1 / maxValue; |
|||
|
|||
for (nint i = 0; i < values.Length; i++) |
|||
{ |
|||
Unsafe.Add(ref valuesRef, i) *= scale; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,38 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System.Numerics; |
|||
using System.Runtime.CompilerServices; |
|||
using System.Runtime.InteropServices; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters |
|||
{ |
|||
internal abstract partial class JpegColorConverterBase |
|||
{ |
|||
internal sealed class FromGrayScaleVector8 : VectorizedJpegColorConverter |
|||
{ |
|||
public FromGrayScaleVector8(int precision) |
|||
: base(JpegColorSpace.Grayscale, precision) |
|||
{ |
|||
} |
|||
|
|||
protected override void ConvertCoreVectorizedInplace(in ComponentValues values) |
|||
{ |
|||
ref Vector<float> cBase = |
|||
ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(values.Component0)); |
|||
|
|||
var scale = new Vector<float>(1 / this.MaximumValue); |
|||
|
|||
nint n = values.Component0.Length / 8; |
|||
for (nint i = 0; i < n; i++) |
|||
{ |
|||
ref Vector<float> c0 = ref Unsafe.Add(ref cBase, i); |
|||
c0 *= scale; |
|||
} |
|||
} |
|||
|
|||
protected override void ConvertCoreInplace(in ComponentValues values) => |
|||
FromGrayscaleScalar.ConvertCoreInplace(values.Component0, this.MaximumValue); |
|||
} |
|||
} |
|||
} |
|||
@ -1,32 +0,0 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.Numerics; |
|||
using System.Runtime.InteropServices; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters |
|||
{ |
|||
internal abstract partial class JpegColorConverter |
|||
{ |
|||
internal sealed class FromRgbBasic : BasicJpegColorConverter |
|||
{ |
|||
public FromRgbBasic(int precision) |
|||
: base(JpegColorSpace.RGB, precision) |
|||
{ |
|||
} |
|||
|
|||
public override void ConvertToRgbInplace(in ComponentValues values) |
|||
{ |
|||
ConvertCoreInplace(values, this.MaximumValue); |
|||
} |
|||
|
|||
internal static void ConvertCoreInplace(ComponentValues values, float maxValue) |
|||
{ |
|||
FromGrayscaleBasic.ScaleValues(values.Component0, maxValue); |
|||
FromGrayscaleBasic.ScaleValues(values.Component1, maxValue); |
|||
FromGrayscaleBasic.ScaleValues(values.Component2, maxValue); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,26 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters |
|||
{ |
|||
internal abstract partial class JpegColorConverterBase |
|||
{ |
|||
internal sealed class FromRgbScalar : ScalarJpegColorConverter |
|||
{ |
|||
public FromRgbScalar(int precision) |
|||
: base(JpegColorSpace.RGB, precision) |
|||
{ |
|||
} |
|||
|
|||
public override void ConvertToRgbInplace(in ComponentValues values) => |
|||
ConvertCoreInplace(values, this.MaximumValue); |
|||
|
|||
internal static void ConvertCoreInplace(ComponentValues values, float maxValue) |
|||
{ |
|||
FromGrayscaleScalar.ConvertCoreInplace(values.Component0, maxValue); |
|||
FromGrayscaleScalar.ConvertCoreInplace(values.Component1, maxValue); |
|||
FromGrayscaleScalar.ConvertCoreInplace(values.Component2, maxValue); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,42 +0,0 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.Numerics; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters |
|||
{ |
|||
internal abstract partial class JpegColorConverter |
|||
{ |
|||
internal sealed class FromYCbCrBasic : BasicJpegColorConverter |
|||
{ |
|||
public FromYCbCrBasic(int precision) |
|||
: base(JpegColorSpace.YCbCr, precision) |
|||
{ |
|||
} |
|||
|
|||
public override void ConvertToRgbInplace(in ComponentValues values) |
|||
=> ConvertCoreInplace(values, this.MaximumValue, this.HalfValue); |
|||
|
|||
internal static void ConvertCoreInplace(in ComponentValues values, float maxValue, float halfValue) |
|||
{ |
|||
Span<float> c0 = values.Component0; |
|||
Span<float> c1 = values.Component1; |
|||
Span<float> c2 = values.Component2; |
|||
|
|||
var scale = 1 / maxValue; |
|||
|
|||
for (int i = 0; i < c0.Length; i++) |
|||
{ |
|||
float y = c0[i]; |
|||
float cb = c1[i] - halfValue; |
|||
float cr = c2[i] - halfValue; |
|||
|
|||
c0[i] = MathF.Round(y + (1.402F * cr), MidpointRounding.AwayFromZero) * scale; |
|||
c1[i] = MathF.Round(y - (0.344136F * cb) - (0.714136F * cr), MidpointRounding.AwayFromZero) * scale; |
|||
c2[i] = MathF.Round(y + (1.772F * cb), MidpointRounding.AwayFromZero) * scale; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,50 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters |
|||
{ |
|||
internal abstract partial class JpegColorConverterBase |
|||
{ |
|||
internal sealed class FromYCbCrScalar : ScalarJpegColorConverter |
|||
{ |
|||
// TODO: comments, derived from ITU-T Rec. T.871
|
|||
internal const float RCrMult = 1.402f; |
|||
internal const float GCbMult = (float)(0.114 * 1.772 / 0.587); |
|||
internal const float GCrMult = (float)(0.299 * 1.402 / 0.587); |
|||
internal const float BCbMult = 1.772f; |
|||
|
|||
public FromYCbCrScalar(int precision) |
|||
: base(JpegColorSpace.YCbCr, precision) |
|||
{ |
|||
} |
|||
|
|||
public override void ConvertToRgbInplace(in ComponentValues values) |
|||
=> ConvertCoreInplace(values, this.MaximumValue, this.HalfValue); |
|||
|
|||
internal static void ConvertCoreInplace(in ComponentValues values, float maxValue, float halfValue) |
|||
{ |
|||
Span<float> c0 = values.Component0; |
|||
Span<float> c1 = values.Component1; |
|||
Span<float> c2 = values.Component2; |
|||
|
|||
float scale = 1 / maxValue; |
|||
|
|||
for (int i = 0; i < c0.Length; i++) |
|||
{ |
|||
float y = c0[i]; |
|||
float cb = c1[i] - halfValue; |
|||
float cr = c2[i] - halfValue; |
|||
|
|||
// r = y + (1.402F * cr);
|
|||
// g = y - (0.344136F * cb) - (0.714136F * cr);
|
|||
// b = y + (1.772F * cb);
|
|||
c0[i] = MathF.Round(y + (RCrMult * cr), MidpointRounding.AwayFromZero) * scale; |
|||
c1[i] = MathF.Round(y - (GCbMult * cb) - (GCrMult * cr), MidpointRounding.AwayFromZero) * scale; |
|||
c2[i] = MathF.Round(y + (BCbMult * cb), MidpointRounding.AwayFromZero) * scale; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,88 +0,0 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.Numerics; |
|||
using System.Runtime.CompilerServices; |
|||
using System.Runtime.InteropServices; |
|||
using SixLabors.ImageSharp.Tuples; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters |
|||
{ |
|||
internal abstract partial class JpegColorConverter |
|||
{ |
|||
internal sealed class FromYCbCrVector4 : VectorizedJpegColorConverter |
|||
{ |
|||
public FromYCbCrVector4(int precision) |
|||
: base(JpegColorSpace.YCbCr, precision, 8) |
|||
{ |
|||
} |
|||
|
|||
protected override bool IsAvailable => SimdUtils.HasVector4; |
|||
|
|||
protected override void ConvertCoreVectorizedInplace(in ComponentValues values) |
|||
{ |
|||
DebugGuard.IsTrue(values.Component0.Length % 8 == 0, nameof(values), "Length should be divisible by 8!"); |
|||
|
|||
ref Vector4Pair c0Base = |
|||
ref Unsafe.As<float, Vector4Pair>(ref MemoryMarshal.GetReference(values.Component0)); |
|||
ref Vector4Pair c1Base = |
|||
ref Unsafe.As<float, Vector4Pair>(ref MemoryMarshal.GetReference(values.Component1)); |
|||
ref Vector4Pair c2Base = |
|||
ref Unsafe.As<float, Vector4Pair>(ref MemoryMarshal.GetReference(values.Component2)); |
|||
|
|||
var chromaOffset = new Vector4(-this.HalfValue); |
|||
var maxValue = this.MaximumValue; |
|||
|
|||
// Walking 8 elements at one step:
|
|||
nint n = values.Component0.Length / 8; |
|||
|
|||
for (nint i = 0; i < n; i++) |
|||
{ |
|||
// y = yVals[i];
|
|||
ref Vector4Pair c0 = ref Unsafe.Add(ref c0Base, i); |
|||
|
|||
// cb = cbVals[i] - halfValue);
|
|||
ref Vector4Pair c1 = ref Unsafe.Add(ref c1Base, i); |
|||
c1.AddInplace(chromaOffset); |
|||
|
|||
// cr = crVals[i] - halfValue;
|
|||
ref Vector4Pair c2 = ref Unsafe.Add(ref c2Base, i); |
|||
c2.AddInplace(chromaOffset); |
|||
|
|||
// r = y + (1.402F * cr);
|
|||
Vector4Pair r = c0; |
|||
Vector4Pair tmp = c2; |
|||
tmp.MultiplyInplace(1.402F); |
|||
r.AddInplace(ref tmp); |
|||
|
|||
// g = y - (0.344136F * cb) - (0.714136F * cr);
|
|||
Vector4Pair g = c0; |
|||
tmp = c1; |
|||
tmp.MultiplyInplace(-0.344136F); |
|||
g.AddInplace(ref tmp); |
|||
tmp = c2; |
|||
tmp.MultiplyInplace(-0.714136F); |
|||
g.AddInplace(ref tmp); |
|||
|
|||
// b = y + (1.772F * cb);
|
|||
Vector4Pair b = c0; |
|||
tmp = c1; |
|||
tmp.MultiplyInplace(1.772F); |
|||
b.AddInplace(ref tmp); |
|||
|
|||
r.RoundAndDownscalePreVector8(maxValue); |
|||
g.RoundAndDownscalePreVector8(maxValue); |
|||
b.RoundAndDownscalePreVector8(maxValue); |
|||
|
|||
c0 = r; |
|||
c1 = g; |
|||
c2 = b; |
|||
} |
|||
} |
|||
|
|||
protected override void ConvertCoreInplace(in ComponentValues values) |
|||
=> FromYCbCrBasic.ConvertCoreInplace(values, this.MaximumValue, this.HalfValue); |
|||
} |
|||
} |
|||
} |
|||
@ -1,18 +0,0 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters |
|||
{ |
|||
internal abstract partial class JpegColorConverter |
|||
{ |
|||
internal abstract class Vector8JpegColorConverter : VectorizedJpegColorConverter |
|||
{ |
|||
protected Vector8JpegColorConverter(JpegColorSpace colorSpace, int precision) |
|||
: base(colorSpace, precision, 8) |
|||
{ |
|||
} |
|||
|
|||
protected sealed override bool IsAvailable => SimdUtils.HasVector8; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,32 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
#if SUPPORTS_RUNTIME_INTRINSICS
|
|||
using System.Runtime.Intrinsics.X86; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters |
|||
{ |
|||
internal abstract partial class JpegColorConverterBase |
|||
{ |
|||
/// <summary>
|
|||
/// <see cref="JpegColorConverterBase"/> abstract base for implementations
|
|||
/// based on <see cref="Avx"/> instructions.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// Converters of this family would expect input buffers lengths to be
|
|||
/// divisible by 8 without a remainder.
|
|||
/// This is guaranteed by real-life data as jpeg stores pixels via 8x8 blocks.
|
|||
/// DO NOT pass test data of invalid size to these converters as they
|
|||
/// potentially won't do a bound check and return a false positive result.
|
|||
/// </remarks>
|
|||
internal abstract class AvxColorConverter : JpegColorConverterBase |
|||
{ |
|||
protected AvxColorConverter(JpegColorSpace colorSpace, int precision) |
|||
: base(colorSpace, precision) |
|||
{ |
|||
} |
|||
|
|||
protected override bool IsAvailable => Avx.IsSupported; |
|||
} |
|||
} |
|||
} |
|||
#endif
|
|||
@ -0,0 +1,22 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters |
|||
{ |
|||
internal abstract partial class JpegColorConverterBase |
|||
{ |
|||
/// <summary>
|
|||
/// <see cref="JpegColorConverterBase"/> abstract base for implementations
|
|||
/// based on scalar instructions.
|
|||
/// </summary>
|
|||
internal abstract class ScalarJpegColorConverter : JpegColorConverterBase |
|||
{ |
|||
protected ScalarJpegColorConverter(JpegColorSpace colorSpace, int precision) |
|||
: base(colorSpace, precision) |
|||
{ |
|||
} |
|||
|
|||
protected override bool IsAvailable => true; |
|||
} |
|||
} |
|||
} |
|||
@ -1,27 +1,36 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.Numerics; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters |
|||
{ |
|||
internal abstract partial class JpegColorConverter |
|||
internal abstract partial class JpegColorConverterBase |
|||
{ |
|||
internal abstract class VectorizedJpegColorConverter : JpegColorConverter |
|||
/// <summary>
|
|||
/// <see cref="JpegColorConverterBase"/> abstract base for implementations
|
|||
/// based on <see cref="System.Numerics.Vector"/> API.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// Converters of this family can work with data of any size.
|
|||
/// Even though real life data is guaranteed to be of size
|
|||
/// divisible by 8 newer SIMD instructions like AVX512 won't work with
|
|||
/// such data out of the box. These converters have fallback code
|
|||
/// for 'remainder' data.
|
|||
/// </remarks>
|
|||
internal abstract class VectorizedJpegColorConverter : JpegColorConverterBase |
|||
{ |
|||
private readonly int vectorSize; |
|||
|
|||
protected VectorizedJpegColorConverter(JpegColorSpace colorSpace, int precision, int vectorSize) |
|||
protected VectorizedJpegColorConverter(JpegColorSpace colorSpace, int precision) |
|||
: base(colorSpace, precision) |
|||
{ |
|||
this.vectorSize = vectorSize; |
|||
} |
|||
|
|||
protected sealed override bool IsAvailable => SimdUtils.HasVector8; |
|||
|
|||
public override void ConvertToRgbInplace(in ComponentValues values) |
|||
{ |
|||
int length = values.Component0.Length; |
|||
int remainder = values.Component0.Length % this.vectorSize; |
|||
int remainder = values.Component0.Length % 8; |
|||
int simdCount = length - remainder; |
|||
if (simdCount > 0) |
|||
{ |
|||
Loading…
Reference in new issue