Browse Source

Merge branch 'main' into stefannikolei/fix/scalar

pull/2416/head
Brian Popow 3 years ago
committed by GitHub
parent
commit
ac78ff5600
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 29
      src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs
  2. 68
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.GrayScaleArm.cs
  3. 5
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterBase.cs
  4. 8
      tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/GrayscaleColorConversion.cs
  5. 17
      tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs

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

@ -4,6 +4,7 @@
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.Arm;
using System.Runtime.Intrinsics.X86;
using SixLabors.ImageSharp.PixelFormats;
@ -554,6 +555,34 @@ internal static partial class SimdUtils
return Avx.Add(Avx.Multiply(vm0, vm1), va);
}
/// <summary>
/// Performs a multiplication and an addition of the <see cref="Vector128{Single}"/>.
/// TODO: Fix. The arguments are in a different order to the FMA intrinsic.
/// </summary>
/// <remarks>ret = (vm0 * vm1) + va</remarks>
/// <param name="va">The vector to add to the intermediate result.</param>
/// <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.AlwaysInline)]
public static Vector128<float> MultiplyAdd(
Vector128<float> va,
Vector128<float> vm0,
Vector128<float> vm1)
{
if (Fma.IsSupported)
{
return Fma.MultiplyAdd(vm1, vm0, va);
}
if (AdvSimd.IsSupported)
{
return AdvSimd.Add(AdvSimd.Multiply(vm0, vm1), va);
}
return Sse.Add(Sse.Multiply(vm0, vm1), va);
}
/// <summary>
/// Performs a multiplication and a subtraction of the <see cref="Vector256{Single}"/>.
/// TODO: Fix. The arguments are in a different order to the FMA intrinsic.

68
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.GrayScaleArm.cs

@ -0,0 +1,68 @@
// 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;
using static SixLabors.ImageSharp.SimdUtils;
namespace SixLabors.ImageSharp.Formats.Jpeg.Components;
internal abstract partial class JpegColorConverterBase
{
internal sealed class GrayscaleArm : JpegColorConverterArm
{
public GrayscaleArm(int precision)
: base(JpegColorSpace.Grayscale, precision)
{
}
/// <inheritdoc/>
public override void ConvertToRgbInplace(in ComponentValues values)
{
ref Vector128<float> c0Base =
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(values.Component0));
// Used for the color conversion
var scale = Vector128.Create(1 / this.MaximumValue);
nuint n = (uint)values.Component0.Length / (uint)Vector128<float>.Count;
for (nuint i = 0; i < n; i++)
{
ref Vector128<float> c0 = ref Unsafe.Add(ref c0Base, i);
c0 = AdvSimd.Multiply(c0, scale);
}
}
/// <inheritdoc/>
public override void ConvertFromRgb(in ComponentValues values, Span<float> rLane, Span<float> gLane, Span<float> bLane)
{
ref Vector128<float> destLuminance =
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(values.Component0));
ref Vector128<float> srcRed =
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(rLane));
ref Vector128<float> srcGreen =
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(gLane));
ref Vector128<float> srcBlue =
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(bLane));
// Used for the color conversion
var f0299 = Vector128.Create(0.299f);
var f0587 = Vector128.Create(0.587f);
var f0114 = Vector128.Create(0.114f);
nuint n = (uint)values.Component0.Length / (uint)Vector128<float>.Count;
for (nuint i = 0; i < n; i++)
{
ref Vector128<float> r = ref Unsafe.Add(ref srcRed, i);
ref Vector128<float> g = ref Unsafe.Add(ref srcGreen, i);
ref Vector128<float> b = ref Unsafe.Add(ref srcBlue, i);
// luminocity = (0.299 * r) + (0.587 * g) + (0.114 * b)
Unsafe.Add(ref destLuminance, i) = HwIntrinsics.MultiplyAdd(HwIntrinsics.MultiplyAdd(AdvSimd.Multiply(f0114, b), f0587, g), f0299, r);
}
}
}
}

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

@ -200,6 +200,11 @@ internal abstract partial class JpegColorConverterBase
return new GrayscaleAvx(precision);
}
if (JpegColorConverterArm.IsSupported)
{
return new GrayscaleArm(precision);
}
if (JpegColorConverterVector.IsSupported)
{
return new GrayScaleVector(precision);

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

@ -29,4 +29,12 @@ public class GrayscaleColorConversion : ColorConversionBenchmark
new JpegColorConverterBase.GrayscaleAvx(8).ConvertToRgbInplace(values);
}
[Benchmark]
public void SimdVectorArm()
{
var values = new JpegColorConverterBase.ComponentValues(this.Input, 0);
new JpegColorConverterBase.GrayscaleArm(8).ConvertToRgbInplace(values);
}
}

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

@ -470,6 +470,23 @@ public class JpegColorConverterTests
new JpegColorConverterBase.GrayscaleScalar(8),
precísion: 3);
[Theory]
[MemberData(nameof(Seeds))]
public void FromGrayscaleArm(int seed) =>
this.TestConversionToRgb(new JpegColorConverterBase.GrayscaleArm(8),
1,
seed,
new JpegColorConverterBase.GrayscaleScalar(8));
[Theory]
[MemberData(nameof(Seeds))]
public void FromRgbToGrayscaleArm(int seed) =>
this.TestConversionFromRgb(new JpegColorConverterBase.GrayscaleArm(8),
1,
seed,
new JpegColorConverterBase.GrayscaleScalar(8),
precísion: 3);
[Theory]
[MemberData(nameof(Seeds))]
public void FromRgbAvx2(int seed) =>

Loading…
Cancel
Save