Browse Source

Color.BulkOperations full implementation

pull/126/head
Anton Firszov 9 years ago
parent
commit
ebb581b3f6
  1. 109
      src/ImageSharp/Colors/Color.BulkOperations.cs
  2. 19
      src/ImageSharp/Common/Memory/BufferPointer.cs
  3. 4
      src/ImageSharp/Common/Memory/BufferPointer{T}.cs
  4. 22
      src/ImageSharp/Common/Memory/PinnedBuffer{T}.cs
  5. 59
      tests/ImageSharp.Tests/Common/BufferPointerTests.cs

109
src/ImageSharp/Colors/Color.BulkOperations.cs

@ -125,6 +125,115 @@ namespace ImageSharp
base.ToVector4(sourceColors, destVectors, remainder);
}
}
/// <inheritdoc />
internal override unsafe void PackFromXyzBytes(BufferPointer<byte> sourceBytes, BufferPointer<Color> destColors, int count)
{
byte* source = (byte*)sourceBytes;
byte* destination = (byte*)destColors;
for (int x = 0; x < count; x++)
{
Unsafe.Write(destination, (uint)(*source << 0 | *(source + 1) << 8 | *(source + 2) << 16 | 255 << 24));
source += 3;
destination += 4;
}
}
/// <inheritdoc />
internal override unsafe void ToXyzBytes(BufferPointer<Color> sourceColors, BufferPointer<byte> destBytes, int count)
{
byte* source = (byte*)sourceColors;
byte* destination = (byte*)destBytes;
for (int x = 0; x < count; x++)
{
*destination = *(source + 0);
*(destination + 1) = *(source + 1);
*(destination + 2) = *(source + 2);
source += 4;
destination += 3;
}
}
/// <inheritdoc />
internal override void PackFromXyzwBytes(BufferPointer<byte> sourceBytes, BufferPointer<Color> destColors, int count)
{
BufferPointer.Copy(sourceBytes, destColors, count);
}
/// <inheritdoc />
internal override void ToXyzwBytes(BufferPointer<Color> sourceColors, BufferPointer<byte> destBytes, int count)
{
BufferPointer.Copy(sourceColors, destBytes, count);
}
/// <inheritdoc />
internal override unsafe void PackFromZyxBytes(BufferPointer<byte> sourceBytes, BufferPointer<Color> destColors, int count)
{
byte* source = (byte*)sourceBytes;
byte* destination = (byte*)destColors;
for (int x = 0; x < count; x++)
{
Unsafe.Write(destination, (uint)(*(source + 2) << 0 | *(source + 1) << 8 | *source << 16 | 255 << 24));
source += 3;
destination += 4;
}
}
/// <inheritdoc />
internal override unsafe void ToZyxBytes(BufferPointer<Color> sourceColors, BufferPointer<byte> destBytes, int count)
{
byte* source = (byte*)sourceColors;
byte* destination = (byte*)destBytes;
for (int x = 0; x < count; x++)
{
*destination = *(source + 2);
*(destination + 1) = *(source + 1);
*(destination + 2) = *(source + 0);
source += 4;
destination += 3;
}
}
/// <inheritdoc />
internal override unsafe void PackFromZyxwBytes(BufferPointer<byte> sourceBytes, BufferPointer<Color> destColors, int count)
{
byte* source = (byte*)sourceBytes;
byte* destination = (byte*)destColors;
for (int x = 0; x < count; x++)
{
Unsafe.Write(destination, (uint)(*(source + 2) << 0 | *(source + 1) << 8 | *source << 16 | *(source + 3) << 24));
source += 4;
destination += 4;
}
}
/// <inheritdoc />
internal override unsafe void ToZyxwBytes(BufferPointer<Color> sourceColors, BufferPointer<byte> destBytes, int count)
{
byte* source = (byte*)sourceColors;
byte* destination = (byte*)destBytes;
for (int x = 0; x < count; x++)
{
*destination = *(source + 2);
*(destination + 1) = *(source + 1);
*(destination + 2) = *(source + 0);
*(destination + 3) = *(source + 3);
source += 4;
destination += 4;
}
}
}
}
}

19
src/ImageSharp/Common/Memory/BufferPointer.cs

@ -12,18 +12,7 @@ namespace ImageSharp
/// </summary>
internal static class BufferPointer
{
/// <summary>
/// Gets a <see cref="BufferPointer{T}"/> to the beginning of the raw data in 'buffer'.
/// </summary>
/// <typeparam name="T">The element type</typeparam>
/// <param name="buffer">The input <see cref="PinnedBuffer{T}"/></param>
/// <returns>The <see cref="BufferPointer{T}"/></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe BufferPointer<T> Slice<T>(this PinnedBuffer<T> buffer)
where T : struct
{
return new BufferPointer<T>(buffer.Array, (void*)buffer.Pointer);
}
/// <summary>
/// Copy 'count' number of elements of the same type from 'source' to 'dest'
@ -36,7 +25,7 @@ namespace ImageSharp
public static unsafe void Copy<T>(BufferPointer<T> source, BufferPointer<T> destination, int count)
where T : struct
{
Unsafe.CopyBlock((void*)source.PointerAtOffset, (void*)destination.PointerAtOffset, USizeOf<T>(count));
Unsafe.CopyBlock((void*)destination.PointerAtOffset, (void*)source.PointerAtOffset, USizeOf<T>(count));
}
/// <summary>
@ -50,7 +39,7 @@ namespace ImageSharp
public static unsafe void Copy<T>(BufferPointer<T> source, BufferPointer<byte> destination, int countInSource)
where T : struct
{
Unsafe.CopyBlock((void*)source.PointerAtOffset, (void*)destination.PointerAtOffset, USizeOf<T>(countInSource));
Unsafe.CopyBlock((void*)destination.PointerAtOffset, (void*)source.PointerAtOffset, USizeOf<T>(countInSource));
}
/// <summary>
@ -64,7 +53,7 @@ namespace ImageSharp
public static unsafe void Copy<T>(BufferPointer<byte> source, BufferPointer<T> destination, int countInDest)
where T : struct
{
Unsafe.CopyBlock((void*)source.PointerAtOffset, (void*)destination.PointerAtOffset, USizeOf<T>(countInDest));
Unsafe.CopyBlock((void*)destination.PointerAtOffset, (void*)source.PointerAtOffset, USizeOf<T>(countInDest));
}
/// <summary>

4
src/ImageSharp/Common/Memory/BufferPointer{T}.cs

@ -79,7 +79,7 @@ namespace ImageSharp
}
/// <summary>
/// Convertes <see cref="BufferPointer{T}"/> instance to a raw 'byte*' pointer
/// Converts <see cref="BufferPointer{T}"/> instance to a raw 'byte*' pointer
/// </summary>
/// <param name="bufferPointer">The <see cref="BufferPointer{T}"/> to convert</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@ -87,7 +87,7 @@ namespace ImageSharp
{
return (byte*)bufferPointer.PointerAtOffset;
}
/// <summary>
/// Forms a slice out of the given BufferPointer, beginning at 'offset'.
/// </summary>

22
src/ImageSharp/Common/Memory/PinnedBuffer{T}.cs

@ -7,6 +7,7 @@ namespace ImageSharp
{
using System;
using System.Buffers;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
/// <summary>
@ -94,6 +95,27 @@ namespace ImageSharp
/// Gets a pointer to the pinned <see cref="Array"/>.
/// </summary>
public IntPtr Pointer { get; private set; }
/// <summary>
/// Converts <see cref="PinnedBuffer{T}"/> to an <see cref="BufferPointer{T}"/>.
/// </summary>
/// <param name="buffer">The <see cref="PinnedBuffer{T}"/> to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator BufferPointer<T>(PinnedBuffer<T> buffer)
{
return buffer.Slice();
}
/// <summary>
/// Gets a <see cref="BufferPointer{T}"/> to the beginning of the raw data in 'buffer'.
/// </summary>
/// <typeparam name="T">The element type</typeparam>
/// <returns>The <see cref="BufferPointer{T}"/></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe BufferPointer<T> Slice()
{
return new BufferPointer<T>(this.Array, (void*)this.Pointer);
}
/// <summary>
/// Disposes the <see cref="PinnedBuffer{T}"/> instance by unpinning the array, and returning the pooled buffer when necessary.

59
tests/ImageSharp.Tests/Common/BufferPointerTests.cs

@ -15,12 +15,18 @@ namespace ImageSharp.Tests.Common
public double B;
public Foo(int a, double b)
{
this.A = a;
this.B = b;
}
internal static Foo[] CreateArray(int size)
{
Foo[] result = new Foo[size];
for (int i = 0; i < size; i++)
{
result[i] = new Foo() { A = i, B = i };
result[i] = new Foo(i, i);
}
return result;
}
@ -81,6 +87,12 @@ namespace ImageSharp.Tests.Common
public class Copy
{
private static void AssertNotDefault<T>(T[] data, int idx)
where T : struct
{
Assert.NotEqual(default(T), data[idx]);
}
[Theory]
[InlineData(4)]
[InlineData(1500)]
@ -98,7 +110,11 @@ namespace ImageSharp.Tests.Common
BufferPointer.Copy(apSource, apDest, count);
}
AssertNotDefault(source, 1);
AssertNotDefault(dest, 1);
Assert.Equal(source[0], dest[0]);
Assert.Equal(source[1], dest[1]);
Assert.Equal(source[count-1], dest[count-1]);
Assert.NotEqual(source[count], dest[count]);
}
@ -121,19 +137,31 @@ namespace ImageSharp.Tests.Common
BufferPointer.Copy(apSource, apDest, count);
}
AssertNotDefault(source, 1);
Assert.True(ElementsAreEqual(source, dest, 0));
Assert.True(ElementsAreEqual(source, dest, count - 1));
Assert.False(ElementsAreEqual(source, dest, count));
}
private static byte[] CreateTestBytes(int count)
{
byte[] result = new byte[count];
for (int i = 0; i < result.Length; i++)
{
result[i] = (byte)(i % 255);
}
return result;
}
[Theory]
[InlineData(4)]
[InlineData(1500)]
public void BytesToGeneric(int count)
{
int destCount = count * sizeof(Foo);
byte[] source = new byte[destCount + sizeof(Foo) + 1];
Foo[] dest = Foo.CreateArray(count + 2);
int srcCount = count * sizeof(Foo);
byte[] source = CreateTestBytes(srcCount);
Foo[] dest = new Foo[count + 2];
fixed(byte* pSource = source)
fixed (Foo* pDest = dest)
@ -144,10 +172,33 @@ namespace ImageSharp.Tests.Common
BufferPointer.Copy(apSource, apDest, count);
}
AssertNotDefault(source, sizeof(Foo) + 1);
AssertNotDefault(dest, 1);
Assert.True(ElementsAreEqual(dest, source, 0));
Assert.True(ElementsAreEqual(dest, source, 1));
Assert.True(ElementsAreEqual(dest, source, count - 1));
Assert.False(ElementsAreEqual(dest, source, count));
}
[Fact]
public void ColorToBytes()
{
Color[] colors = { new Color(0, 1, 2, 3), new Color(4, 5, 6, 7), new Color(8, 9, 10, 11), };
using (PinnedBuffer<Color> colorBuf = new PinnedBuffer<Color>(colors))
using (PinnedBuffer<byte> byteBuf = new PinnedBuffer<byte>(colors.Length*4))
{
BufferPointer.Copy<Color>(colorBuf, byteBuf, colorBuf.Count);
byte[] a = byteBuf.Array;
for (int i = 0; i < byteBuf.Count; i++)
{
Assert.Equal((byte)i, a[i]);
}
}
}
private static bool ElementsAreEqual(Foo[] array, byte[] rawArray, int index)
{

Loading…
Cancel
Save