Browse Source

BulkConvertNormalizedFloatToByteClampOverflows

pull/742/head
Anton Firszov 7 years ago
parent
commit
df87a68555
  1. 66
      src/ImageSharp/Common/Extensions/SimdUtils.ExtendedIntrinsics.cs
  2. 18
      tests/ImageSharp.Tests/Common/SimdUtilsTests.cs

66
src/ImageSharp/Common/Extensions/SimdUtils.ExtendedIntrinsics.cs

@ -24,6 +24,9 @@ namespace SixLabors.ImageSharp
false;
#endif
/// <summary>
/// A variant of <see cref="SimdUtils.BulkConvertByteToNormalizedFloat"/>, which is faster on new .NET runtime.
/// </summary>
// ReSharper disable once MemberHidesStaticFromOuterClass
internal static void BulkConvertByteToNormalizedFloat(ReadOnlySpan<byte> source, Span<float> dest)
{
@ -37,7 +40,7 @@ namespace SixLabors.ImageSharp
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);
const float Scale = 1f / 255f;
for (int i = 0; i < n; i++)
{
@ -47,10 +50,10 @@ namespace SixLabors.ImageSharp
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;
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;
@ -59,6 +62,59 @@ namespace SixLabors.ImageSharp
Unsafe.Add(ref d, 3) = f3;
}
}
/// <summary>
/// A variant of <see cref="SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows"/>, which is faster on new .NET runtime.
/// </summary>
// ReSharper disable once MemberHidesStaticFromOuterClass
internal static void BulkConvertNormalizedFloatToByteClampOverflows(ReadOnlySpan<float> source, Span<byte> dest)
{
Guard.IsTrue(
dest.Length % Vector<byte>.Count == 0,
nameof(source),
"dest.Length should be divisable by Vector<byte>.Count!");
int n = dest.Length / Vector<byte>.Count;
ref Vector<float> sourceBase = ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(source));
ref Vector<byte> destBase = ref Unsafe.As<byte, Vector<byte>>(ref MemoryMarshal.GetReference(dest));
for (int i = 0; i < n; i++)
{
ref Vector<float> s = ref Unsafe.Add(ref sourceBase, i * 4);
Vector<float> f0 = s;
f0 = Clamp(f0);
Vector<float> f1 = Unsafe.Add(ref s, 1);
f1 = Clamp(f1);
Vector<float> f2 = Unsafe.Add(ref s, 2);
f2 = Clamp(f2);
Vector<float> f3 = Unsafe.Add(ref s, 3);
f3 = Clamp(f3);
Vector<uint> w0 = Vector.ConvertToUInt32(f0 * 255f);
Vector<uint> w1 = Vector.ConvertToUInt32(f1 * 255f);
Vector<uint> w2 = Vector.ConvertToUInt32(f2 * 255f);
Vector<uint> w3 = Vector.ConvertToUInt32(f3 * 255f);
Vector<ushort> u0 = Vector.Narrow(w0, w1);
Vector<ushort> u1 = Vector.Narrow(w2, w3);
Vector<byte> b = Vector.Narrow(u0, u1);
Unsafe.Add(ref destBase, i) = b;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Vector<float> Clamp(Vector<float> x)
{
return Vector.Min(Vector.Max(x, Vector<float>.Zero), Vector<float>.One);
}
}
}
}

18
tests/ImageSharp.Tests/Common/SimdUtilsTests.cs

@ -226,6 +226,24 @@ namespace SixLabors.ImageSharp.Tests.Common
Assert.Equal(expected, result, new ApproximateFloatComparer(1e-5f));
}
[Theory]
[InlineData(1, 0)]
[InlineData(2, 32)]
[InlineData(3, 128)]
public void ExtendedIntrinsics_BulkConvertNormalizedFloatToByteClampOverflows(int seed, int count)
{
float[] orig = new Random(seed).GenerateRandomRoundedFloatArray(count, -50, 444);
float[] normalized = orig.Select(f => f / 255f).ToArray();
byte[] dest = new byte[count];
SimdUtils.ExtendedIntrinsics.BulkConvertNormalizedFloatToByteClampOverflows(normalized, dest);
byte[] expected = orig.Select(f => (byte)Clamp255(f)).ToArray();
Assert.Equal(expected, dest);
}
[Theory]
[InlineData(0)]
[InlineData(7)]

Loading…
Cancel
Save