Browse Source

Begin add vector based Color

af/merge-core
James Jackson-South 9 years ago
parent
commit
e340b3f103
  1. 306
      src/ImageSharp/Colors/Color.BulkOperations.cs
  2. 335
      src/ImageSharp/Colors/Color.cs
  3. 291
      src/ImageSharp/Colors/Color32.BulkOperations.cs
  4. 2
      src/ImageSharp/Colors/Color32.Transforms.cs
  5. 2
      src/ImageSharp/Colors/Color32.cs
  6. 2
      src/ImageSharp/Colors/ColorspaceTransforms.cs
  7. 40
      src/ImageSharp/Colors/PackedPixel/BulkPixelOperations{TColor}.cs
  8. 21
      tests/ImageSharp.Benchmarks/Samplers/Resize.cs

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

@ -1,305 +1,35 @@
// <copyright file="Color32.BulkOperations.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
namespace ImageSharp
{
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
/// <content>
/// Conains the definition of <see cref="BulkOperations"/>
/// </content>
public partial struct Color32
/// <summary>
/// Unpacked pixel type containing four 16-bit unsigned normalized values ranging from 0 to 1.
/// The color components are stored in red, green, blue, and alpha order.
/// </summary>
/// <remarks>
/// This struct is fully mutable. This is done (against the guidelines) for the sake of performance,
/// as it avoids the need to create new values for modification operations.
/// </remarks>
public partial struct Color
{
/// <summary>
/// <see cref="BulkPixelOperations{TColor32}"/> implementation optimized for <see cref="Color32"/>.
/// <see cref="BulkPixelOperations{TColor}"/> implementation optimized for <see cref="Color"/>.
/// </summary>
internal class BulkOperations : BulkPixelOperations<Color32>
internal class BulkOperations : BulkPixelOperations<Color>
{
/// <summary>
/// SIMD optimized bulk implementation of <see cref="IPixel.PackFromVector4(Vector4)"/>
/// that works only with `count` divisible by <see cref="Vector{UInt32}.Count"/>.
/// </summary>
/// <param name="sourceColor32s">The <see cref="BufferSpan{T}"/> to the source colors.</param>
/// <param name="destVectors">The <see cref="BufferSpan{T}"/> to the dstination vectors.</param>
/// <param name="count">The number of pixels to convert.</param>
/// <remarks>
/// Implementation adapted from:
/// <see>
/// <cref>http://stackoverflow.com/a/5362789</cref>
/// </see>
/// TODO: We can replace this implementation in the future using new Vector API-s:
/// <see>
/// <cref>https://github.com/dotnet/corefx/issues/15957</cref>
/// </see>
/// </remarks>
internal static unsafe void ToVector4SimdAligned(
BufferSpan<Color32> sourceColor32s,
BufferSpan<Vector4> destVectors,
int count)
{
if (!Vector.IsHardwareAccelerated)
{
throw new InvalidOperationException(
"Color32.BulkOperations.ToVector4SimdAligned() should not be called when Vector.IsHardwareAccelerated == false!");
}
int vecSize = Vector<uint>.Count;
DebugGuard.IsTrue(
count % vecSize == 0,
nameof(count),
"Argument 'count' should divisible by Vector<uint>.Count!");
Vector<float> bVec = new Vector<float>(256.0f / 255.0f);
Vector<float> magicFloat = new Vector<float>(32768.0f);
Vector<uint> magicInt = new Vector<uint>(1191182336); // reinterpreded value of 32768.0f
Vector<uint> mask = new Vector<uint>(255);
int unpackedRawCount = count * 4;
ref uint src = ref Unsafe.As<Color32, uint>(ref sourceColor32s.DangerousGetPinnableReference());
using (Buffer<uint> tempBuf = new Buffer<uint>(
unpackedRawCount + Vector<uint>.Count))
{
uint[] temp = tempBuf.Array;
float[] fTemp = Unsafe.As<float[]>(temp);
ref UnpackedRGBA tempBase = ref Unsafe.As<uint, UnpackedRGBA>(ref tempBuf[0]);
for (int i = 0; i < count; i++)
{
uint sVal = Unsafe.Add(ref src, i);
ref UnpackedRGBA dst = ref Unsafe.Add(ref tempBase, i);
// This call is the bottleneck now:
dst.Load(sVal);
}
for (int i = 0; i < unpackedRawCount; i += vecSize)
{
Vector<uint> vi = new Vector<uint>(temp, i);
vi &= mask;
vi |= magicInt;
Vector<float> vf = Vector.AsVectorSingle(vi);
vf = (vf - magicFloat) * bVec;
vf.CopyTo(fTemp, i);
}
BufferSpan.Copy(tempBuf.Span.AsBytes(), destVectors.AsBytes(), unpackedRawCount * sizeof(uint));
}
}
/// <inheritdoc />
internal override void ToVector4(BufferSpan<Color32> sourceColor32s, BufferSpan<Vector4> destVectors, int count)
internal override void ToVector4(BufferSpan<Color> sourceColors, BufferSpan<Vector4> destVectors, int count)
{
if (count < 256 || !Vector.IsHardwareAccelerated)
{
// Doesn't worth to bother with SIMD:
base.ToVector4(sourceColor32s, destVectors, count);
return;
}
int remainder = count % Vector<uint>.Count;
int alignedCount = count - remainder;
if (alignedCount > 0)
{
ToVector4SimdAligned(sourceColor32s, destVectors, alignedCount);
}
if (remainder > 0)
{
sourceColor32s = sourceColor32s.Slice(alignedCount);
destVectors = destVectors.Slice(alignedCount);
base.ToVector4(sourceColor32s, destVectors, remainder);
}
}
/// <inheritdoc />
internal override void PackFromXyzBytes(
BufferSpan<byte> sourceBytes,
BufferSpan<Color32> destColor32s,
int count)
{
ref RGB24 sourceRef = ref Unsafe.As<byte, RGB24>(ref sourceBytes.DangerousGetPinnableReference());
ref Color32 destRef = ref destColor32s.DangerousGetPinnableReference();
ref Vector4 sourceRef = ref Unsafe.As<Color, Vector4>(ref sourceColors.DangerousGetPinnableReference());
ref Vector4 destRef = ref destVectors.DangerousGetPinnableReference();
for (int i = 0; i < count; i++)
{
ref RGB24 sp = ref Unsafe.Add(ref sourceRef, i);
ref Color32 dp = ref Unsafe.Add(ref destRef, i);
Unsafe.As<Color32, RGB24>(ref dp) = sp;
dp.A = 255;
}
}
/// <inheritdoc />
internal override void ToXyzBytes(BufferSpan<Color32> sourceColor32s, BufferSpan<byte> destBytes, int count)
{
ref Color32 sourceRef = ref sourceColor32s.DangerousGetPinnableReference();
ref RGB24 destRef = ref Unsafe.As<byte, RGB24>(ref destBytes.DangerousGetPinnableReference());
for (int i = 0; i < count; i++)
{
ref Color32 sp = ref Unsafe.Add(ref sourceRef, i);
ref RGB24 dp = ref Unsafe.Add(ref destRef, i);
dp = Unsafe.As<Color32, RGB24>(ref sp);
}
}
/// <inheritdoc />
internal override unsafe void PackFromXyzwBytes(
BufferSpan<byte> sourceBytes,
BufferSpan<Color32> destColor32s,
int count)
{
BufferSpan.Copy(sourceBytes, destColor32s.AsBytes(), count * sizeof(Color32));
}
/// <inheritdoc />
internal override unsafe void ToXyzwBytes(BufferSpan<Color32> sourceColor32s, BufferSpan<byte> destBytes, int count)
{
BufferSpan.Copy(sourceColor32s.AsBytes(), destBytes, count * sizeof(Color32));
}
/// <inheritdoc />
internal override void PackFromZyxBytes(
BufferSpan<byte> sourceBytes,
BufferSpan<Color32> destColor32s,
int count)
{
ref RGB24 sourceRef = ref Unsafe.As<byte, RGB24>(ref sourceBytes.DangerousGetPinnableReference());
ref Color32 destRef = ref destColor32s.DangerousGetPinnableReference();
for (int i = 0; i < count; i++)
{
ref RGB24 sp = ref Unsafe.Add(ref sourceRef, i);
ref Color32 dp = ref Unsafe.Add(ref destRef, i);
Unsafe.As<Color32, RGB24>(ref dp) = sp.ToZyx();
dp.A = 255;
}
}
/// <inheritdoc />
internal override void ToZyxBytes(
BufferSpan<Color32> sourceColor32s,
BufferSpan<byte> destBytes,
int count)
{
ref Color32 sourceRef = ref sourceColor32s.DangerousGetPinnableReference();
ref RGB24 destRef = ref Unsafe.As<byte, RGB24>(ref destBytes.DangerousGetPinnableReference());
for (int i = 0; i < count; i++)
{
ref Color32 sp = ref Unsafe.Add(ref sourceRef, i);
ref RGB24 dp = ref Unsafe.Add(ref destRef, i);
dp = Unsafe.As<Color32, RGB24>(ref sp).ToZyx();
}
}
/// <inheritdoc />
internal override void PackFromZyxwBytes(
BufferSpan<byte> sourceBytes,
BufferSpan<Color32> destColor32s,
int count)
{
ref RGBA32 sourceRef = ref Unsafe.As<byte, RGBA32>(ref sourceBytes.DangerousGetPinnableReference());
ref Color32 destRef = ref destColor32s.DangerousGetPinnableReference();
for (int i = 0; i < count; i++)
{
ref RGBA32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Color32 dp = ref Unsafe.Add(ref destRef, i);
RGBA32 zyxw = sp.ToZyxw();
dp = Unsafe.As<RGBA32, Color32>(ref zyxw);
}
}
/// <inheritdoc />
internal override void ToZyxwBytes(
BufferSpan<Color32> sourceColor32s,
BufferSpan<byte> destBytes,
int count)
{
ref Color32 sourceRef = ref sourceColor32s.DangerousGetPinnableReference();
ref RGBA32 destRef = ref Unsafe.As<byte, RGBA32>(ref destBytes.DangerousGetPinnableReference());
for (int i = 0; i < count; i++)
{
ref RGBA32 sp = ref Unsafe.As<Color32, RGBA32>(ref Unsafe.Add(ref sourceRef, i));
ref RGBA32 dp = ref Unsafe.Add(ref destRef, i);
dp = sp.ToZyxw();
}
}
/// <summary>
/// Helper struct to manipulate 3-byte RGB data.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
private struct RGB24
{
private byte x;
private byte y;
private byte z;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public RGB24 ToZyx() => new RGB24 { x = this.z, y = this.y, z = this.x };
}
/// <summary>
/// Helper struct to manipulate 4-byte RGBA data.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
private struct RGBA32
{
private byte x;
private byte y;
private byte z;
private byte w;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public RGBA32 ToZyxw() => new RGBA32 { x = this.z, y = this.y, z = this.x, w = this.w };
}
/// <summary>
/// Value type to store <see cref="Color32"/>-s unpacked into multiple <see cref="uint"/>-s.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
private struct UnpackedRGBA
{
private uint r;
private uint g;
private uint b;
private uint a;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Load(uint p)
{
this.r = p;
this.g = p >> GreenShift;
this.b = p >> BlueShift;
this.a = p >> AlphaShift;
ref Vector4 sp = ref Unsafe.Add(ref sourceRef, i);
ref Vector4 dp = ref Unsafe.Add(ref destRef, i);
dp = sp;
}
}
}

335
src/ImageSharp/Colors/Color.cs

@ -0,0 +1,335 @@
// <copyright file="Color.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>
/// Unpacked pixel type containing four 16-bit unsigned normalized values ranging from 0 to 1.
/// The color components are stored in red, green, blue, and alpha order.
/// </summary>
/// <remarks>
/// This struct is fully mutable. This is done (against the guidelines) for the sake of performance,
/// as it avoids the need to create new values for modification operations.
/// </remarks>
public partial struct Color : IPixel<Color>
{
/// <summary>
/// The shift count for the red component
/// </summary>
private const int RedShift = 0;
/// <summary>
/// The shift count for the green component
/// </summary>
private const int GreenShift = 8;
/// <summary>
/// The shift count for the blue component
/// </summary>
private const int BlueShift = 16;
/// <summary>
/// The shift count for the alpha component
/// </summary>
private const int AlphaShift = 24;
/// <summary>
/// The maximum byte value.
/// </summary>
private static readonly Vector4 MaxBytes = new Vector4(255);
/// <summary>
/// The half vector value.
/// </summary>
private static readonly Vector4 Half = new Vector4(0.5F);
/// <summary>
/// The backing vector for SIMD support.
/// </summary>
private Vector4 backingVector;
/// <summary>
/// Initializes a new instance of the <see cref="Color"/> struct.
/// </summary>
/// <param name="r">The red component.</param>
/// <param name="g">The green component.</param>
/// <param name="b">The blue component.</param>
/// <param name="a">The alpha component.</param>
public Color(byte r, byte g, byte b, byte a = 255)
: this()
{
this.backingVector = new Vector4(r, g, b, a) / MaxBytes;
}
/// <summary>
/// Initializes a new instance of the <see cref="Color"/> struct.
/// </summary>
/// <param name="r">The red component.</param>
/// <param name="g">The green component.</param>
/// <param name="b">The blue component.</param>
/// <param name="a">The alpha component.</param>
public Color(float r, float g, float b, float a = 1)
: this()
{
this.backingVector = new Vector4(r, g, b, a);
}
/// <summary>
/// Initializes a new instance of the <see cref="Color"/> struct.
/// </summary>
/// <param name="vector">
/// The vector containing the components for the packed vector.
/// </param>
public Color(Vector3 vector)
: this()
{
this.backingVector = new Vector4(vector, 1);
}
/// <summary>
/// Initializes a new instance of the <see cref="Color"/> struct.
/// </summary>
/// <param name="vector">
/// The vector containing the components for the packed vector.
/// </param>
public Color(Vector4 vector)
: this()
{
this.backingVector = vector;
}
/// <summary>
/// Gets or sets the red component.
/// </summary>
public float R
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
return this.backingVector.X;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set
{
this.backingVector.X = value;
}
}
/// <summary>
/// Gets or sets the green component.
/// </summary>
public float G
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
return this.backingVector.Y;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set
{
this.backingVector.Y = value;
}
}
/// <summary>
/// Gets or sets the blue component.
/// </summary>
public float B
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
return this.backingVector.Z;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set
{
this.backingVector.Z = value;
}
}
/// <summary>
/// Gets or sets the alpha component.
/// </summary>
public float A
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
return this.backingVector.W;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set
{
this.backingVector.W = value;
}
}
/// <summary>
/// Compares two <see cref="Color"/> objects for equality.
/// </summary>
/// <param name="left">
/// The <see cref="Color"/> on the left side of the operand.
/// </param>
/// <param name="right">
/// The <see cref="Color"/> on the right side of the operand.
/// </param>
/// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Color left, Color right)
{
return left.backingVector == right.backingVector;
}
/// <summary>
/// Compares two <see cref="Color"/> objects for equality.
/// </summary>
/// <param name="left">The <see cref="Color"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="Color"/> on the right side of the operand.</param>
/// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(Color left, Color right)
{
return left.backingVector != right.backingVector;
}
/// <summary>
/// Creates a new instance of the <see cref="Color"/> struct.
/// </summary>
/// <param name="hex">
/// The hexadecimal representation of the combined color components arranged
/// in rgb, rgba, rrggbb, or rrggbbaa format to match web syntax.
/// </param>
/// <returns>
/// The <see cref="Color"/>.
/// </returns>
public static Color FromHex(string hex)
{
return ColorBuilder<Color>.FromHex(hex);
}
/// <inheritdoc />
public BulkPixelOperations<Color> CreateBulkOperations() => new Color.BulkOperations();
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromBytes(byte x, byte y, byte z, byte w)
{
this.backingVector = new Vector4(x, y, z, w) / MaxBytes;
}
/// <summary>
/// Converts the value of this instance to a hexadecimal string.
/// </summary>
/// <returns>A hexadecimal string representation of the value.</returns>
public string ToHex()
{
Vector4 vector = this.backingVector * MaxBytes;
vector += Half;
uint hexOrder = (uint)((byte)vector.X << RedShift | (byte)vector.Y << GreenShift | (byte)vector.Z << BlueShift | (byte)vector.W << AlphaShift);
return hexOrder.ToString("X8");
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToXyzBytes(byte[] bytes, int startIndex)
{
Vector4 vector = Vector4.Clamp(this.backingVector, Vector4.Zero, Vector4.One) * MaxBytes;
vector += Half;
bytes[startIndex] = (byte)vector.X;
bytes[startIndex + 1] = (byte)vector.Y;
bytes[startIndex + 2] = (byte)vector.Z;
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToXyzwBytes(byte[] bytes, int startIndex)
{
Vector4 vector = Vector4.Clamp(this.backingVector, Vector4.Zero, Vector4.One) * MaxBytes;
vector += Half;
bytes[startIndex] = (byte)vector.X;
bytes[startIndex + 1] = (byte)vector.Y;
bytes[startIndex + 2] = (byte)vector.Z;
bytes[startIndex + 2] = (byte)vector.W;
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToZyxBytes(byte[] bytes, int startIndex)
{
Vector4 vector = Vector4.Clamp(this.backingVector, Vector4.Zero, Vector4.One) * MaxBytes;
vector += Half;
bytes[startIndex] = (byte)vector.Z;
bytes[startIndex + 1] = (byte)vector.Y;
bytes[startIndex + 2] = (byte)vector.X;
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToZyxwBytes(byte[] bytes, int startIndex)
{
Vector4 vector = Vector4.Clamp(this.backingVector, Vector4.Zero, Vector4.One) * MaxBytes;
vector += Half;
bytes[startIndex] = (byte)vector.Z;
bytes[startIndex + 1] = (byte)vector.Y;
bytes[startIndex + 2] = (byte)vector.X;
bytes[startIndex + 2] = (byte)vector.W;
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromVector4(Vector4 vector)
{
this.backingVector = vector;
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ToVector4()
{
return this.backingVector;
}
/// <inheritdoc/>
public override bool Equals(object obj)
{
return (obj is Color) && this.Equals((Color)obj);
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(Color other)
{
return this.backingVector == other.backingVector;
}
/// <summary>
/// Gets a string representation of the packed vector.
/// </summary>
/// <returns>A string representation of the packed vector.</returns>
public override string ToString()
{
return this.ToVector4().ToString();
}
/// <inheritdoc/>
public override int GetHashCode()
{
return this.backingVector.GetHashCode();
}
}
}

291
src/ImageSharp/Colors/Color32.BulkOperations.cs

@ -0,0 +1,291 @@
// <copyright file="Color32.BulkOperations.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.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
/// <summary>
/// Unpacked pixel type containing four 8-bit unsigned normalized values ranging from 0 to 255.
/// The color components are stored in red, green, blue, and alpha order.
/// </summary>
/// <remarks>
/// This struct is fully mutable. This is done (against the guidelines) for the sake of performance,
/// as it avoids the need to create new values for modification operations.
/// </remarks>
public partial struct Color32
{
/// <summary>
/// <see cref="BulkPixelOperations{TColor}"/> implementation optimized for <see cref="Color32"/>.
/// </summary>
internal class BulkOperations : BulkPixelOperations<Color32>
{
/// <summary>
/// SIMD optimized bulk implementation of <see cref="IPixel.PackFromVector4(Vector4)"/>
/// that works only with `count` divisible by <see cref="Vector{UInt32}.Count"/>.
/// </summary>
/// <param name="sourceColors">The <see cref="BufferSpan{T}"/> to the source colors.</param>
/// <param name="destVectors">The <see cref="BufferSpan{T}"/> to the dstination vectors.</param>
/// <param name="count">The number of pixels to convert.</param>
/// <remarks>
/// Implementation adapted from:
/// <see>
/// <cref>http://stackoverflow.com/a/5362789</cref>
/// </see>
/// TODO: We can replace this implementation in the future using new Vector API-s:
/// <see>
/// <cref>https://github.com/dotnet/corefx/issues/15957</cref>
/// </see>
/// </remarks>
internal static unsafe void ToVector4SimdAligned(BufferSpan<Color32> sourceColors, BufferSpan<Vector4> destVectors, int count)
{
if (!Vector.IsHardwareAccelerated)
{
throw new InvalidOperationException(
"Color32.BulkOperations.ToVector4SimdAligned() should not be called when Vector.IsHardwareAccelerated == false!");
}
int vecSize = Vector<uint>.Count;
DebugGuard.IsTrue(
count % vecSize == 0,
nameof(count),
"Argument 'count' should divisible by Vector<uint>.Count!");
Vector<float> bVec = new Vector<float>(256.0f / 255.0f);
Vector<float> magicFloat = new Vector<float>(32768.0f);
Vector<uint> magicInt = new Vector<uint>(1191182336); // reinterpreded value of 32768.0f
Vector<uint> mask = new Vector<uint>(255);
int unpackedRawCount = count * 4;
ref uint src = ref Unsafe.As<Color32, uint>(ref sourceColors.DangerousGetPinnableReference());
using (Buffer<uint> tempBuf = new Buffer<uint>(
unpackedRawCount + Vector<uint>.Count))
{
uint[] temp = tempBuf.Array;
float[] fTemp = Unsafe.As<float[]>(temp);
ref UnpackedRGBA tempBase = ref Unsafe.As<uint, UnpackedRGBA>(ref tempBuf[0]);
for (int i = 0; i < count; i++)
{
uint sVal = Unsafe.Add(ref src, i);
ref UnpackedRGBA dst = ref Unsafe.Add(ref tempBase, i);
// This call is the bottleneck now:
dst.Load(sVal);
}
for (int i = 0; i < unpackedRawCount; i += vecSize)
{
Vector<uint> vi = new Vector<uint>(temp, i);
vi &= mask;
vi |= magicInt;
Vector<float> vf = Vector.AsVectorSingle(vi);
vf = (vf - magicFloat) * bVec;
vf.CopyTo(fTemp, i);
}
BufferSpan.Copy(tempBuf.Span.AsBytes(), destVectors.AsBytes(), unpackedRawCount * sizeof(uint));
}
}
/// <inheritdoc />
internal override void ToVector4(BufferSpan<Color32> sourceColors, BufferSpan<Vector4> destVectors, int count)
{
if (count < 256 || !Vector.IsHardwareAccelerated)
{
// Doesn't worth to bother with SIMD:
base.ToVector4(sourceColors, destVectors, count);
return;
}
int remainder = count % Vector<uint>.Count;
int alignedCount = count - remainder;
if (alignedCount > 0)
{
ToVector4SimdAligned(sourceColors, destVectors, alignedCount);
}
if (remainder > 0)
{
sourceColors = sourceColors.Slice(alignedCount);
destVectors = destVectors.Slice(alignedCount);
base.ToVector4(sourceColors, destVectors, remainder);
}
}
/// <inheritdoc />
internal override void PackFromXyzBytes(BufferSpan<byte> sourceBytes, BufferSpan<Color32> destColors, int count)
{
ref RGB24 sourceRef = ref Unsafe.As<byte, RGB24>(ref sourceBytes.DangerousGetPinnableReference());
ref Color32 destRef = ref destColors.DangerousGetPinnableReference();
for (int i = 0; i < count; i++)
{
ref RGB24 sp = ref Unsafe.Add(ref sourceRef, i);
ref Color32 dp = ref Unsafe.Add(ref destRef, i);
Unsafe.As<Color32, RGB24>(ref dp) = sp;
dp.A = 255;
}
}
/// <inheritdoc />
internal override void ToXyzBytes(BufferSpan<Color32> sourceColors, BufferSpan<byte> destBytes, int count)
{
ref Color32 sourceRef = ref sourceColors.DangerousGetPinnableReference();
ref RGB24 destRef = ref Unsafe.As<byte, RGB24>(ref destBytes.DangerousGetPinnableReference());
for (int i = 0; i < count; i++)
{
ref Color32 sp = ref Unsafe.Add(ref sourceRef, i);
ref RGB24 dp = ref Unsafe.Add(ref destRef, i);
dp = Unsafe.As<Color32, RGB24>(ref sp);
}
}
/// <inheritdoc />
internal override unsafe void PackFromXyzwBytes(BufferSpan<byte> sourceBytes, BufferSpan<Color32> destColors, int count)
{
BufferSpan.Copy(sourceBytes, destColors.AsBytes(), count * sizeof(Color32));
}
/// <inheritdoc />
internal override unsafe void ToXyzwBytes(BufferSpan<Color32> sourceColors, BufferSpan<byte> destBytes, int count)
{
BufferSpan.Copy(sourceColors.AsBytes(), destBytes, count * sizeof(Color32));
}
/// <inheritdoc />
internal override void PackFromZyxBytes(BufferSpan<byte> sourceBytes, BufferSpan<Color32> destColors, int count)
{
ref RGB24 sourceRef = ref Unsafe.As<byte, RGB24>(ref sourceBytes.DangerousGetPinnableReference());
ref Color32 destRef = ref destColors.DangerousGetPinnableReference();
for (int i = 0; i < count; i++)
{
ref RGB24 sp = ref Unsafe.Add(ref sourceRef, i);
ref Color32 dp = ref Unsafe.Add(ref destRef, i);
Unsafe.As<Color32, RGB24>(ref dp) = sp.ToZyx();
dp.A = 255;
}
}
/// <inheritdoc />
internal override void ToZyxBytes(BufferSpan<Color32> sourceColors, BufferSpan<byte> destBytes, int count)
{
ref Color32 sourceRef = ref sourceColors.DangerousGetPinnableReference();
ref RGB24 destRef = ref Unsafe.As<byte, RGB24>(ref destBytes.DangerousGetPinnableReference());
for (int i = 0; i < count; i++)
{
ref Color32 sp = ref Unsafe.Add(ref sourceRef, i);
ref RGB24 dp = ref Unsafe.Add(ref destRef, i);
dp = Unsafe.As<Color32, RGB24>(ref sp).ToZyx();
}
}
/// <inheritdoc />
internal override void PackFromZyxwBytes(BufferSpan<byte> sourceBytes, BufferSpan<Color32> destColors, int count)
{
ref RGBA32 sourceRef = ref Unsafe.As<byte, RGBA32>(ref sourceBytes.DangerousGetPinnableReference());
ref Color32 destRef = ref destColors.DangerousGetPinnableReference();
for (int i = 0; i < count; i++)
{
ref RGBA32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Color32 dp = ref Unsafe.Add(ref destRef, i);
RGBA32 zyxw = sp.ToZyxw();
dp = Unsafe.As<RGBA32, Color32>(ref zyxw);
}
}
/// <inheritdoc />
internal override void ToZyxwBytes(BufferSpan<Color32> sourceColors, BufferSpan<byte> destBytes, int count)
{
ref Color32 sourceRef = ref sourceColors.DangerousGetPinnableReference();
ref RGBA32 destRef = ref Unsafe.As<byte, RGBA32>(ref destBytes.DangerousGetPinnableReference());
for (int i = 0; i < count; i++)
{
ref RGBA32 sp = ref Unsafe.As<Color32, RGBA32>(ref Unsafe.Add(ref sourceRef, i));
ref RGBA32 dp = ref Unsafe.Add(ref destRef, i);
dp = sp.ToZyxw();
}
}
/// <summary>
/// Helper struct to manipulate 3-byte RGB data.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
private struct RGB24
{
private byte x;
private byte y;
private byte z;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public RGB24 ToZyx() => new RGB24 { x = this.z, y = this.y, z = this.x };
}
/// <summary>
/// Helper struct to manipulate 4-byte RGBA data.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
private struct RGBA32
{
private byte x;
private byte y;
private byte z;
private byte w;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public RGBA32 ToZyxw() => new RGBA32 { x = this.z, y = this.y, z = this.x, w = this.w };
}
/// <summary>
/// Value type to store <see cref="Color32"/>-s unpacked into multiple <see cref="uint"/>-s.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
private struct UnpackedRGBA
{
private uint r;
private uint g;
private uint b;
private uint a;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Load(uint p)
{
this.r = p;
this.g = p >> GreenShift;
this.b = p >> BlueShift;
this.a = p >> AlphaShift;
}
}
}
}
}

2
src/ImageSharp/Colors/Color32.Transforms.cs

@ -8,7 +8,7 @@ namespace ImageSharp
using System.Numerics;
/// <summary>
/// Packed vector type containing four 8-bit unsigned normalized values ranging from 0 to 255.
/// Unpacked pixel type containing four 8-bit unsigned normalized values ranging from 0 to 255.
/// The color components are stored in red, green, blue, and alpha order.
/// </summary>
/// <remarks>

2
src/ImageSharp/Colors/Color32.cs

@ -10,7 +10,7 @@ namespace ImageSharp
using System.Runtime.InteropServices;
/// <summary>
/// Packed pixel type containing four 8-bit unsigned normalized values ranging from 0 to 255.
/// Unpacked pixel type containing four 8-bit unsigned normalized values ranging from 0 to 255.
/// The color components are stored in red, green, blue, and alpha order.
/// </summary>
/// <remarks>

2
src/ImageSharp/Colors/ColorspaceTransforms.cs

@ -10,7 +10,7 @@ namespace ImageSharp
using Colors.Spaces;
/// <summary>
/// Packed vector type containing four 8-bit unsigned normalized values ranging from 0 to 255.
/// Unpacked pixel type containing four 8-bit unsigned normalized values ranging from 0 to 255.
/// The color components are stored in red, green, blue, and alpha order.
/// </summary>
/// <remarks>

40
src/ImageSharp/Colors/PackedPixel/BulkPixelOperations{TColor}.cs

@ -27,10 +27,7 @@ namespace ImageSharp
/// <param name="sourceVectors">The <see cref="BufferSpan{T}"/> to the source vectors.</param>
/// <param name="destColors">The <see cref="BufferSpan{T}"/> to the destination colors.</param>
/// <param name="count">The number of pixels to convert.</param>
internal virtual void PackFromVector4(
BufferSpan<Vector4> sourceVectors,
BufferSpan<TColor> destColors,
int count)
internal virtual void PackFromVector4(BufferSpan<Vector4> sourceVectors, BufferSpan<TColor> destColors, int count)
{
ref Vector4 sourceRef = ref sourceVectors.DangerousGetPinnableReference();
ref TColor destRef = ref destColors.DangerousGetPinnableReference();
@ -49,10 +46,7 @@ namespace ImageSharp
/// <param name="sourceColors">The <see cref="BufferSpan{T}"/> to the source colors.</param>
/// <param name="destVectors">The <see cref="BufferSpan{T}"/> to the destination vectors.</param>
/// <param name="count">The number of pixels to convert.</param>
internal virtual void ToVector4(
BufferSpan<TColor> sourceColors,
BufferSpan<Vector4> destVectors,
int count)
internal virtual void ToVector4(BufferSpan<TColor> sourceColors, BufferSpan<Vector4> destVectors, int count)
{
ref TColor sourceRef = ref sourceColors.DangerousGetPinnableReference();
ref Vector4 destRef = ref destVectors.DangerousGetPinnableReference();
@ -71,10 +65,7 @@ namespace ImageSharp
/// <param name="sourceBytes">The <see cref="BufferSpan{T}"/> to the source bytes.</param>
/// <param name="destColors">The <see cref="BufferSpan{T}"/> to the destination colors.</param>
/// <param name="count">The number of pixels to convert.</param>
internal virtual void PackFromXyzBytes(
BufferSpan<byte> sourceBytes,
BufferSpan<TColor> destColors,
int count)
internal virtual void PackFromXyzBytes(BufferSpan<byte> sourceBytes, BufferSpan<TColor> destColors, int count)
{
ref byte sourceRef = ref sourceBytes.DangerousGetPinnableReference();
ref TColor destRef = ref destColors.DangerousGetPinnableReference();
@ -115,10 +106,7 @@ namespace ImageSharp
/// <param name="sourceBytes">The <see cref="BufferSpan{T}"/> to the source bytes.</param>
/// <param name="destColors">The <see cref="BufferSpan{T}"/> to the destination colors.</param>
/// <param name="count">The number of pixels to convert.</param>
internal virtual void PackFromXyzwBytes(
BufferSpan<byte> sourceBytes,
BufferSpan<TColor> destColors,
int count)
internal virtual void PackFromXyzwBytes(BufferSpan<byte> sourceBytes, BufferSpan<TColor> destColors, int count)
{
ref byte sourceRef = ref sourceBytes.DangerousGetPinnableReference();
ref TColor destRef = ref destColors.DangerousGetPinnableReference();
@ -141,10 +129,7 @@ namespace ImageSharp
/// <param name="sourceColors">The <see cref="BufferSpan{T}"/> to the source colors.</param>
/// <param name="destBytes">The <see cref="BufferSpan{T}"/> to the destination bytes.</param>
/// <param name="count">The number of pixels to convert.</param>
internal virtual void ToXyzwBytes(
BufferSpan<TColor> sourceColors,
BufferSpan<byte> destBytes,
int count)
internal virtual void ToXyzwBytes(BufferSpan<TColor> sourceColors, BufferSpan<byte> destBytes, int count)
{
ref TColor sourceRef = ref sourceColors.DangerousGetPinnableReference();
byte[] dest = destBytes.Array;
@ -162,10 +147,7 @@ namespace ImageSharp
/// <param name="sourceBytes">The <see cref="BufferSpan{T}"/> to the source bytes.</param>
/// <param name="destColors">The <see cref="BufferSpan{T}"/> to the destination colors.</param>
/// <param name="count">The number of pixels to convert.</param>
internal virtual void PackFromZyxBytes(
BufferSpan<byte> sourceBytes,
BufferSpan<TColor> destColors,
int count)
internal virtual void PackFromZyxBytes(BufferSpan<byte> sourceBytes, BufferSpan<TColor> destColors, int count)
{
ref byte sourceRef = ref sourceBytes.DangerousGetPinnableReference();
ref TColor destRef = ref destColors.DangerousGetPinnableReference();
@ -206,10 +188,7 @@ namespace ImageSharp
/// <param name="sourceBytes">The <see cref="BufferSpan{T}"/> to the source bytes.</param>
/// <param name="destColors">The <see cref="BufferSpan{T}"/> to the destination colors.</param>
/// <param name="count">The number of pixels to convert.</param>
internal virtual void PackFromZyxwBytes(
BufferSpan<byte> sourceBytes,
BufferSpan<TColor> destColors,
int count)
internal virtual void PackFromZyxwBytes(BufferSpan<byte> sourceBytes, BufferSpan<TColor> destColors, int count)
{
ref byte sourceRef = ref sourceBytes.DangerousGetPinnableReference();
ref TColor destRef = ref destColors.DangerousGetPinnableReference();
@ -232,10 +211,7 @@ namespace ImageSharp
/// <param name="sourceColors">The <see cref="BufferSpan{T}"/> to the source colors.</param>
/// <param name="destBytes">The <see cref="BufferSpan{T}"/> to the destination bytes.</param>
/// <param name="count">The number of pixels to convert.</param>
internal virtual void ToZyxwBytes(
BufferSpan<TColor> sourceColors,
BufferSpan<byte> destBytes,
int count)
internal virtual void ToZyxwBytes(BufferSpan<TColor> sourceColors, BufferSpan<byte> destBytes, int count)
{
ref TColor sourceRef = ref sourceColors.DangerousGetPinnableReference();
byte[] dest = destBytes.Array;

21
tests/ImageSharp.Benchmarks/Samplers/Resize.cs

@ -11,6 +11,7 @@ namespace ImageSharp.Benchmarks
using BenchmarkDotNet.Attributes;
using CoreSize = ImageSharp.Size;
using CoreImage = ImageSharp.Image;
using CoreVectorImage = ImageSharp.Image<ImageSharp.Color>;
public class Resize : BenchmarkBase
{
@ -44,6 +45,16 @@ namespace ImageSharp.Benchmarks
}
}
[Benchmark(Description = "ImageSharp Vector Resize")]
public CoreSize ResizeCoreVector()
{
using (CoreVectorImage image = new CoreVectorImage(2000, 2000))
{
image.Resize(400, 400);
return new CoreSize(image.Width, image.Height);
}
}
[Benchmark(Description = "ImageSharp Compand Resize")]
public CoreSize ResizeCoreCompand()
{
@ -53,5 +64,15 @@ namespace ImageSharp.Benchmarks
return new CoreSize(image.Width, image.Height);
}
}
[Benchmark(Description = "ImageSharp Vector Compand Resize")]
public CoreSize ResizeCoreVectorCompand()
{
using (CoreVectorImage image = new CoreVectorImage(2000, 2000))
{
image.Resize(400, 400, true);
return new CoreSize(image.Width, image.Height);
}
}
}
}

Loading…
Cancel
Save