Browse Source

BulkPixelOperations<T> skeleton

pull/125/head
Anton Firszov 9 years ago
parent
commit
a52f6bf1b5
  1. 3
      src/ImageSharp/Colors/Color.cs
  2. 3
      src/ImageSharp/Colors/PackedPixel/Alpha8.cs
  3. 3
      src/ImageSharp/Colors/PackedPixel/Argb.cs
  4. 3
      src/ImageSharp/Colors/PackedPixel/Bgr565.cs
  5. 3
      src/ImageSharp/Colors/PackedPixel/Bgra4444.cs
  6. 3
      src/ImageSharp/Colors/PackedPixel/Bgra5551.cs
  7. 56
      src/ImageSharp/Colors/PackedPixel/BulkPixelOperations.cs
  8. 3
      src/ImageSharp/Colors/PackedPixel/Byte4.cs
  9. 3
      src/ImageSharp/Colors/PackedPixel/HalfSingle.cs
  10. 3
      src/ImageSharp/Colors/PackedPixel/HalfVector2.cs
  11. 3
      src/ImageSharp/Colors/PackedPixel/HalfVector4.cs
  12. 4
      src/ImageSharp/Colors/PackedPixel/IPixel.cs
  13. 3
      src/ImageSharp/Colors/PackedPixel/NormalizedByte2.cs
  14. 3
      src/ImageSharp/Colors/PackedPixel/NormalizedByte4.cs
  15. 3
      src/ImageSharp/Colors/PackedPixel/NormalizedShort2.cs
  16. 3
      src/ImageSharp/Colors/PackedPixel/NormalizedShort4.cs
  17. 3
      src/ImageSharp/Colors/PackedPixel/Rg32.cs
  18. 3
      src/ImageSharp/Colors/PackedPixel/Rgba1010102.cs
  19. 3
      src/ImageSharp/Colors/PackedPixel/Rgba64.cs
  20. 3
      src/ImageSharp/Colors/PackedPixel/Short2.cs
  21. 3
      src/ImageSharp/Colors/PackedPixel/Short4.cs
  22. 50
      src/ImageSharp/Common/Memory/ArrayPointer.cs
  23. 25
      tests/ImageSharp.Benchmarks/General/ArrayCopy.cs
  24. 104
      tests/ImageSharp.Tests/Colors/BulkPixelOperationsTests.cs
  25. 94
      tests/ImageSharp.Tests/Common/ArrayPointerTests.cs

3
src/ImageSharp/Colors/Color.cs

@ -112,6 +112,9 @@ namespace ImageSharp
this.packedValue = packed;
}
/// <inheritdoc />
public BulkPixelOperations<Color> BulkOperations => new BulkPixelOperations<Color>();
/// <summary>
/// Gets or sets the red component.
/// </summary>

3
src/ImageSharp/Colors/PackedPixel/Alpha8.cs

@ -26,6 +26,9 @@ namespace ImageSharp
/// <inheritdoc />
public byte PackedValue { get; set; }
/// <inheritdoc />
public BulkPixelOperations<Alpha8> BulkOperations => new BulkPixelOperations<Alpha8>();
/// <summary>
/// Compares two <see cref="Alpha8"/> objects for equality.
/// </summary>

3
src/ImageSharp/Colors/PackedPixel/Argb.cs

@ -109,6 +109,9 @@ namespace ImageSharp
/// <inheritdoc/>
public uint PackedValue { get; set; }
/// <inheritdoc />
public BulkPixelOperations<Argb> BulkOperations => new BulkPixelOperations<Argb>();
/// <summary>
/// Gets or sets the red component.
/// </summary>

3
src/ImageSharp/Colors/PackedPixel/Bgr565.cs

@ -39,6 +39,9 @@ namespace ImageSharp
/// <inheritdoc/>
public ushort PackedValue { get; set; }
/// <inheritdoc />
public BulkPixelOperations<Bgr565> BulkOperations => new BulkPixelOperations<Bgr565>();
/// <summary>
/// Compares two <see cref="Bgr565"/> objects for equality.
/// </summary>

3
src/ImageSharp/Colors/PackedPixel/Bgra4444.cs

@ -38,6 +38,9 @@ namespace ImageSharp
/// <inheritdoc/>
public ushort PackedValue { get; set; }
/// <inheritdoc />
public BulkPixelOperations<Bgra4444> BulkOperations => new BulkPixelOperations<Bgra4444>();
/// <summary>
/// Compares two <see cref="Bgra4444"/> objects for equality.
/// </summary>

3
src/ImageSharp/Colors/PackedPixel/Bgra5551.cs

@ -40,6 +40,9 @@ namespace ImageSharp
/// <inheritdoc/>
public ushort PackedValue { get; set; }
/// <inheritdoc />
public BulkPixelOperations<Bgra5551> BulkOperations => new BulkPixelOperations<Bgra5551>();
/// <summary>
/// Compares two <see cref="Bgra5551"/> objects for equality.
/// </summary>

56
src/ImageSharp/Colors/PackedPixel/BulkPixelOperations.cs

@ -0,0 +1,56 @@
namespace ImageSharp
{
using System.Numerics;
public unsafe class BulkPixelOperations<TColor>
where TColor : struct, IPixel<TColor>
{
public static BulkPixelOperations<TColor> Instance { get; } = default(TColor).BulkOperations;
internal virtual void PackFromVector4(
ArrayPointer<Vector4> sourceVectors,
ArrayPointer<TColor> destColors,
int count)
{
}
internal virtual void PackToVector4(
ArrayPointer<TColor> sourceColors,
ArrayPointer<Vector4> destVectors,
int count)
{
}
internal virtual void PackToXyzBytes(ArrayPointer<TColor> sourceColors, ArrayPointer<byte> destBytes, int count)
{
}
internal virtual void PackFromXyzBytes(ArrayPointer<byte> sourceBytes, ArrayPointer<TColor> destColors, int count)
{
}
internal virtual void PackToXyzwBytes(ArrayPointer<TColor> sourceColors, ArrayPointer<byte> destBytes, int count)
{
}
internal virtual void PackFromXyzwBytes(ArrayPointer<byte> sourceBytes, ArrayPointer<TColor> destColors, int count)
{
}
internal virtual void PackToZyxBytes(ArrayPointer<TColor> sourceColors, ArrayPointer<byte> destBytes, int count)
{
}
internal virtual void PackFromZyxBytes(ArrayPointer<byte> sourceBytes, ArrayPointer<TColor> destColors, int count)
{
}
internal virtual void PackToZyxwBytes(ArrayPointer<TColor> sourceColors, ArrayPointer<byte> destBytes, int count)
{
}
internal virtual void PackFromZyxwBytes(ArrayPointer<byte> sourceBytes, ArrayPointer<TColor> destColors, int count)
{
}
}
}

3
src/ImageSharp/Colors/PackedPixel/Byte4.cs

@ -41,6 +41,9 @@ namespace ImageSharp
/// <inheritdoc/>
public uint PackedValue { get; set; }
/// <inheritdoc />
public BulkPixelOperations<Byte4> BulkOperations => new BulkPixelOperations<Byte4>();
/// <summary>
/// Compares two <see cref="Byte4"/> objects for equality.
/// </summary>

3
src/ImageSharp/Colors/PackedPixel/HalfSingle.cs

@ -36,6 +36,9 @@ namespace ImageSharp
/// <inheritdoc/>
public ushort PackedValue { get; set; }
/// <inheritdoc />
public BulkPixelOperations<HalfSingle> BulkOperations => new BulkPixelOperations<HalfSingle>();
/// <summary>
/// Compares two <see cref="HalfSingle"/> objects for equality.
/// </summary>

3
src/ImageSharp/Colors/PackedPixel/HalfVector2.cs

@ -45,6 +45,9 @@ namespace ImageSharp
/// <inheritdoc/>
public uint PackedValue { get; set; }
/// <inheritdoc />
public BulkPixelOperations<HalfVector2> BulkOperations => new BulkPixelOperations<HalfVector2>();
/// <summary>
/// Compares two <see cref="HalfVector2"/> objects for equality.

3
src/ImageSharp/Colors/PackedPixel/HalfVector4.cs

@ -49,6 +49,9 @@ namespace ImageSharp
/// <inheritdoc/>
public ulong PackedValue { get; set; }
/// <inheritdoc />
public BulkPixelOperations<HalfVector4> BulkOperations => new BulkPixelOperations<HalfVector4>();
/// <summary>
/// Compares two <see cref="HalfVector2"/> objects for equality.
/// </summary>

4
src/ImageSharp/Colors/PackedPixel/IPixel.cs

@ -15,6 +15,10 @@ namespace ImageSharp
public interface IPixel<TSelf> : IPixel, IEquatable<TSelf>
where TSelf : struct, IPixel<TSelf>
{
/// <summary>
/// Gets the <see cref="BulkPixelOperations{TColor}"/> instance for this pixel type.
/// </summary>
BulkPixelOperations<TSelf> BulkOperations { get; }
}
/// <summary>

3
src/ImageSharp/Colors/PackedPixel/NormalizedByte2.cs

@ -51,6 +51,9 @@ namespace ImageSharp
/// <inheritdoc/>
public ushort PackedValue { get; set; }
/// <inheritdoc />
public BulkPixelOperations<NormalizedByte2> BulkOperations => new BulkPixelOperations<NormalizedByte2>();
/// <summary>
/// Compares two <see cref="NormalizedByte2"/> objects for equality.
/// </summary>

3
src/ImageSharp/Colors/PackedPixel/NormalizedByte4.cs

@ -52,6 +52,9 @@ namespace ImageSharp
/// <inheritdoc/>
public uint PackedValue { get; set; }
/// <inheritdoc />
public BulkPixelOperations<NormalizedByte4> BulkOperations => new BulkPixelOperations<NormalizedByte4>();
/// <summary>
/// Compares two <see cref="NormalizedByte4"/> objects for equality.

3
src/ImageSharp/Colors/PackedPixel/NormalizedShort2.cs

@ -51,6 +51,9 @@ namespace ImageSharp
/// <inheritdoc/>
public uint PackedValue { get; set; }
/// <inheritdoc />
public BulkPixelOperations<NormalizedShort2> BulkOperations => new BulkPixelOperations<NormalizedShort2>();
/// <summary>
/// Compares two <see cref="NormalizedShort2"/> objects for equality.
/// </summary>

3
src/ImageSharp/Colors/PackedPixel/NormalizedShort4.cs

@ -53,6 +53,9 @@ namespace ImageSharp
/// <inheritdoc/>
public ulong PackedValue { get; set; }
/// <inheritdoc />
public BulkPixelOperations<NormalizedShort4> BulkOperations => new BulkPixelOperations<NormalizedShort4>();
/// <summary>
/// Compares two <see cref="NormalizedShort4"/> objects for equality.
/// </summary>

3
src/ImageSharp/Colors/PackedPixel/Rg32.cs

@ -36,6 +36,9 @@ namespace ImageSharp
/// <inheritdoc/>
public uint PackedValue { get; set; }
/// <inheritdoc />
public BulkPixelOperations<Rg32> BulkOperations => new BulkPixelOperations<Rg32>();
/// <summary>
/// Compares two <see cref="Rg32"/> objects for equality.
/// </summary>

3
src/ImageSharp/Colors/PackedPixel/Rgba1010102.cs

@ -39,6 +39,9 @@ namespace ImageSharp
/// <inheritdoc/>
public uint PackedValue { get; set; }
/// <inheritdoc />
public BulkPixelOperations<Rgba1010102> BulkOperations => new BulkPixelOperations<Rgba1010102>();
/// <summary>
/// Compares two <see cref="Rgba1010102"/> objects for equality.
/// </summary>

3
src/ImageSharp/Colors/PackedPixel/Rgba64.cs

@ -38,6 +38,9 @@ namespace ImageSharp
/// <inheritdoc/>
public ulong PackedValue { get; set; }
/// <inheritdoc />
public BulkPixelOperations<Rgba64> BulkOperations => new BulkPixelOperations<Rgba64>();
/// <summary>
/// Compares two <see cref="Rgba64"/> objects for equality.
/// </summary>

3
src/ImageSharp/Colors/PackedPixel/Short2.cs

@ -51,6 +51,9 @@ namespace ImageSharp
/// <inheritdoc/>
public uint PackedValue { get; set; }
/// <inheritdoc />
public BulkPixelOperations<Short2> BulkOperations => new BulkPixelOperations<Short2>();
/// <summary>
/// Compares two <see cref="Short2"/> objects for equality.
/// </summary>

3
src/ImageSharp/Colors/PackedPixel/Short4.cs

@ -53,6 +53,9 @@ namespace ImageSharp
/// <inheritdoc/>
public ulong PackedValue { get; set; }
/// <inheritdoc />
public BulkPixelOperations<Short4> BulkOperations => new BulkPixelOperations<Short4>();
/// <summary>
/// Compares two <see cref="Short4"/> objects for equality.
/// </summary>

50
src/ImageSharp/Common/Memory/ArrayPointer.cs

@ -0,0 +1,50 @@
namespace ImageSharp
{
using System.Runtime.CompilerServices;
/// <summary>
/// Utility methods to <see cref="ArrayPointer{T}"/>
/// </summary>
internal static class ArrayPointer
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe void Copy<T>(ArrayPointer<T> source, ArrayPointer<T> destination, int count)
where T : struct
{
Unsafe.CopyBlock((void*)source.PointerAtOffset, (void*)destination.PointerAtOffset, USizeOf<T>(count));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe void Copy<T>(ArrayPointer<T> source, ArrayPointer<byte> destination, int countInSource)
where T : struct
{
Unsafe.CopyBlock((void*)source.PointerAtOffset, (void*)destination.PointerAtOffset, USizeOf<T>(countInSource));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe void Copy<T>(ArrayPointer<byte> source, ArrayPointer<T> destination, int countInDest)
where T : struct
{
Unsafe.CopyBlock((void*)source.PointerAtOffset, (void*)destination.PointerAtOffset, USizeOf<T>(countInDest));
}
/// <summary>
/// Gets the size of `count` elements in bytes.
/// </summary>
/// <param name="count">The count of the elements</param>
/// <returns>The size in bytes as int</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int SizeOf<T>(int count)
where T : struct => Unsafe.SizeOf<T>() * count;
/// <summary>
/// Gets the size of `count` elements in bytes as UInt32
/// </summary>
/// <param name="count">The count of the elements</param>
/// <returns>The size in bytes as UInt32</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static uint USizeOf<T>(int count)
where T : struct
=> (uint)SizeOf<T>(count);
}
}

25
tests/ImageSharp.Benchmarks/General/ArrayCopy.cs

@ -2,22 +2,23 @@
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Benchmarks.General
{
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using BenchmarkDotNet.Attributes;
[Config(typeof(Config.Short))]
public class ArrayCopy
{
[Params(100, 1000, 10000)]
[Params(10, 100, 1000, 10000)]
public int Count { get; set; }
private byte[] source;
byte[] source;
private byte[] destination;
byte[] destination;
[Setup]
public void SetUp()
@ -42,6 +43,12 @@ namespace ImageSharp.Benchmarks.General
}
}
[Benchmark(Description = "Copy using Buffer.BlockCopy()")]
public void CopyUsingBufferBlockCopy()
{
Buffer.BlockCopy(this.source, 0, this.destination, 0, this.Count);
}
[Benchmark(Description = "Copy using Buffer.MemoryCopy<T>")]
public unsafe void CopyUsingBufferMemoryCopy()
{
@ -51,5 +58,15 @@ namespace ImageSharp.Benchmarks.General
Buffer.MemoryCopy(pinnedSource, pinnedDestination, this.Count, this.Count);
}
}
[Benchmark(Description = "Copy using Marshal.Copy<T>")]
public unsafe void CopyUsingMarshalCopy()
{
fixed (byte* pinnedDestination = this.destination)
{
Marshal.Copy(this.source, 0, (IntPtr)pinnedDestination, this.Count);
}
}
}
}

104
tests/ImageSharp.Tests/Colors/BulkPixelOperationsTests.cs

@ -0,0 +1,104 @@
namespace ImageSharp.Tests.Colors
{
using System;
using Xunit;
public class BulkPixelOperationsTests
{
public class TypeParam<TColor>
{
}
[Theory]
[InlineData(default(TypeParam<Color>))]
[InlineData(default(TypeParam<Argb>))]
public virtual void PackFromVector4<TColor>(TypeParam<TColor> dummy)
where TColor : struct, IPixel<TColor>
{
throw new NotImplementedException();
}
[Theory]
[InlineData(default(TypeParam<Color>))]
[InlineData(default(TypeParam<Argb>))]
public virtual void PackToVector4<TColor>(TypeParam<TColor> dummy)
where TColor : struct, IPixel<TColor>
{
throw new NotImplementedException();
}
[Theory]
[InlineData(default(TypeParam<Color>))]
[InlineData(default(TypeParam<Argb>))]
public virtual void PackToXyzBytes<TColor>(TypeParam<TColor> dummy)
where TColor : struct, IPixel<TColor>
{
throw new NotImplementedException();
}
[Theory]
[InlineData(default(TypeParam<Color>))]
[InlineData(default(TypeParam<Argb>))]
public virtual void PackFromXyzBytes<TColor>(TypeParam<TColor> dummy)
where TColor : struct, IPixel<TColor>
{
throw new NotImplementedException();
}
[Theory]
[InlineData(default(TypeParam<Color>))]
[InlineData(default(TypeParam<Argb>))]
public virtual void PackToXyzwBytes<TColor>(TypeParam<TColor> dummy)
where TColor : struct, IPixel<TColor>
{
throw new NotImplementedException();
}
[Theory]
[InlineData(default(TypeParam<Color>))]
[InlineData(default(TypeParam<Argb>))]
public virtual void PackFromXyzwBytes<TColor>(TypeParam<TColor> dummy)
where TColor : struct, IPixel<TColor>
{
throw new NotImplementedException();
}
[Theory]
[InlineData(default(TypeParam<Color>))]
[InlineData(default(TypeParam<Argb>))]
public virtual void PackToZyxBytes<TColor>(TypeParam<TColor> dummy)
where TColor : struct, IPixel<TColor>
{
throw new NotImplementedException();
}
[Theory]
[InlineData(default(TypeParam<Color>))]
[InlineData(default(TypeParam<Argb>))]
public virtual void PackFromZyxBytes<TColor>(TypeParam<TColor> dummy)
where TColor : struct, IPixel<TColor>
{
throw new NotImplementedException();
}
[Theory]
[InlineData(default(TypeParam<Color>))]
[InlineData(default(TypeParam<Argb>))]
public virtual void PackToZyxwBytes<TColor>(TypeParam<TColor> dummy)
where TColor : struct, IPixel<TColor>
{
throw new NotImplementedException();
}
[Theory]
[InlineData(default(TypeParam<Color>))]
[InlineData(default(TypeParam<Argb>))]
public virtual void PackFromZyxwBytes<TColor>(TypeParam<TColor> dummy)
where TColor : struct, IPixel<TColor>
{
throw new NotImplementedException();
}
}
}

94
tests/ImageSharp.Tests/Common/ArrayPointerTests.cs

@ -3,6 +3,7 @@
namespace ImageSharp.Tests.Common
{
using System;
using System.Runtime.CompilerServices;
using Xunit;
@ -10,18 +11,16 @@ namespace ImageSharp.Tests.Common
{
public struct Foo
{
#pragma warning disable CS0414
private int a;
public int A;
private double b;
#pragma warning restore CS0414
public double 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() { A = i, B = i };
}
return result;
}
@ -79,5 +78,90 @@ namespace ImageSharp.Tests.Common
Assert.Equal((IntPtr)(p + totalOffset), ap.PointerAtOffset);
}
}
public class Copy
{
[Theory]
[InlineData(4)]
[InlineData(1500)]
public void GenericToOwnType(int count)
{
Foo[] source = Foo.CreateArray(count + 2);
Foo[] dest = new Foo[count + 5];
fixed (Foo* pSource = source)
fixed (Foo* pDest = dest)
{
ArrayPointer<Foo> apSource = new ArrayPointer<Foo>(source, pSource);
ArrayPointer<Foo> apDest = new ArrayPointer<Foo>(dest, pDest);
ArrayPointer.Copy(apSource, apDest, count);
}
Assert.Equal(source[0], dest[0]);
Assert.Equal(source[count-1], dest[count-1]);
Assert.NotEqual(source[count], dest[count]);
}
[Theory]
[InlineData(4)]
[InlineData(1500)]
public void GenericToBytes(int count)
{
int destCount = count * sizeof(Foo);
Foo[] source = Foo.CreateArray(count + 2);
byte[] dest = new byte[destCount + sizeof(Foo) + 1];
fixed (Foo* pSource = source)
fixed (byte* pDest = dest)
{
ArrayPointer<Foo> apSource = new ArrayPointer<Foo>(source, pSource);
ArrayPointer<byte> apDest = new ArrayPointer<byte>(dest, pDest);
ArrayPointer.Copy(apSource, apDest, count);
}
Assert.True(ElementsAreEqual(source, dest, 0));
Assert.True(ElementsAreEqual(source, dest, count - 1));
Assert.False(ElementsAreEqual(source, dest, count));
}
[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);
fixed(byte* pSource = source)
fixed (Foo* pDest = dest)
{
ArrayPointer<byte> apSource = new ArrayPointer<byte>(source, pSource);
ArrayPointer<Foo> apDest = new ArrayPointer<Foo>(dest, pDest);
ArrayPointer.Copy(apSource, apDest, count);
}
Assert.True(ElementsAreEqual(dest, source, 0));
Assert.True(ElementsAreEqual(dest, source, count - 1));
Assert.False(ElementsAreEqual(dest, source, count));
}
private static bool ElementsAreEqual(Foo[] array, byte[] rawArray, int index)
{
fixed (Foo* pArray = array)
fixed (byte* pRaw = rawArray)
{
Foo* pCasted = (Foo*)pRaw;
Foo val1 = pArray[index];
Foo val2 = pCasted[index];
return val1.Equals(val2);
}
}
}
}
}
Loading…
Cancel
Save