Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Decode Jpeg into Rgb24 when pixel type not specified #1773

Merged
merged 29 commits into from
Oct 5, 2021
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
033ed8e
Inplace JpegColorConverter basic infra
antonfirsov Oct 2, 2021
8599caa
convert YCbCr inplace
antonfirsov Oct 2, 2021
ef767cc
Cmyk & Grayscale inplace conversion
antonfirsov Oct 2, 2021
0a6189d
inplace ycck conversion
antonfirsov Oct 2, 2021
5f90e02
Change SpectralConverter<T> to use inplace converters and PackFromRgb…
antonfirsov Oct 2, 2021
c9d6556
simplify DecodeJpeg_ImageSpecific benchmark
antonfirsov Oct 2, 2021
d798450
Decode into Rgb24 by default
antonfirsov Oct 2, 2021
06566c5
Resize: do not premultiply pixels with no alpha
antonfirsov Oct 3, 2021
5ba6461
fix whitespace issues
antonfirsov Oct 3, 2021
adcc6d4
remove old JpegColorConverter methods
antonfirsov Oct 3, 2021
179e43a
delete more unused methods
antonfirsov Oct 3, 2021
d2989d8
fix ImageSharp.Benchmarks build
antonfirsov Oct 3, 2021
387bdfa
fix ProfilingSandbox
antonfirsov Oct 3, 2021
a4cf70f
remove unused test methods
antonfirsov Oct 3, 2021
74a0dea
Merge branch 'master' into af/jpeg-pack-sandbox
antonfirsov Oct 3, 2021
cf4c3fb
Delete Vector4Octet
antonfirsov Oct 3, 2021
2537547
use AggressiveInlining in some methods regardless of PROFILING
antonfirsov Oct 3, 2021
6e136ec
LoadResizeSaveStressRunner.ThumbnailSize as a parameter
antonfirsov Oct 3, 2021
e66f7b2
Merge branch 'af/jpeg-pack-sandbox' of https://github.com/SixLabors/I…
antonfirsov Oct 3, 2021
a421d6e
!values.IsEmpty
antonfirsov Oct 3, 2021
bcfd3f3
use nint with Unsafe.Add
antonfirsov Oct 3, 2021
fb36608
Merge branch 'af/jpeg-pack-sandbox' of https://github.com/SixLabors/I…
antonfirsov Oct 3, 2021
4803b45
"less ceremony"
antonfirsov Oct 3, 2021
ed57622
((uint)bufferIdx >= group.Count) trick
antonfirsov Oct 3, 2021
8ebe3b5
Merge branch 'af/jpeg-pack-sandbox' of https://github.com/SixLabors/I…
antonfirsov Oct 3, 2021
78fd768
Merge branch 'master' into af/jpeg-pack-sandbox
JimBobSquarePants Oct 5, 2021
ad976f1
elide further bound checks
antonfirsov Oct 5, 2021
6d9a04d
Premultiply only if alpha representation is unknown or Unassociated
antonfirsov Oct 5, 2021
4323c8d
Update src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeP…
JimBobSquarePants Oct 5, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/ImageSharp/Common/Helpers/InliningOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ namespace SixLabors.ImageSharp
/// </summary>
internal static class InliningOptions
{
/// <summary>
/// <see cref="MethodImplOptions.AggressiveInlining"/> regardless of the build conditions.
/// </summary>
public const MethodImplOptions AlwaysInline = MethodImplOptions.AggressiveInlining;
#if PROFILING
public const MethodImplOptions HotPath = MethodImplOptions.NoInlining;
public const MethodImplOptions ShortMethod = MethodImplOptions.NoInlining;
Expand Down
2 changes: 1 addition & 1 deletion src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs
Original file line number Diff line number Diff line change
Expand Up @@ -537,7 +537,7 @@ private static void Shuffle4Slice3(
/// <param name="vm0">The first vector to multiply.</param>
/// <param name="vm1">The second vector to multiply.</param>
/// <returns>The <see cref="Vector256{T}"/>.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(InliningOptions.AlwaysInline)]
public static Vector256<float> MultiplyAdd(
in Vector256<float> va,
in Vector256<float> vm0,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,60 +22,39 @@ public FromCmykAvx2(int precision)
{
}

protected override void ConvertCoreVectorized(in ComponentValues values, Span<Vector4> result)
protected override void ConvertCoreVectorizedInplace(in ComponentValues values)
{
#if SUPPORTS_RUNTIME_INTRINSICS
ref Vector256<float> cBase =
ref Vector256<float> c0Base =
ref Unsafe.As<float, Vector256<float>>(ref MemoryMarshal.GetReference(values.Component0));
ref Vector256<float> mBase =
ref Vector256<float> c1Base =
ref Unsafe.As<float, Vector256<float>>(ref MemoryMarshal.GetReference(values.Component1));
ref Vector256<float> yBase =
ref Vector256<float> c2Base =
ref Unsafe.As<float, Vector256<float>>(ref MemoryMarshal.GetReference(values.Component2));
ref Vector256<float> kBase =
ref Vector256<float> c3Base =
ref Unsafe.As<float, Vector256<float>>(ref MemoryMarshal.GetReference(values.Component3));

ref Vector256<float> resultBase =
ref Unsafe.As<Vector4, Vector256<float>>(ref MemoryMarshal.GetReference(result));

// Used for the color conversion
var scale = Vector256.Create(1 / this.MaximumValue);
var one = Vector256.Create(1F);

// Used for packing
ref byte control = ref MemoryMarshal.GetReference(HwIntrinsics.PermuteMaskEvenOdd8x32);
Vector256<int> vcontrol = Unsafe.As<byte, Vector256<int>>(ref control);

int n = result.Length / 8;
for (int i = 0; i < n; i++)
nint n = values.Component0.Length / 8;
for (nint i = 0; i < n; i++)
{
Vector256<float> k = Avx2.PermuteVar8x32(Unsafe.Add(ref kBase, i), vcontrol);
Vector256<float> c = Avx2.PermuteVar8x32(Unsafe.Add(ref cBase, i), vcontrol);
Vector256<float> m = Avx2.PermuteVar8x32(Unsafe.Add(ref mBase, i), vcontrol);
Vector256<float> y = Avx2.PermuteVar8x32(Unsafe.Add(ref yBase, i), vcontrol);
ref Vector256<float> c = ref Unsafe.Add(ref c0Base, i);
ref Vector256<float> m = ref Unsafe.Add(ref c1Base, i);
ref Vector256<float> y = ref Unsafe.Add(ref c2Base, i);
Vector256<float> k = Unsafe.Add(ref c3Base, i);

k = Avx.Multiply(k, scale);

c = Avx.Multiply(Avx.Multiply(c, k), scale);
m = Avx.Multiply(Avx.Multiply(m, k), scale);
y = Avx.Multiply(Avx.Multiply(y, k), scale);

Vector256<float> cmLo = Avx.UnpackLow(c, m);
Vector256<float> yoLo = Avx.UnpackLow(y, one);
Vector256<float> cmHi = Avx.UnpackHigh(c, m);
Vector256<float> yoHi = Avx.UnpackHigh(y, one);

ref Vector256<float> destination = ref Unsafe.Add(ref resultBase, i * 4);

destination = Avx.Shuffle(cmLo, yoLo, 0b01_00_01_00);
Unsafe.Add(ref destination, 1) = Avx.Shuffle(cmLo, yoLo, 0b11_10_11_10);
Unsafe.Add(ref destination, 2) = Avx.Shuffle(cmHi, yoHi, 0b01_00_01_00);
Unsafe.Add(ref destination, 3) = Avx.Shuffle(cmHi, yoHi, 0b11_10_11_10);
}
#endif
}

protected override void ConvertCore(in ComponentValues values, Span<Vector4> result) =>
FromCmykBasic.ConvertCore(values, result, this.MaximumValue);
protected override void ConvertCoreInplace(in ComponentValues values) =>
FromCmykBasic.ConvertCoreInplace(values, this.MaximumValue);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,38 +15,27 @@ public FromCmykBasic(int precision)
{
}

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

internal static void ConvertCore(in ComponentValues values, Span<Vector4> result, float maxValue)
internal static void ConvertCoreInplace(in ComponentValues values, float maxValue)
{
ReadOnlySpan<float> cVals = values.Component0;
ReadOnlySpan<float> mVals = values.Component1;
ReadOnlySpan<float> yVals = values.Component2;
ReadOnlySpan<float> kVals = values.Component3;

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

var maximum = 1 / maxValue;
var scale = new Vector4(maximum, maximum, maximum, 1F);
Span<float> c0 = values.Component0;
Span<float> c1 = values.Component1;
Span<float> c2 = values.Component2;
Span<float> c3 = values.Component3;

for (int i = 0; i < result.Length; i++)
float scale = 1 / maxValue;
for (int i = 0; i < c0.Length; i++)
{
float c = cVals[i];
float m = mVals[i];
float y = yVals[i];
float k = kVals[i] / maxValue;

v.X = c * k;
v.Y = m * k;
v.Z = y * k;
v.W = 1F;

v *= scale;

result[i] = v;
float c = c0[i];
float m = c1[i];
float y = c2[i];
float k = c3[i] / maxValue;

c0[i] = c * k * scale;
c1[i] = m * k * scale;
c2[i] = y * k * scale;
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public FromCmykVector8(int precision)
{
}

protected override void ConvertCoreVectorized(in ComponentValues values, Span<Vector4> result)
protected override void ConvertCoreVectorizedInplace(in ComponentValues values)
{
ref Vector<float> cBase =
ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(values.Component0));
Expand All @@ -29,43 +29,25 @@ protected override void ConvertCoreVectorized(in ComponentValues values, Span<Ve
ref Vector<float> kBase =
ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(values.Component3));

ref Vector4Octet resultBase =
ref Unsafe.As<Vector4, Vector4Octet>(ref MemoryMarshal.GetReference(result));

Vector4Pair cc = default;
Vector4Pair mm = default;
Vector4Pair yy = default;
ref Vector<float> ccRefAsVector = ref Unsafe.As<Vector4Pair, Vector<float>>(ref cc);
ref Vector<float> mmRefAsVector = ref Unsafe.As<Vector4Pair, Vector<float>>(ref mm);
ref Vector<float> yyRefAsVector = ref Unsafe.As<Vector4Pair, Vector<float>>(ref yy);

var scale = new Vector<float>(1 / this.MaximumValue);

// Walking 8 elements at one step:
int n = result.Length / 8;
for (int i = 0; i < n; i++)
nint n = values.Component0.Length / 8;
for (nint i = 0; i < n; i++)
{
Vector<float> c = Unsafe.Add(ref cBase, i);
Vector<float> m = Unsafe.Add(ref mBase, i);
Vector<float> y = Unsafe.Add(ref yBase, i);
ref Vector<float> c = ref Unsafe.Add(ref cBase, i);
ref Vector<float> m = ref Unsafe.Add(ref mBase, i);
ref Vector<float> y = ref Unsafe.Add(ref yBase, i);
Vector<float> k = Unsafe.Add(ref kBase, i) * scale;

c = (c * k) * scale;
m = (m * k) * scale;
y = (y * k) * scale;

ccRefAsVector = c;
mmRefAsVector = m;
yyRefAsVector = y;

// Collect (c0,c1...c8) (m0,m1...m8) (y0,y1...y8) vector values in the expected (r0,g0,g1,1), (r1,g1,g2,1) ... order:
ref Vector4Octet destination = ref Unsafe.Add(ref resultBase, i);
destination.Pack(ref cc, ref mm, ref yy);
}
}

protected override void ConvertCore(in ComponentValues values, Span<Vector4> result) =>
FromCmykBasic.ConvertCore(values, result, this.MaximumValue);
protected override void ConvertCoreInplace(in ComponentValues values) =>
FromCmykBasic.ConvertCoreInplace(values, this.MaximumValue);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,42 +22,26 @@ public FromGrayscaleAvx2(int precision)
{
}

protected override void ConvertCoreVectorized(in ComponentValues values, Span<Vector4> result)
protected override void ConvertCoreVectorizedInplace(in ComponentValues values)
{
#if SUPPORTS_RUNTIME_INTRINSICS
ref Vector256<float> gBase =
ref Vector256<float> c0Base =
ref Unsafe.As<float, Vector256<float>>(ref MemoryMarshal.GetReference(values.Component0));

ref Vector256<float> resultBase =
ref Unsafe.As<Vector4, Vector256<float>>(ref MemoryMarshal.GetReference(result));

// Used for the color conversion
var scale = Vector256.Create(1 / this.MaximumValue);
var one = Vector256.Create(1F);

// Used for packing
ref byte control = ref MemoryMarshal.GetReference(HwIntrinsics.PermuteMaskEvenOdd8x32);
Vector256<int> vcontrol = Unsafe.As<byte, Vector256<int>>(ref control);

int n = result.Length / 8;
for (int i = 0; i < n; i++)
nint n = values.Component0.Length / 8;
for (nint i = 0; i < n; i++)
{
Vector256<float> g = Avx.Multiply(Unsafe.Add(ref gBase, i), scale);

g = Avx2.PermuteVar8x32(g, vcontrol);

ref Vector256<float> destination = ref Unsafe.Add(ref resultBase, i * 4);

destination = Avx.Blend(Avx.Permute(g, 0b00_00_00_00), one, 0b1000_1000);
Unsafe.Add(ref destination, 1) = Avx.Blend(Avx.Shuffle(g, g, 0b01_01_01_01), one, 0b1000_1000);
Unsafe.Add(ref destination, 2) = Avx.Blend(Avx.Shuffle(g, g, 0b10_10_10_10), one, 0b1000_1000);
Unsafe.Add(ref destination, 3) = Avx.Blend(Avx.Shuffle(g, g, 0b11_11_11_11), one, 0b1000_1000);
ref Vector256<float> c0 = ref Unsafe.Add(ref c0Base, i);
c0 = Avx.Multiply(c0, scale);
}
#endif
}

protected override void ConvertCore(in ComponentValues values, Span<Vector4> result) =>
FromGrayscaleBasic.ConvertCore(values, result, this.MaximumValue);
protected override void ConvertCoreInplace(in ComponentValues values) =>
FromGrayscaleBasic.ScaleValues(values.Component0, this.MaximumValue);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,25 +17,35 @@ public FromGrayscaleBasic(int precision)
{
}

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

internal static void ConvertCore(in ComponentValues values, Span<Vector4> result, float maxValue)
internal static void ScaleValues(Span<float> values, float maxValue)
{
var maximum = 1 / maxValue;
var scale = new Vector4(maximum, maximum, maximum, 1F);
Span<Vector4> vecValues = MemoryMarshal.Cast<float, Vector4>(values);

ref float sBase = ref MemoryMarshal.GetReference(values.Component0);
ref Vector4 dBase = ref MemoryMarshal.GetReference(result);
var scaleVector = new Vector4(1 / maxValue);

for (int i = 0; i < result.Length; i++)
for (int i = 0; i < vecValues.Length; i++)
{
var v = new Vector4(Unsafe.Add(ref sBase, i));
v.W = 1f;
v *= scale;
Unsafe.Add(ref dBase, i) = v;
vecValues[i] *= scaleVector;
}

values = values.Slice(vecValues.Length * 4);
if (!values.IsEmpty)
{
float scaleValue = 1f / maxValue;
values[0] *= scaleValue;

if (values.Length > 1)
{
values[1] *= scaleValue;

if (values.Length > 2)
antonfirsov marked this conversation as resolved.
Show resolved Hide resolved
{
values[2] *= scaleValue;
}
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public FromRgbAvx2(int precision)
{
}

protected override void ConvertCoreVectorized(in ComponentValues values, Span<Vector4> result)
protected override void ConvertCoreVectorizedInplace(in ComponentValues values)
{
#if SUPPORTS_RUNTIME_INTRINSICS
ref Vector256<float> rBase =
Expand All @@ -32,41 +32,23 @@ protected override void ConvertCoreVectorized(in ComponentValues values, Span<Ve
ref Vector256<float> bBase =
ref Unsafe.As<float, Vector256<float>>(ref MemoryMarshal.GetReference(values.Component2));

ref Vector256<float> resultBase =
ref Unsafe.As<Vector4, Vector256<float>>(ref MemoryMarshal.GetReference(result));

// Used for the color conversion
var scale = Vector256.Create(1 / this.MaximumValue);
var one = Vector256.Create(1F);

// Used for packing
ref byte control = ref MemoryMarshal.GetReference(HwIntrinsics.PermuteMaskEvenOdd8x32);
Vector256<int> vcontrol = Unsafe.As<byte, Vector256<int>>(ref control);

int n = result.Length / 8;
for (int i = 0; i < n; i++)
nint n = values.Component0.Length / 8;
for (nint i = 0; i < n; i++)
{
Vector256<float> r = Avx.Multiply(Avx2.PermuteVar8x32(Unsafe.Add(ref rBase, i), vcontrol), scale);
Vector256<float> g = Avx.Multiply(Avx2.PermuteVar8x32(Unsafe.Add(ref gBase, i), vcontrol), scale);
Vector256<float> b = Avx.Multiply(Avx2.PermuteVar8x32(Unsafe.Add(ref bBase, i), vcontrol), scale);

Vector256<float> rgLo = Avx.UnpackLow(r, g);
Vector256<float> boLo = Avx.UnpackLow(b, one);
Vector256<float> rgHi = Avx.UnpackHigh(r, g);
Vector256<float> boHi = Avx.UnpackHigh(b, one);

ref Vector256<float> destination = ref Unsafe.Add(ref resultBase, i * 4);

destination = Avx.Shuffle(rgLo, boLo, 0b01_00_01_00);
Unsafe.Add(ref destination, 1) = Avx.Shuffle(rgLo, boLo, 0b11_10_11_10);
Unsafe.Add(ref destination, 2) = Avx.Shuffle(rgHi, boHi, 0b01_00_01_00);
Unsafe.Add(ref destination, 3) = Avx.Shuffle(rgHi, boHi, 0b11_10_11_10);
ref Vector256<float> r = ref Unsafe.Add(ref rBase, i);
ref Vector256<float> g = ref Unsafe.Add(ref gBase, i);
ref Vector256<float> b = ref Unsafe.Add(ref bBase, i);
r = Avx.Multiply(r, scale);
g = Avx.Multiply(g, scale);
b = Avx.Multiply(b, scale);
}
#endif
}

protected override void ConvertCore(in ComponentValues values, Span<Vector4> result) =>
FromRgbBasic.ConvertCore(values, result, this.MaximumValue);
protected override void ConvertCoreInplace(in ComponentValues values) =>
FromRgbBasic.ConvertCoreInplace(values, this.MaximumValue);
}
}
}
Loading