Skip to content

Commit 97ac149

Browse files
authored
Merge branch 'main' into vector-constants
2 parents cdf6eed + 49c2262 commit 97ac149

File tree

5 files changed

+128
-1
lines changed

5 files changed

+128
-1
lines changed

src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System.Runtime.CompilerServices;
55
using System.Runtime.InteropServices;
66
using System.Runtime.Intrinsics;
7+
using System.Runtime.Intrinsics.Arm;
78
using System.Runtime.Intrinsics.X86;
89
using SixLabors.ImageSharp.PixelFormats;
910

@@ -555,6 +556,34 @@ public static Vector256<float> MultiplyAdd(
555556
return Avx.Add(Avx.Multiply(vm0, vm1), va);
556557
}
557558

559+
/// <summary>
560+
/// Performs a multiplication and an addition of the <see cref="Vector128{Single}"/>.
561+
/// TODO: Fix. The arguments are in a different order to the FMA intrinsic.
562+
/// </summary>
563+
/// <remarks>ret = (vm0 * vm1) + va</remarks>
564+
/// <param name="va">The vector to add to the intermediate result.</param>
565+
/// <param name="vm0">The first vector to multiply.</param>
566+
/// <param name="vm1">The second vector to multiply.</param>
567+
/// <returns>The <see cref="Vector256{T}"/>.</returns>
568+
[MethodImpl(InliningOptions.AlwaysInline)]
569+
public static Vector128<float> MultiplyAdd(
570+
Vector128<float> va,
571+
Vector128<float> vm0,
572+
Vector128<float> vm1)
573+
{
574+
if (Fma.IsSupported)
575+
{
576+
return Fma.MultiplyAdd(vm1, vm0, va);
577+
}
578+
579+
if (AdvSimd.IsSupported)
580+
{
581+
return AdvSimd.Add(AdvSimd.Multiply(vm0, vm1), va);
582+
}
583+
584+
return Sse.Add(Sse.Multiply(vm0, vm1), va);
585+
}
586+
558587
/// <summary>
559588
/// Performs a multiplication and a subtraction of the <see cref="Vector256{Single}"/>.
560589
/// TODO: Fix. The arguments are in a different order to the FMA intrinsic.
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// Copyright (c) Six Labors.
2+
// Licensed under the Six Labors Split License.
3+
4+
using System.Runtime.CompilerServices;
5+
using System.Runtime.InteropServices;
6+
using System.Runtime.Intrinsics;
7+
using System.Runtime.Intrinsics.Arm;
8+
using static SixLabors.ImageSharp.SimdUtils;
9+
10+
namespace SixLabors.ImageSharp.Formats.Jpeg.Components;
11+
12+
internal abstract partial class JpegColorConverterBase
13+
{
14+
internal sealed class GrayscaleArm : JpegColorConverterArm
15+
{
16+
public GrayscaleArm(int precision)
17+
: base(JpegColorSpace.Grayscale, precision)
18+
{
19+
}
20+
21+
/// <inheritdoc/>
22+
public override void ConvertToRgbInplace(in ComponentValues values)
23+
{
24+
ref Vector128<float> c0Base =
25+
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(values.Component0));
26+
27+
// Used for the color conversion
28+
var scale = Vector128.Create(1 / this.MaximumValue);
29+
30+
nuint n = (uint)values.Component0.Length / (uint)Vector128<float>.Count;
31+
for (nuint i = 0; i < n; i++)
32+
{
33+
ref Vector128<float> c0 = ref Unsafe.Add(ref c0Base, i);
34+
c0 = AdvSimd.Multiply(c0, scale);
35+
}
36+
}
37+
38+
/// <inheritdoc/>
39+
public override void ConvertFromRgb(in ComponentValues values, Span<float> rLane, Span<float> gLane, Span<float> bLane)
40+
{
41+
ref Vector128<float> destLuminance =
42+
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(values.Component0));
43+
44+
ref Vector128<float> srcRed =
45+
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(rLane));
46+
ref Vector128<float> srcGreen =
47+
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(gLane));
48+
ref Vector128<float> srcBlue =
49+
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(bLane));
50+
51+
// Used for the color conversion
52+
var f0299 = Vector128.Create(0.299f);
53+
var f0587 = Vector128.Create(0.587f);
54+
var f0114 = Vector128.Create(0.114f);
55+
56+
nuint n = (uint)values.Component0.Length / (uint)Vector128<float>.Count;
57+
for (nuint i = 0; i < n; i++)
58+
{
59+
ref Vector128<float> r = ref Unsafe.Add(ref srcRed, i);
60+
ref Vector128<float> g = ref Unsafe.Add(ref srcGreen, i);
61+
ref Vector128<float> b = ref Unsafe.Add(ref srcBlue, i);
62+
63+
// luminocity = (0.299 * r) + (0.587 * g) + (0.114 * b)
64+
Unsafe.Add(ref destLuminance, i) = HwIntrinsics.MultiplyAdd(HwIntrinsics.MultiplyAdd(AdvSimd.Multiply(f0114, b), f0587, g), f0299, r);
65+
}
66+
}
67+
}
68+
}

src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterBase.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,11 @@ private static JpegColorConverterBase GetGrayScaleConverter(int precision)
200200
return new GrayscaleAvx(precision);
201201
}
202202

203+
if (JpegColorConverterArm.IsSupported)
204+
{
205+
return new GrayscaleArm(precision);
206+
}
207+
203208
if (JpegColorConverterVector.IsSupported)
204209
{
205210
return new GrayScaleVector(precision);

tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/GrayscaleColorConversion.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,12 @@ public void SimdVectorAvx()
2929

3030
new JpegColorConverterBase.GrayscaleAvx(8).ConvertToRgbInplace(values);
3131
}
32+
33+
[Benchmark]
34+
public void SimdVectorArm()
35+
{
36+
var values = new JpegColorConverterBase.ComponentValues(this.Input, 0);
37+
38+
new JpegColorConverterBase.GrayscaleArm(8).ConvertToRgbInplace(values);
39+
}
3240
}

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

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,23 @@ public void FromRgbToGrayscaleAvx2(int seed) =>
307307
new JpegColorConverterBase.GrayscaleScalar(8),
308308
precísion: 3);
309309

310+
[Theory]
311+
[MemberData(nameof(Seeds))]
312+
public void FromGrayscaleArm(int seed) =>
313+
this.TestConversionToRgb(new JpegColorConverterBase.GrayscaleArm(8),
314+
1,
315+
seed,
316+
new JpegColorConverterBase.GrayscaleScalar(8));
317+
318+
[Theory]
319+
[MemberData(nameof(Seeds))]
320+
public void FromRgbToGrayscaleArm(int seed) =>
321+
this.TestConversionFromRgb(new JpegColorConverterBase.GrayscaleArm(8),
322+
1,
323+
seed,
324+
new JpegColorConverterBase.GrayscaleScalar(8),
325+
precísion: 3);
326+
310327
[Theory]
311328
[MemberData(nameof(Seeds))]
312329
public void FromRgbAvx2(int seed) =>
@@ -480,7 +497,7 @@ private static void ValidateConversionFromRgb(
480497
JpegColorConverterBase baseLineConverter,
481498
int precision = 4)
482499
{
483-
// arrange
500+
// arrange
484501
JpegColorConverterBase.ComponentValues actual = CreateRandomValues(TestBufferLength, componentCount, seed);
485502
JpegColorConverterBase.ComponentValues expected = CreateRandomValues(TestBufferLength, componentCount, seed);
486503
Random rnd = new(seed);

0 commit comments

Comments
 (0)