Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ If you prefer, you can compile ImageSharp yourself (please do and help!)

- Using [Visual Studio 2022](https://visualstudio.microsoft.com/vs/)
- Make sure you have the latest version installed
- Make sure you have [the .NET 6 SDK](https://www.microsoft.com/net/core#windows) installed
- Make sure you have [the .NET 7 SDK](https://www.microsoft.com/net/core#windows) installed

Alternatively, you can work from command line and/or with a lightweight editor on **both Linux/Unix and Windows**:

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.

using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.Arm;

namespace SixLabors.ImageSharp.Formats.Jpeg.Components;

internal abstract partial class JpegColorConverterBase
{
internal sealed class CmykArm64 : JpegColorConverterArm64
{
public CmykArm64(int precision)
: base(JpegColorSpace.Cmyk, precision)
{
}

/// <inheritdoc/>
public override void ConvertToRgbInplace(in ComponentValues values)
{
ref Vector128<float> c0Base =
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(values.Component0));
ref Vector128<float> c1Base =
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(values.Component1));
ref Vector128<float> c2Base =
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(values.Component2));
ref Vector128<float> c3Base =
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(values.Component3));

// Used for the color conversion
var scale = Vector128.Create(1 / (this.MaximumValue * this.MaximumValue));

nint n = (nint)(uint)values.Component0.Length / Vector128<float>.Count;
for (nint i = 0; i < n; i++)
{
ref Vector128<float> c = ref Unsafe.Add(ref c0Base, i);
ref Vector128<float> m = ref Unsafe.Add(ref c1Base, i);
ref Vector128<float> y = ref Unsafe.Add(ref c2Base, i);
Vector128<float> k = Unsafe.Add(ref c3Base, i);

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

/// <inheritdoc/>
public override void ConvertFromRgb(in ComponentValues values, Span<float> rLane, Span<float> gLane, Span<float> bLane)
=> ConvertFromRgb(in values, this.MaximumValue, rLane, gLane, bLane);

public static void ConvertFromRgb(in ComponentValues values, float maxValue, Span<float> rLane, Span<float> gLane, Span<float> bLane)
{
ref Vector128<float> destC =
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(values.Component0));
ref Vector128<float> destM =
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(values.Component1));
ref Vector128<float> destY =
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(values.Component2));
ref Vector128<float> destK =
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(values.Component3));

ref Vector128<float> srcR =
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(rLane));
ref Vector128<float> srcG =
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(gLane));
ref Vector128<float> srcB =
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(bLane));

var scale = Vector128.Create(maxValue);

nint n = (nint)(uint)values.Component0.Length / Vector128<float>.Count;
for (nint i = 0; i < n; i++)
{
Vector128<float> ctmp = AdvSimd.Subtract(scale, Unsafe.Add(ref srcR, i));
Vector128<float> mtmp = AdvSimd.Subtract(scale, Unsafe.Add(ref srcG, i));
Vector128<float> ytmp = AdvSimd.Subtract(scale, Unsafe.Add(ref srcB, i));
Vector128<float> ktmp = AdvSimd.Min(ctmp, AdvSimd.Min(mtmp, ytmp));

Vector128<float> kMask = AdvSimd.Not(AdvSimd.CompareEqual(ktmp, scale));

ctmp = AdvSimd.And(AdvSimd.Arm64.Divide(AdvSimd.Subtract(ctmp, ktmp), AdvSimd.Subtract(scale, ktmp)), kMask);
mtmp = AdvSimd.And(AdvSimd.Arm64.Divide(AdvSimd.Subtract(mtmp, ktmp), AdvSimd.Subtract(scale, ktmp)), kMask);
ytmp = AdvSimd.And(AdvSimd.Arm64.Divide(AdvSimd.Subtract(ytmp, ktmp), AdvSimd.Subtract(scale, ktmp)), kMask);

Unsafe.Add(ref destC, i) = AdvSimd.Subtract(scale, AdvSimd.Multiply(ctmp, scale));
Unsafe.Add(ref destM, i) = AdvSimd.Subtract(scale, AdvSimd.Multiply(mtmp, scale));
Unsafe.Add(ref destY, i) = AdvSimd.Subtract(scale, AdvSimd.Multiply(ytmp, scale));
Unsafe.Add(ref destK, i) = AdvSimd.Subtract(scale, ktmp);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.Arm;
using System.Runtime.Intrinsics.X86;

namespace SixLabors.ImageSharp.Formats.Jpeg.Components;

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 JpegColorConverterArm64 : JpegColorConverterBase
{
protected JpegColorConverterArm64(JpegColorSpace colorSpace, int precision)
: base(colorSpace, precision)
{
}

public static bool IsSupported => AdvSimd.Arm64.IsSupported;

public sealed override bool IsAvailable => IsSupported;

public sealed override int ElementsPerBatch => Vector128<float>.Count;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,11 @@ private static JpegColorConverterBase GetCmykConverter(int precision)
return new CmykAvx(precision);
}

if (JpegColorConverterArm64.IsSupported)
{
return new CmykArm64(precision);
}

if (JpegColorConverterVector.IsSupported)
{
return new CmykVector(precision);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,12 @@ public void SimdVectorAvx()

new JpegColorConverterBase.CmykAvx(8).ConvertToRgbInplace(values);
}

[Benchmark]
public void SimdVectorArm64()
{
var values = new JpegColorConverterBase.ComponentValues(this.Input, 0);

new JpegColorConverterBase.CmykArm64(8).ConvertToRgbInplace(values);
}
}
Loading