Skip to content

Commit

Permalink
Merge pull request #784 from feliwir/jpeg-12bit
Browse files Browse the repository at this point in the history
Jpeg 12 bit support
  • Loading branch information
JimBobSquarePants authored Dec 30, 2018
2 parents abaf558 + 537dbcf commit db0fc0d
Show file tree
Hide file tree
Showing 25 changed files with 202 additions and 123 deletions.
17 changes: 8 additions & 9 deletions src/ImageSharp/Common/Tuples/Vector4Pair.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,21 +37,20 @@ public void AddInplace(ref Vector4Pair other)
this.B += other.B;
}

/// <summary>
/// Downscale method, specific to Jpeg color conversion. Works only if Vector{float}.Count == 4!
/// TODO: Move it somewhere else.
/// <summary>.
/// Downscale method, specific to Jpeg color conversion. Works only if Vector{float}.Count == 4! /// TODO: Move it somewhere else.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void RoundAndDownscalePreAvx2()
internal void RoundAndDownscalePreAvx2(float downscaleFactor)
{
ref Vector<float> a = ref Unsafe.As<Vector4, Vector<float>>(ref this.A);
a = a.FastRound();

ref Vector<float> b = ref Unsafe.As<Vector4, Vector<float>>(ref this.B);
b = b.FastRound();

// Downscale by 1/255
var scale = new Vector4(1 / 255f);
// Downscale by 1/factor
var scale = new Vector4(1 / downscaleFactor);
this.A *= scale;
this.B *= scale;
}
Expand All @@ -61,14 +60,14 @@ internal void RoundAndDownscalePreAvx2()
/// TODO: Move it somewhere else.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void RoundAndDownscaleAvx2()
internal void RoundAndDownscaleAvx2(float downscaleFactor)
{
ref Vector<float> self = ref Unsafe.As<Vector4Pair, Vector<float>>(ref this);
Vector<float> v = self;
v = v.FastRound();

// Downscale by 1/255
v *= new Vector<float>(1 / 255f);
// Downscale by 1/factor
v *= new Vector<float>(1 / downscaleFactor);
self = v;
}

Expand Down
19 changes: 10 additions & 9 deletions src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.

using System;
using System.Numerics;
using System.Runtime.CompilerServices;

Expand All @@ -9,10 +10,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
{
internal partial struct Block8x8F
{
private static readonly Vector4 CMin4 = new Vector4(0F);
private static readonly Vector4 CMax4 = new Vector4(255F);
private static readonly Vector4 COff4 = new Vector4(128F);

/// <summary>
/// Transpose the block into the destination block.
/// </summary>
Expand Down Expand Up @@ -94,10 +91,14 @@ public void TransposeInto(ref Block8x8F d)
}

/// <summary>
/// Level shift by +128, clip to [0, 255]
/// Level shift by +maximum/2, clip to [0, maximum]
/// </summary>
public void NormalizeColorsInplace()
public void NormalizeColorsInplace(float maximum)
{
Vector4 CMin4 = new Vector4(0F);
Vector4 CMax4 = new Vector4(maximum);
Vector4 COff4 = new Vector4((float)Math.Ceiling(maximum/2));

this.V0L = Vector4.Clamp(this.V0L + COff4, CMin4, CMax4);
this.V0R = Vector4.Clamp(this.V0R + COff4, CMin4, CMax4);
this.V1L = Vector4.Clamp(this.V1L + COff4, CMin4, CMax4);
Expand All @@ -120,10 +121,10 @@ public void NormalizeColorsInplace()
/// AVX2-only variant for executing <see cref="NormalizeColorsInplace"/> and <see cref="RoundInplace"/> in one step.
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
public void NormalizeColorsAndRoundInplaceAvx2()
public void NormalizeColorsAndRoundInplaceAvx2(float maximum)
{
Vector<float> off = new Vector<float>(128f);
Vector<float> max = new Vector<float>(255F);
Vector<float> off = new Vector<float>((float)Math.Ceiling(maximum/2));
Vector<float> max = new Vector<float>(maximum);

ref Vector<float> row0 = ref Unsafe.As<Vector4, Vector<float>>(ref this.V0L);
row0 = NormalizeAndRound(row0, off, max);
Expand Down
19 changes: 10 additions & 9 deletions src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.tt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.

using System;
using System.Numerics;
using System.Runtime.CompilerServices;

Expand All @@ -22,10 +23,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
{
internal partial struct Block8x8F
{
private static readonly Vector4 CMin4 = new Vector4(0F);
private static readonly Vector4 CMax4 = new Vector4(255F);
private static readonly Vector4 COff4 = new Vector4(128F);

/// <summary>
/// Transpose the block into the destination block.
/// </summary>
Expand Down Expand Up @@ -59,10 +56,14 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
}

/// <summary>
/// Level shift by +128, clip to [0, 255]
/// Level shift by +maximum/2, clip to [0, maximum]
/// </summary>
public void NormalizeColorsInplace()
public void NormalizeColorsInplace(float maximum)
{
Vector4 CMin4 = new Vector4(0F);
Vector4 CMax4 = new Vector4(maximum);
Vector4 COff4 = new Vector4((float)Math.Ceiling(maximum/2));

<#

PushIndent(" ");
Expand All @@ -83,10 +84,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
/// AVX2-only variant for executing <see cref="NormalizeColorsInplace"/> and <see cref="RoundInplace"/> in one step.
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
public void NormalizeColorsAndRoundInplaceAvx2()
public void NormalizeColorsAndRoundInplaceAvx2(float maximum)
{
Vector<float> off = new Vector<float>(128f);
Vector<float> max = new Vector<float>(255F);
Vector<float> off = new Vector<float>((float)Math.Ceiling(maximum/2));
Vector<float> max = new Vector<float>(maximum);
<#

for (int i = 0; i < 8; i++)
Expand Down
8 changes: 4 additions & 4 deletions src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs
Original file line number Diff line number Diff line change
Expand Up @@ -467,17 +467,17 @@ public Block8x8 RoundAsInt16Block()
}

/// <summary>
/// Level shift by +128, clip to [0..255], and round all the values in the block.
/// Level shift by +maximum/2, clip to [0..maximum], and round all the values in the block.
/// </summary>
public void NormalizeColorsAndRoundInplace()
public void NormalizeColorsAndRoundInplace(float maximum)
{
if (SimdUtils.IsAvx2CompatibleArchitecture)
{
this.NormalizeColorsAndRoundInplaceAvx2();
this.NormalizeColorsAndRoundInplaceAvx2(maximum);
}
else
{
this.NormalizeColorsInplace();
this.NormalizeColorsInplace(maximum);
this.RoundInplace();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ internal abstract partial class JpegColorConverter
{
internal class FromCmyk : JpegColorConverter
{
public FromCmyk()
: base(JpegColorSpace.Cmyk)
public FromCmyk(int precision)
: base(JpegColorSpace.Cmyk, precision)
{
}

Expand All @@ -25,14 +25,18 @@ public override void ConvertToRgba(in ComponentValues values, Span<Vector4> resu

var v = new Vector4(0, 0, 0, 1F);

var scale = new Vector4(1 / 255F, 1 / 255F, 1 / 255F, 1F);
var scale = new Vector4(
1 / this.MaximumValue,
1 / this.MaximumValue,
1 / this.MaximumValue,
1F);

for (int i = 0; i < result.Length; i++)
{
float c = cVals[i];
float m = mVals[i];
float y = yVals[i];
float k = kVals[i] / 255F;
float k = kVals[i] / this.MaximumValue;

v.X = c * k;
v.Y = m * k;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,18 @@ internal abstract partial class JpegColorConverter
{
internal class FromGrayscale : JpegColorConverter
{
public FromGrayscale()
: base(JpegColorSpace.Grayscale)
public FromGrayscale(int precision)
: base(JpegColorSpace.Grayscale, precision)
{
}

public override void ConvertToRgba(in ComponentValues values, Span<Vector4> result)
{
var scale = new Vector4(1 / 255F, 1 / 255F, 1 / 255F, 1F);
var scale = new Vector4(
1 / this.MaximumValue,
1 / this.MaximumValue,
1 / this.MaximumValue,
1F);

ref float sBase = ref MemoryMarshal.GetReference(values.Component0);
ref Vector4 dBase = ref MemoryMarshal.GetReference(result);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ internal abstract partial class JpegColorConverter
{
internal class FromRgb : JpegColorConverter
{
public FromRgb()
: base(JpegColorSpace.RGB)
public FromRgb(int precision)
: base(JpegColorSpace.RGB, precision)
{
}

Expand All @@ -24,7 +24,11 @@ public override void ConvertToRgba(in ComponentValues values, Span<Vector4> resu

var v = new Vector4(0, 0, 0, 1);

var scale = new Vector4(1 / 255F, 1 / 255F, 1 / 255F, 1F);
var scale = new Vector4(
1 / this.MaximumValue,
1 / this.MaximumValue,
1 / this.MaximumValue,
1F);

for (int i = 0; i < result.Length; i++)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,17 @@ internal abstract partial class JpegColorConverter
{
internal class FromYCbCrBasic : JpegColorConverter
{
public FromYCbCrBasic()
: base(JpegColorSpace.YCbCr)
public FromYCbCrBasic(int precision)
: base(JpegColorSpace.YCbCr, precision)
{
}

public override void ConvertToRgba(in ComponentValues values, Span<Vector4> result)
{
ConvertCore(values, result);
ConvertCore(values, result, this.MaximumValue, this.HalfValue);
}

internal static void ConvertCore(in ComponentValues values, Span<Vector4> result)
internal static void ConvertCore(in ComponentValues values, Span<Vector4> result, float maxValue, float halfValue)
{
// TODO: We can optimize a lot here with Vector<float> and SRCS.Unsafe()!
ReadOnlySpan<float> yVals = values.Component0;
Expand All @@ -29,13 +29,13 @@ internal static void ConvertCore(in ComponentValues values, Span<Vector4> result

var v = new Vector4(0, 0, 0, 1);

var scale = new Vector4(1 / 255F, 1 / 255F, 1 / 255F, 1F);
var scale = new Vector4(1 / maxValue, 1 / maxValue, 1 / maxValue, 1F);

for (int i = 0; i < result.Length; i++)
{
float y = yVals[i];
float cb = cbVals[i] - 128F;
float cr = crVals[i] - 128F;
float cb = cbVals[i] - halfValue;
float cr = crVals[i] - halfValue;

v.X = MathF.Round(y + (1.402F * cr), MidpointRounding.AwayFromZero);
v.Y = MathF.Round(y - (0.344136F * cb) - (0.714136F * cr), MidpointRounding.AwayFromZero);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ internal abstract partial class JpegColorConverter
{
internal class FromYCbCrSimd : JpegColorConverter
{
public FromYCbCrSimd()
: base(JpegColorSpace.YCbCr)
public FromYCbCrSimd(int precision)
: base(JpegColorSpace.YCbCr, precision)
{
}

Expand All @@ -25,16 +25,16 @@ public override void ConvertToRgba(in ComponentValues values, Span<Vector4> resu
int simdCount = result.Length - remainder;
if (simdCount > 0)
{
ConvertCore(values.Slice(0, simdCount), result.Slice(0, simdCount));
ConvertCore(values.Slice(0, simdCount), result.Slice(0, simdCount), this.MaximumValue, this.HalfValue);
}

FromYCbCrBasic.ConvertCore(values.Slice(simdCount, remainder), result.Slice(simdCount, remainder));
FromYCbCrBasic.ConvertCore(values.Slice(simdCount, remainder), result.Slice(simdCount, remainder), this.MaximumValue, this.HalfValue);
}

/// <summary>
/// SIMD convert using buffers of sizes divisible by 8.
/// </summary>
internal static void ConvertCore(in ComponentValues values, Span<Vector4> result)
internal static void ConvertCore(in ComponentValues values, Span<Vector4> result, float maxValue, float halfValue)
{
DebugGuard.IsTrue(result.Length % 8 == 0, nameof(result), "result.Length should be divisible by 8!");

Expand All @@ -48,7 +48,7 @@ internal static void ConvertCore(in ComponentValues values, Span<Vector4> result
ref Vector4Octet resultBase =
ref Unsafe.As<Vector4, Vector4Octet>(ref MemoryMarshal.GetReference(result));

var chromaOffset = new Vector4(-128f);
var chromaOffset = new Vector4(-halfValue);

// Walking 8 elements at one step:
int n = result.Length / 8;
Expand All @@ -58,11 +58,11 @@ internal static void ConvertCore(in ComponentValues values, Span<Vector4> result
// y = yVals[i];
Vector4Pair y = Unsafe.Add(ref yBase, i);

// cb = cbVals[i] - 128F;
// cb = cbVals[i] - halfValue);
Vector4Pair cb = Unsafe.Add(ref cbBase, i);
cb.AddInplace(chromaOffset);

// cr = crVals[i] - 128F;
// cr = crVals[i] - halfValue;
Vector4Pair cr = Unsafe.Add(ref crBase, i);
cr.AddInplace(chromaOffset);

Expand Down Expand Up @@ -90,15 +90,15 @@ internal static void ConvertCore(in ComponentValues values, Span<Vector4> result
if (Vector<float>.Count == 4)
{
// TODO: Find a way to properly run & test this path on AVX2 PC-s! (Have I already mentioned that Vector<T> is terrible?)
r.RoundAndDownscalePreAvx2();
g.RoundAndDownscalePreAvx2();
b.RoundAndDownscalePreAvx2();
r.RoundAndDownscalePreAvx2(maxValue);
g.RoundAndDownscalePreAvx2(maxValue);
b.RoundAndDownscalePreAvx2(maxValue);
}
else if (SimdUtils.IsAvx2CompatibleArchitecture)
{
r.RoundAndDownscaleAvx2();
g.RoundAndDownscaleAvx2();
b.RoundAndDownscaleAvx2();
r.RoundAndDownscaleAvx2(maxValue);
g.RoundAndDownscaleAvx2(maxValue);
b.RoundAndDownscaleAvx2(maxValue);
}
else
{
Expand Down
Loading

0 comments on commit db0fc0d

Please sign in to comment.