Browse Source

Merge branch 'master' into sp/refactoring-and-tweaks-2

pull/1122/head
Sergio Pedri 6 years ago
committed by GitHub
parent
commit
687d13a7ef
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 30
      src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs
  2. 112
      src/ImageSharp/Common/Tuples/Octet.cs
  3. 73
      src/ImageSharp/Common/Tuples/Octet{T}.cs
  4. 10
      tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Bgra32.cs
  5. 4
      tests/ImageSharp.Benchmarks/General/Vectorization/WidenBytesToUInt32.cs

30
src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs

@ -94,17 +94,17 @@ namespace SixLabors.ImageSharp
var magicInt = new Vector<uint>(1191182336); // reinterpreted value of 32768.0f
var mask = new Vector<uint>(255);
ref Octet.OfByte sourceBase = ref Unsafe.As<byte, Octet.OfByte>(ref MemoryMarshal.GetReference(source));
ref Octet.OfUInt32 destBaseAsWideOctet = ref Unsafe.As<float, Octet.OfUInt32>(ref MemoryMarshal.GetReference(dest));
ref Octet<byte> sourceBase = ref Unsafe.As<byte, Octet<byte>>(ref MemoryMarshal.GetReference(source));
ref Octet<uint> destBaseAsWideOctet = ref Unsafe.As<float, Octet<uint>>(ref MemoryMarshal.GetReference(dest));
ref Vector<float> destBaseAsFloat = ref Unsafe.As<Octet.OfUInt32, Vector<float>>(ref destBaseAsWideOctet);
ref Vector<float> destBaseAsFloat = ref Unsafe.As<Octet<uint>, Vector<float>>(ref destBaseAsWideOctet);
int n = dest.Length / 8;
for (int i = 0; i < n; i++)
{
ref Octet.OfByte s = ref Unsafe.Add(ref sourceBase, i);
ref Octet.OfUInt32 d = ref Unsafe.Add(ref destBaseAsWideOctet, i);
ref Octet<byte> s = ref Unsafe.Add(ref sourceBase, i);
ref Octet<uint> d = ref Unsafe.Add(ref destBaseAsWideOctet, i);
d.LoadFrom(ref s);
}
@ -137,17 +137,17 @@ namespace SixLabors.ImageSharp
}
ref Vector<float> srcBase = ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(source));
ref Octet.OfByte destBase = ref Unsafe.As<byte, Octet.OfByte>(ref MemoryMarshal.GetReference(dest));
ref Octet<byte> destBase = ref Unsafe.As<byte, Octet<byte>>(ref MemoryMarshal.GetReference(dest));
int n = source.Length / 8;
var magick = new Vector<float>(32768.0f);
var scale = new Vector<float>(255f) / new Vector<float>(256f);
// need to copy to a temporary struct, because
// SimdUtils.Octet.OfUInt32 temp = Unsafe.As<Vector<float>, SimdUtils.Octet.OfUInt32>(ref x)
// SimdUtils.Octet<uint> temp = Unsafe.As<Vector<float>, SimdUtils.Octet<uint>>(ref x)
// does not work. TODO: This might be a CoreClr bug, need to ask/report
var temp = default(Octet.OfUInt32);
ref Vector<float> tempRef = ref Unsafe.As<Octet.OfUInt32, Vector<float>>(ref temp);
var temp = default(Octet<uint>);
ref Vector<float> tempRef = ref Unsafe.As<Octet<uint>, Vector<float>>(ref temp);
for (int i = 0; i < n; i++)
{
@ -161,7 +161,7 @@ namespace SixLabors.ImageSharp
x = (x * scale) + magick;
tempRef = x;
ref Octet.OfByte d = ref Unsafe.Add(ref destBase, i);
ref Octet<byte> d = ref Unsafe.Add(ref destBase, i);
d.LoadFrom(ref temp);
}
}
@ -186,17 +186,17 @@ namespace SixLabors.ImageSharp
}
ref Vector<float> srcBase = ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(source));
ref Octet.OfByte destBase = ref Unsafe.As<byte, Octet.OfByte>(ref MemoryMarshal.GetReference(dest));
ref Octet<byte> destBase = ref Unsafe.As<byte, Octet<byte>>(ref MemoryMarshal.GetReference(dest));
int n = source.Length / 8;
var magick = new Vector<float>(32768.0f);
var scale = new Vector<float>(255f) / new Vector<float>(256f);
// need to copy to a temporary struct, because
// SimdUtils.Octet.OfUInt32 temp = Unsafe.As<Vector<float>, SimdUtils.Octet.OfUInt32>(ref x)
// SimdUtils.Octet<uint> temp = Unsafe.As<Vector<float>, SimdUtils.Octet<uint>>(ref x)
// does not work. TODO: This might be a CoreClr bug, need to ask/report
var temp = default(Octet.OfUInt32);
ref Vector<float> tempRef = ref Unsafe.As<Octet.OfUInt32, Vector<float>>(ref temp);
var temp = default(Octet<uint>);
ref Vector<float> tempRef = ref Unsafe.As<Octet<uint>, Vector<float>>(ref temp);
for (int i = 0; i < n; i++)
{
@ -207,7 +207,7 @@ namespace SixLabors.ImageSharp
x = (x * scale) + magick;
tempRef = x;
ref Octet.OfByte d = ref Unsafe.Add(ref destBase, i);
ref Octet<byte> d = ref Unsafe.Add(ref destBase, i);
d.LoadFrom(ref temp);
}
}

112
src/ImageSharp/Common/Tuples/Octet.cs

@ -1,112 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.Tuples
{
/// <summary>
/// Contains 8 element value tuples of various types.
/// </summary>
internal static class Octet
{
/// <summary>
/// Value tuple of <see cref="uint"/>-s.
/// </summary>
[StructLayout(LayoutKind.Explicit, Size = 8 * sizeof(uint))]
public struct OfUInt32
{
[FieldOffset(0 * sizeof(uint))]
public uint V0;
[FieldOffset(1 * sizeof(uint))]
public uint V1;
[FieldOffset(2 * sizeof(uint))]
public uint V2;
[FieldOffset(3 * sizeof(uint))]
public uint V3;
[FieldOffset(4 * sizeof(uint))]
public uint V4;
[FieldOffset(5 * sizeof(uint))]
public uint V5;
[FieldOffset(6 * sizeof(uint))]
public uint V6;
[FieldOffset(7 * sizeof(uint))]
public uint V7;
public override string ToString()
{
return $"{nameof(Octet)}.{nameof(OfUInt32)}({this.V0},{this.V1},{this.V2},{this.V3},{this.V4},{this.V5},{this.V6},{this.V7})";
}
[MethodImpl(InliningOptions.ShortMethod)]
public void LoadFrom(ref OfByte src)
{
this.V0 = src.V0;
this.V1 = src.V1;
this.V2 = src.V2;
this.V3 = src.V3;
this.V4 = src.V4;
this.V5 = src.V5;
this.V6 = src.V6;
this.V7 = src.V7;
}
}
/// <summary>
/// Value tuple of <see cref="byte"/>-s
/// </summary>
[StructLayout(LayoutKind.Explicit, Size = 8)]
public struct OfByte
{
[FieldOffset(0)]
public byte V0;
[FieldOffset(1)]
public byte V1;
[FieldOffset(2)]
public byte V2;
[FieldOffset(3)]
public byte V3;
[FieldOffset(4)]
public byte V4;
[FieldOffset(5)]
public byte V5;
[FieldOffset(6)]
public byte V6;
[FieldOffset(7)]
public byte V7;
public override string ToString()
{
return $"{nameof(Octet)}.{nameof(OfByte)}({this.V0},{this.V1},{this.V2},{this.V3},{this.V4},{this.V5},{this.V6},{this.V7})";
}
[MethodImpl(InliningOptions.ShortMethod)]
public void LoadFrom(ref OfUInt32 src)
{
this.V0 = (byte)src.V0;
this.V1 = (byte)src.V1;
this.V2 = (byte)src.V2;
this.V3 = (byte)src.V3;
this.V4 = (byte)src.V4;
this.V5 = (byte)src.V5;
this.V6 = (byte)src.V6;
this.V7 = (byte)src.V7;
}
}
}
}

73
src/ImageSharp/Common/Tuples/Octet{T}.cs

@ -0,0 +1,73 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.Tuples
{
/// <summary>
/// Contains 8 element value tuples of various types.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
internal struct Octet<T>
where T : unmanaged
{
public T V0;
public T V1;
public T V2;
public T V3;
public T V4;
public T V5;
public T V6;
public T V7;
/// <inheritdoc/>
public override readonly string ToString()
{
return $"Octet<{typeof(T)}>({this.V0},{this.V1},{this.V2},{this.V3},{this.V4},{this.V5},{this.V6},{this.V7})";
}
}
/// <summary>
/// Extension methods for the <see cref="Octet{T}"/> type.
/// </summary>
internal static class OctetExtensions
{
/// <summary>
/// Loads the fields in a target <see cref="Octet{T}"/> of <see cref="uint"/> from one of <see cref="byte"/> type.
/// </summary>
/// <param name="destination">The target <see cref="Octet{T}"/> of <see cref="uint"/> instance.</param>
/// <param name="source">The source <see cref="Octet{T}"/> of <see cref="byte"/> instance.</param>
[MethodImpl(InliningOptions.ShortMethod)]
public static void LoadFrom(ref this Octet<uint> destination, ref Octet<byte> source)
{
destination.V0 = source.V0;
destination.V1 = source.V1;
destination.V2 = source.V2;
destination.V3 = source.V3;
destination.V4 = source.V4;
destination.V5 = source.V5;
destination.V6 = source.V6;
destination.V7 = source.V7;
}
/// <summary>
/// Loads the fields in a target <see cref="Octet{T}"/> of <see cref="byte"/> from one of <see cref="uint"/> type.
/// </summary>
/// <param name="destination">The target <see cref="Octet{T}"/> of <see cref="byte"/> instance.</param>
/// <param name="source">The source <see cref="Octet{T}"/> of <see cref="uint"/> instance.</param>
[MethodImpl(InliningOptions.ShortMethod)]
public static void LoadFrom(ref this Octet<byte> destination, ref Octet<uint> source)
{
destination.V0 = (byte)source.V0;
destination.V1 = (byte)source.V1;
destination.V2 = (byte)source.V2;
destination.V3 = (byte)source.V3;
destination.V4 = (byte)source.V4;
destination.V5 = (byte)source.V5;
destination.V6 = (byte)source.V6;
destination.V7 = (byte)source.V7;
}
}
}

10
tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Bgra32.cs

@ -233,8 +233,8 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion
// [Benchmark]
public void Bitops_Simd()
{
ref Octet.OfUInt32 sBase = ref Unsafe.As<Rgba32, Octet.OfUInt32>(ref this.source[0]);
ref Octet.OfUInt32 dBase = ref Unsafe.As<Bgra32, Octet.OfUInt32>(ref this.dest[0]);
ref Octet<uint> sBase = ref Unsafe.As<Rgba32, Octet<uint>>(ref this.source[0]);
ref Octet<uint> dBase = ref Unsafe.As<Bgra32, Octet<uint>>(ref this.dest[0]);
for (int i = 0; i < this.Count / 8; i++)
{
@ -257,9 +257,9 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion
#pragma warning restore SA1132 // Do not combine fields
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void BitopsSimdImpl(ref Octet.OfUInt32 s, ref Octet.OfUInt32 d)
private static void BitopsSimdImpl(ref Octet<uint> s, ref Octet<uint> d)
{
Vector<uint> sVec = Unsafe.As<Octet.OfUInt32, Vector<uint>>(ref s);
Vector<uint> sVec = Unsafe.As<Octet<uint>, Vector<uint>>(ref s);
var aMask = new Vector<uint>(0xFF00FF00);
var bMask = new Vector<uint>(0x00FF00FF);
@ -282,7 +282,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion
Vector<uint> cc = Unsafe.As<C, Vector<uint>>(ref c);
Vector<uint> dd = aa + cc;
d = Unsafe.As<Vector<uint>, Octet.OfUInt32>(ref dd);
d = Unsafe.As<Vector<uint>, Octet<uint>>(ref dd);
}
// [Benchmark]

4
tests/ImageSharp.Benchmarks/General/Vectorization/WidenBytesToUInt32.cs

@ -31,8 +31,8 @@ namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization
{
const int N = Count / 8;
ref Octet.OfByte sBase = ref Unsafe.As<byte, Octet.OfByte>(ref this.source[0]);
ref Octet.OfUInt32 dBase = ref Unsafe.As<uint, Octet.OfUInt32>(ref this.dest[0]);
ref Octet<byte> sBase = ref Unsafe.As<byte, Octet<byte>>(ref this.source[0]);
ref Octet<uint> dBase = ref Unsafe.As<uint, Octet<uint>>(ref this.dest[0]);
for (int i = 0; i < N; i++)
{

Loading…
Cancel
Save