Browse Source

SIMD byte -> float conversion: BulkConvertByteToNormalizedFloatFast

pull/742/head
Anton Firszov 7 years ago
parent
commit
af7d96d214
  1. 45
      src/ImageSharp/Common/Extensions/SimdUtils.cs
  2. 16
      tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs
  3. 2
      tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj
  4. 24
      tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs
  5. 2
      tests/ImageSharp.Tests/TestUtilities/Tests/TestEnvironmentTests.cs

45
src/ImageSharp/Common/Extensions/SimdUtils.cs

@ -105,13 +105,50 @@ namespace SixLabors.ImageSharp
}
}
internal static void BulkConvertByteToNormalizedFloat(ReadOnlySpan<byte> source, Span<float> dest)
/// <summary>
/// Fast <see cref="byte"/> -> <see cref="float"/> conversion for RyuJIT runtimes having dotnet/coreclr#10662 merged.
/// <see>
/// <cref>https://github.com/dotnet/coreclr/pull/10662</cref>
/// </see>
/// </summary>
internal static void BulkConvertByteToNormalizedFloatFast(ReadOnlySpan<byte> source, Span<float> dest)
{
if (!Vector.IsHardwareAccelerated)
Guard.IsTrue(
source.Length % Vector<byte>.Count == 0,
nameof(source),
"dest.Length should be divisable by Vector<byte>.Count!");
int n = source.Length / Vector<byte>.Count;
ref Vector<byte> sourceBase = ref Unsafe.As<byte, Vector<byte>>(ref MemoryMarshal.GetReference(source));
ref Vector<float> destBase = ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(dest));
var scale = new Vector<float>(1f / 255f);
for (int i = 0; i < n; i++)
{
throw new InvalidOperationException(
"Rgba32.PixelOperations.ToVector4SimdAligned() should not be called when Vector.IsHardwareAccelerated == false!");
Vector<byte> b = Unsafe.Add(ref sourceBase, i);
Vector.Widen(b, out Vector<ushort> s0, out Vector<ushort> s1);
Vector.Widen(s0, out Vector<uint> w0, out Vector<uint> w1);
Vector.Widen(s1, out Vector<uint> w2, out Vector<uint> w3);
Vector<float> f0 = Vector.ConvertToSingle(w0) * scale;
Vector<float> f1 = Vector.ConvertToSingle(w1) * scale;
Vector<float> f2 = Vector.ConvertToSingle(w2) * scale;
Vector<float> f3 = Vector.ConvertToSingle(w3) * scale;
ref Vector<float> d = ref Unsafe.Add(ref destBase, i * 4);
d = f0;
Unsafe.Add(ref d, 1) = f1;
Unsafe.Add(ref d, 2) = f2;
Unsafe.Add(ref d, 3) = f3;
}
}
internal static void BulkConvertByteToNormalizedFloat(ReadOnlySpan<byte> source, Span<float> dest)
{
GuardAvx2(nameof(BulkConvertByteToNormalizedFloat));
DebugGuard.IsTrue((dest.Length % Vector<float>.Count) == 0, nameof(source), "dest.Length should be divisable by Vector<float>.Count!");

16
tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs

@ -28,7 +28,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
[Params(
//64,
1024)]
2048)]
public int Count { get; set; }
[GlobalSetup]
@ -72,14 +72,14 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
}
[CoreJob]
//[ClrJob]
[ClrJob]
public class ToVector4_Rgba32 : ToVector4<Rgba32>
{
class Config : ManualConfig
{
}
[Benchmark]
//[Benchmark]
public void BulkConvertByteToNormalizedFloat()
{
Span<byte> sBytes = MemoryMarshal.Cast<Rgba32, byte>(this.source.GetSpan());
@ -87,5 +87,15 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
SimdUtils.BulkConvertByteToNormalizedFloat(sBytes, dFloats);
}
[Benchmark]
public void BulkConvertByteToNormalizedFloatFast()
{
Span<byte> sBytes = MemoryMarshal.Cast<Rgba32, byte>(this.source.GetSpan());
Span<float> dFloats = MemoryMarshal.Cast<Vector4, float>(this.destination.GetSpan());
SimdUtils.BulkConvertByteToNormalizedFloatFast(sBytes, dFloats);
}
}
}

2
tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netcoreapp2.0;net461</TargetFrameworks>
<TargetFrameworks>netcoreapp2.1;net461</TargetFrameworks>
<OutputType>Exe</OutputType>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
<RootNamespace>SixLabors.ImageSharp.Benchmarks</RootNamespace>

24
tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs

@ -73,6 +73,30 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats
);
}
[Fact]
public void BulkConvertByteToNormalizedFloatFast()
{
if (!Vector.IsHardwareAccelerated)
{
return;
}
ImageSharp.PixelFormats.Rgba32[] source = CreatePixelTestData(128);
Vector4[] expected = CreateExpectedVector4Data(source);
TestOperation(
source,
expected,
(s, d) =>
{
ReadOnlySpan<byte> sBytes = MemoryMarshal.Cast<ImageSharp.PixelFormats.Rgba32, byte>(s);
Span<float> dFloats = MemoryMarshal.Cast<Vector4, float>(d.Memory.Span);
SimdUtils.BulkConvertByteToNormalizedFloatFast(sBytes, dFloats);
}
);
}
// [Fact] // Profiling benchmark - enable manually!
#pragma warning disable xUnit1013 // Public method should be marked as test

2
tests/ImageSharp.Tests/TestUtilities/Tests/TestEnvironmentTests.cs

@ -3,6 +3,8 @@
using System;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Common.Helpers;
using SixLabors.ImageSharp.Formats;

Loading…
Cancel
Save