mirror of https://github.com/SixLabors/ImageSharp
12 changed files with 552 additions and 433 deletions
@ -1,168 +0,0 @@ |
|||
namespace ImageSharp |
|||
{ |
|||
using System; |
|||
using System.Numerics; |
|||
using System.Runtime.CompilerServices; |
|||
|
|||
public unsafe class BulkPixelOperations<TColor> |
|||
where TColor : struct, IPixel<TColor> |
|||
{ |
|||
public static BulkPixelOperations<TColor> Instance { get; } = default(TColor).BulkOperations; |
|||
|
|||
private static readonly int ColorSize = Unsafe.SizeOf<TColor>(); |
|||
|
|||
internal virtual void PackFromVector4( |
|||
ArrayPointer<Vector4> sourceVectors, |
|||
ArrayPointer<TColor> destColors, |
|||
int count) |
|||
{ |
|||
Vector4* sp = (Vector4*)sourceVectors.PointerAtOffset; |
|||
byte* dp = (byte*)destColors; |
|||
|
|||
for (int i = 0; i < count; i++) |
|||
{ |
|||
Vector4 v = Unsafe.Read<Vector4>(sp); |
|||
TColor c = default(TColor); |
|||
c.PackFromVector4(v); |
|||
Unsafe.Write(dp, c); |
|||
|
|||
sp++; |
|||
dp += ColorSize; |
|||
} |
|||
} |
|||
|
|||
internal virtual void PackToVector4( |
|||
ArrayPointer<TColor> sourceColors, |
|||
ArrayPointer<Vector4> destVectors, |
|||
int count) |
|||
{ |
|||
byte* sp = (byte*)sourceColors; |
|||
Vector4* dp = (Vector4*)destVectors.PointerAtOffset; |
|||
|
|||
for (int i = 0; i < count; i++) |
|||
{ |
|||
TColor c = Unsafe.Read<TColor>(sp); |
|||
*dp = c.ToVector4(); |
|||
sp += ColorSize; |
|||
dp++; |
|||
} |
|||
} |
|||
|
|||
internal virtual void PackFromXyzBytes( |
|||
ArrayPointer<byte> sourceBytes, |
|||
ArrayPointer<TColor> destColors, |
|||
int count) |
|||
{ |
|||
byte* sp = (byte*)sourceBytes; |
|||
byte* dp = (byte*)destColors.PointerAtOffset; |
|||
|
|||
for (int i = 0; i < count; i++) |
|||
{ |
|||
TColor c = default(TColor); |
|||
c.PackFromBytes(sp[0], sp[1], sp[2], 255); |
|||
Unsafe.Write(dp, c); |
|||
sp += 3; |
|||
dp += ColorSize; |
|||
} |
|||
} |
|||
|
|||
internal virtual void PackToXyzBytes( |
|||
ArrayPointer<TColor> sourceColors, |
|||
ArrayPointer<byte> destBytes, int count) |
|||
{ |
|||
byte* sp = (byte*)sourceColors; |
|||
byte[] dest = destBytes.Array; |
|||
|
|||
for (int i = destBytes.Offset; i < destBytes.Offset + count*3; i+=3) |
|||
{ |
|||
TColor c = Unsafe.Read<TColor>(sp); |
|||
c.ToXyzBytes(dest, i); |
|||
sp += ColorSize; |
|||
} |
|||
} |
|||
|
|||
internal virtual void PackFromXyzwBytes(ArrayPointer<byte> sourceBytes, ArrayPointer<TColor> destColors, int count) |
|||
{ |
|||
byte* sp = (byte*)sourceBytes; |
|||
byte* dp = (byte*)destColors.PointerAtOffset; |
|||
|
|||
for (int i = 0; i < count; i++) |
|||
{ |
|||
TColor c = default(TColor); |
|||
c.PackFromBytes(sp[0], sp[1], sp[2], sp[3]); |
|||
Unsafe.Write(dp, c); |
|||
sp += 4; |
|||
dp += ColorSize; |
|||
} |
|||
} |
|||
|
|||
internal virtual void PackToXyzwBytes(ArrayPointer<TColor> sourceColors, ArrayPointer<byte> destBytes, int count) |
|||
{ |
|||
byte* sp = (byte*)sourceColors; |
|||
byte[] dest = destBytes.Array; |
|||
|
|||
for (int i = destBytes.Offset; i < destBytes.Offset + count * 4; i += 4) |
|||
{ |
|||
TColor c = Unsafe.Read<TColor>(sp); |
|||
c.ToXyzwBytes(dest, i); |
|||
sp += ColorSize; |
|||
} |
|||
} |
|||
|
|||
internal virtual void PackFromZyxBytes(ArrayPointer<byte> sourceBytes, ArrayPointer<TColor> destColors, int count) |
|||
{ |
|||
byte* sp = (byte*)sourceBytes; |
|||
byte* dp = (byte*)destColors.PointerAtOffset; |
|||
|
|||
for (int i = 0; i < count; i++) |
|||
{ |
|||
TColor c = default(TColor); |
|||
c.PackFromBytes(sp[2], sp[1], sp[0], 255); |
|||
Unsafe.Write(dp, c); |
|||
sp += 3; |
|||
dp += ColorSize; |
|||
} |
|||
} |
|||
|
|||
internal virtual void PackToZyxBytes(ArrayPointer<TColor> sourceColors, ArrayPointer<byte> destBytes, int count) |
|||
{ |
|||
byte* sp = (byte*)sourceColors; |
|||
byte[] dest = destBytes.Array; |
|||
|
|||
for (int i = destBytes.Offset; i < destBytes.Offset + count * 3; i += 3) |
|||
{ |
|||
TColor c = Unsafe.Read<TColor>(sp); |
|||
c.ToZyxBytes(dest, i); |
|||
sp += ColorSize; |
|||
} |
|||
} |
|||
|
|||
internal virtual void PackFromZyxwBytes(ArrayPointer<byte> sourceBytes, ArrayPointer<TColor> destColors, int count) |
|||
{ |
|||
byte* sp = (byte*)sourceBytes; |
|||
byte* dp = (byte*)destColors.PointerAtOffset; |
|||
|
|||
for (int i = 0; i < count; i++) |
|||
{ |
|||
TColor c = default(TColor); |
|||
c.PackFromBytes(sp[2], sp[1], sp[0], sp[3]); |
|||
Unsafe.Write(dp, c); |
|||
sp += 4; |
|||
dp += ColorSize; |
|||
} |
|||
} |
|||
|
|||
internal virtual void PackToZyxwBytes(ArrayPointer<TColor> sourceColors, ArrayPointer<byte> destBytes, int count) |
|||
{ |
|||
byte* sp = (byte*)sourceColors; |
|||
byte[] dest = destBytes.Array; |
|||
|
|||
for (int i = destBytes.Offset; i < destBytes.Offset + count * 4; i += 4) |
|||
{ |
|||
TColor c = Unsafe.Read<TColor>(sp); |
|||
c.ToZyxwBytes(dest, i); |
|||
sp += ColorSize; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,256 @@ |
|||
// <copyright file="BulkPixelOperations{TColor}.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp |
|||
{ |
|||
using System.Numerics; |
|||
using System.Runtime.CompilerServices; |
|||
|
|||
/// <summary>
|
|||
/// A stateless class implementing Strategy Pattern for batched pixel-data conversion operations
|
|||
/// for pixel buffers of type <typeparamref name="TColor"/>.
|
|||
/// </summary>
|
|||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|||
public unsafe class BulkPixelOperations<TColor> |
|||
where TColor : struct, IPixel<TColor> |
|||
{ |
|||
/// <summary>
|
|||
/// The size of <typeparamref name="TColor"/> in bytes
|
|||
/// </summary>
|
|||
private static readonly int ColorSize = Unsafe.SizeOf<TColor>(); |
|||
|
|||
/// <summary>
|
|||
/// Gets the global <see cref="BulkPixelOperations{TColor}"/> instance for the pixel type <typeparamref name="TColor"/>
|
|||
/// </summary>
|
|||
public static BulkPixelOperations<TColor> Instance { get; } = default(TColor).BulkOperations; |
|||
|
|||
/// <summary>
|
|||
/// Bulk version of <see cref="IPixel.PackFromVector4(Vector4)"/>
|
|||
/// </summary>
|
|||
/// <param name="sourceVectors">The <see cref="ArrayPointer{Vector4}"/> to the source vectors.</param>
|
|||
/// <param name="destColors">The <see cref="ArrayPointer{TColor}"/> to the destination colors.</param>
|
|||
/// <param name="count">The number of pixels to convert.</param>
|
|||
internal virtual void PackFromVector4( |
|||
ArrayPointer<Vector4> sourceVectors, |
|||
ArrayPointer<TColor> destColors, |
|||
int count) |
|||
{ |
|||
Vector4* sp = (Vector4*)sourceVectors.PointerAtOffset; |
|||
byte* dp = (byte*)destColors; |
|||
|
|||
for (int i = 0; i < count; i++) |
|||
{ |
|||
Vector4 v = Unsafe.Read<Vector4>(sp); |
|||
TColor c = default(TColor); |
|||
c.PackFromVector4(v); |
|||
Unsafe.Write(dp, c); |
|||
|
|||
sp++; |
|||
dp += ColorSize; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Bulk version of <see cref="IPixel.ToVector4()"/>.
|
|||
/// </summary>
|
|||
/// <param name="sourceColors">The <see cref="ArrayPointer{TColor}"/> to the source colors.</param>
|
|||
/// <param name="destVectors">The <see cref="ArrayPointer{Vector4}"/> to the destination vectors.</param>
|
|||
/// <param name="count">The number of pixels to convert.</param>
|
|||
internal virtual void PackToVector4( |
|||
ArrayPointer<TColor> sourceColors, |
|||
ArrayPointer<Vector4> destVectors, |
|||
int count) |
|||
{ |
|||
byte* sp = (byte*)sourceColors; |
|||
Vector4* dp = (Vector4*)destVectors.PointerAtOffset; |
|||
|
|||
for (int i = 0; i < count; i++) |
|||
{ |
|||
TColor c = Unsafe.Read<TColor>(sp); |
|||
*dp = c.ToVector4(); |
|||
sp += ColorSize; |
|||
dp++; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Bulk version of <see cref="IPixel.PackFromBytes(byte, byte, byte, byte)"/> that converts data in <see cref="ComponentOrder.Xyz"/>.
|
|||
/// </summary>
|
|||
/// <param name="sourceBytes"></param>
|
|||
/// <param name="destColors"></param>
|
|||
/// <param name="count"></param>
|
|||
internal virtual void PackFromXyzBytes( |
|||
ArrayPointer<byte> sourceBytes, |
|||
ArrayPointer<TColor> destColors, |
|||
int count) |
|||
{ |
|||
byte* sp = (byte*)sourceBytes; |
|||
byte* dp = (byte*)destColors.PointerAtOffset; |
|||
|
|||
for (int i = 0; i < count; i++) |
|||
{ |
|||
TColor c = default(TColor); |
|||
c.PackFromBytes(sp[0], sp[1], sp[2], 255); |
|||
Unsafe.Write(dp, c); |
|||
sp += 3; |
|||
dp += ColorSize; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Bulk version of <see cref="IPixel.ToXyzBytes(byte[], int)"/>.
|
|||
/// </summary>
|
|||
/// <param name="sourceColors"></param>
|
|||
/// <param name="destBytes"></param>
|
|||
/// <param name="count"></param>
|
|||
internal virtual void PackToXyzBytes(ArrayPointer<TColor> sourceColors, ArrayPointer<byte> destBytes, int count) |
|||
{ |
|||
byte* sp = (byte*)sourceColors; |
|||
byte[] dest = destBytes.Array; |
|||
|
|||
for (int i = destBytes.Offset; i < destBytes.Offset + count * 3; i += 3) |
|||
{ |
|||
TColor c = Unsafe.Read<TColor>(sp); |
|||
c.ToXyzBytes(dest, i); |
|||
sp += ColorSize; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Bulk version of <see cref="IPixel.PackFromBytes(byte, byte, byte, byte)"/> that converts data in <see cref="ComponentOrder.Xyzw"/>.
|
|||
/// </summary>
|
|||
/// <param name="sourceBytes"></param>
|
|||
/// <param name="destColors"></param>
|
|||
/// <param name="count"></param>
|
|||
internal virtual void PackFromXyzwBytes( |
|||
ArrayPointer<byte> sourceBytes, |
|||
ArrayPointer<TColor> destColors, |
|||
int count) |
|||
{ |
|||
byte* sp = (byte*)sourceBytes; |
|||
byte* dp = (byte*)destColors.PointerAtOffset; |
|||
|
|||
for (int i = 0; i < count; i++) |
|||
{ |
|||
TColor c = default(TColor); |
|||
c.PackFromBytes(sp[0], sp[1], sp[2], sp[3]); |
|||
Unsafe.Write(dp, c); |
|||
sp += 4; |
|||
dp += ColorSize; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Bulk version of <see cref="IPixel.ToXyzwBytes(byte[], int)"/>.
|
|||
/// </summary>
|
|||
/// <param name="sourceColors"></param>
|
|||
/// <param name="destBytes"></param>
|
|||
/// <param name="count"></param>
|
|||
internal virtual void PackToXyzwBytes( |
|||
ArrayPointer<TColor> sourceColors, |
|||
ArrayPointer<byte> destBytes, |
|||
int count) |
|||
{ |
|||
byte* sp = (byte*)sourceColors; |
|||
byte[] dest = destBytes.Array; |
|||
|
|||
for (int i = destBytes.Offset; i < destBytes.Offset + count * 4; i += 4) |
|||
{ |
|||
TColor c = Unsafe.Read<TColor>(sp); |
|||
c.ToXyzwBytes(dest, i); |
|||
sp += ColorSize; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Bulk version of <see cref="IPixel.PackFromBytes(byte, byte, byte, byte)"/> that converts data in <see cref="ComponentOrder.Zyx"/>.
|
|||
/// </summary>
|
|||
/// <param name="sourceBytes"></param>
|
|||
/// <param name="destColors"></param>
|
|||
/// <param name="count"></param>
|
|||
internal virtual void PackFromZyxBytes( |
|||
ArrayPointer<byte> sourceBytes, |
|||
ArrayPointer<TColor> destColors, |
|||
int count) |
|||
{ |
|||
byte* sp = (byte*)sourceBytes; |
|||
byte* dp = (byte*)destColors.PointerAtOffset; |
|||
|
|||
for (int i = 0; i < count; i++) |
|||
{ |
|||
TColor c = default(TColor); |
|||
c.PackFromBytes(sp[2], sp[1], sp[0], 255); |
|||
Unsafe.Write(dp, c); |
|||
sp += 3; |
|||
dp += ColorSize; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Bulk version of <see cref="IPixel.ToZyxBytes(byte[], int)"/>.
|
|||
/// </summary>
|
|||
/// <param name="sourceColors"></param>
|
|||
/// <param name="destBytes"></param>
|
|||
/// <param name="count"></param>
|
|||
internal virtual void PackToZyxBytes(ArrayPointer<TColor> sourceColors, ArrayPointer<byte> destBytes, int count) |
|||
{ |
|||
byte* sp = (byte*)sourceColors; |
|||
byte[] dest = destBytes.Array; |
|||
|
|||
for (int i = destBytes.Offset; i < destBytes.Offset + count * 3; i += 3) |
|||
{ |
|||
TColor c = Unsafe.Read<TColor>(sp); |
|||
c.ToZyxBytes(dest, i); |
|||
sp += ColorSize; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Bulk version of <see cref="IPixel.PackFromBytes(byte, byte, byte, byte)"/> that converts data in <see cref="ComponentOrder.Zyxw"/>.
|
|||
/// </summary>
|
|||
/// <param name="sourceBytes"></param>
|
|||
/// <param name="destColors"></param>
|
|||
/// <param name="count"></param>
|
|||
internal virtual void PackFromZyxwBytes( |
|||
ArrayPointer<byte> sourceBytes, |
|||
ArrayPointer<TColor> destColors, |
|||
int count) |
|||
{ |
|||
byte* sp = (byte*)sourceBytes; |
|||
byte* dp = (byte*)destColors.PointerAtOffset; |
|||
|
|||
for (int i = 0; i < count; i++) |
|||
{ |
|||
TColor c = default(TColor); |
|||
c.PackFromBytes(sp[2], sp[1], sp[0], sp[3]); |
|||
Unsafe.Write(dp, c); |
|||
sp += 4; |
|||
dp += ColorSize; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Bulk version of <see cref="IPixel.ToZyxwBytes(byte[], int)"/>.
|
|||
/// </summary>
|
|||
/// <param name="sourceColors"></param>
|
|||
/// <param name="destBytes"></param>
|
|||
/// <param name="count"></param>
|
|||
internal virtual void PackToZyxwBytes( |
|||
ArrayPointer<TColor> sourceColors, |
|||
ArrayPointer<byte> destBytes, |
|||
int count) |
|||
{ |
|||
byte* sp = (byte*)sourceColors; |
|||
byte[] dest = destBytes.Array; |
|||
|
|||
for (int i = destBytes.Offset; i < destBytes.Offset + count * 4; i += 4) |
|||
{ |
|||
TColor c = Unsafe.Read<TColor>(sp); |
|||
c.ToZyxwBytes(dest, i); |
|||
sp += ColorSize; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,60 @@ |
|||
// <copyright file="PixelDataPool{TColor}.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp |
|||
{ |
|||
using System; |
|||
using System.Buffers; |
|||
|
|||
/// <summary>
|
|||
/// Provides a resource pool that enables reusing instances of value type arrays <see cref="T:T[]"/>.
|
|||
/// <see cref="Rent(int)"/> will always return arrays initialized with 'default(T)'
|
|||
/// </summary>
|
|||
/// <typeparam name="T">The value type.</typeparam>
|
|||
public static class PixelDataPool<T> |
|||
where T : struct |
|||
{ |
|||
/// <summary>
|
|||
/// The <see cref="ArrayPool{T}"/> used to pool data.
|
|||
/// </summary>
|
|||
private static readonly ArrayPool<T> ArrayPool = ArrayPool<T>.Create(CalculateMaxArrayLength(), 50); |
|||
|
|||
/// <summary>
|
|||
/// Rents the pixel array from the pool.
|
|||
/// </summary>
|
|||
/// <param name="minimumLength">The minimum length of the array to return.</param>
|
|||
/// <returns>The <see cref="T:TColor[]"/></returns>
|
|||
public static T[] Rent(int minimumLength) |
|||
{ |
|||
return ArrayPool.Rent(minimumLength); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the rented pixel array back to the pool.
|
|||
/// </summary>
|
|||
/// <param name="array">The array to return to the buffer pool.</param>
|
|||
public static void Return(T[] array) |
|||
{ |
|||
ArrayPool.Return(array, true); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Heuristically calculates a reasonable maxArrayLength value for the backing <see cref="ArrayPool"/>.
|
|||
/// </summary>
|
|||
/// <returns>The maxArrayLength value</returns>
|
|||
internal static int CalculateMaxArrayLength() |
|||
{ |
|||
if (typeof(IPixel).IsAssignableFrom(typeof(T))) |
|||
{ |
|||
const int MaximumExpectedImageSize = 16384; |
|||
return MaximumExpectedImageSize * MaximumExpectedImageSize; |
|||
} |
|||
else |
|||
{ |
|||
return int.MaxValue; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,43 +0,0 @@ |
|||
// <copyright file="PixelPool{TColor}.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp |
|||
{ |
|||
using System; |
|||
using System.Buffers; |
|||
|
|||
// TODO: Consider refactoring this into a more general ClearPool<T>, so we can use it in PinnedBuffer<T>!
|
|||
/// <summary>
|
|||
/// Provides a resource pool that enables reusing instances of type <see cref="T:TColor[]"/>.
|
|||
/// </summary>
|
|||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|||
public static class PixelPool<TColor> |
|||
where TColor : struct, IPixel<TColor> |
|||
{ |
|||
/// <summary>
|
|||
/// The <see cref="ArrayPool{T}"/> used to pool data. TODO: Choose sensible default size and count
|
|||
/// </summary>
|
|||
private static readonly ArrayPool<TColor> ArrayPool = ArrayPool<TColor>.Create(int.MaxValue, 50); |
|||
|
|||
/// <summary>
|
|||
/// Rents the pixel array from the pool.
|
|||
/// </summary>
|
|||
/// <param name="minimumLength">The minimum length of the array to return.</param>
|
|||
/// <returns>The <see cref="T:TColor[]"/></returns>
|
|||
public static TColor[] RentPixels(int minimumLength) |
|||
{ |
|||
return ArrayPool.Rent(minimumLength); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the rented pixel array back to the pool.
|
|||
/// </summary>
|
|||
/// <param name="array">The array to return to the buffer pool.</param>
|
|||
public static void ReturnPixels(TColor[] array) |
|||
{ |
|||
ArrayPool.Return(array, true); |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue