/// <inheritdoc /> 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(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); } }
public static unsafe void Copy <T>(BufferSpan <T> source, BufferSpan <T> destination, int count) where T : struct { DebugGuard.MustBeLessThanOrEqualTo(count, source.Length, nameof(count)); DebugGuard.MustBeLessThanOrEqualTo(count, destination.Length, nameof(count)); ref byte srcRef = ref Unsafe.As <T, byte>(ref source.DangerousGetPinnableReference());
private static unsafe void CopyImpl <T, TDest>(BufferSpan <T> source, BufferSpan <TDest> destination, int count) where T : struct where TDest : struct { int byteCount = SizeOf <T>(count); if (byteCount > ByteCountThreshold) { if (Unsafe.SizeOf <T>() == sizeof(long)) { Marshal.Copy(Unsafe.As <long[]>(source.Array), source.Start, destination.PointerAtOffset, count); return; } else if (Unsafe.SizeOf <T>() == sizeof(int)) { Marshal.Copy(Unsafe.As <int[]>(source.Array), source.Start, destination.PointerAtOffset, count); return; } else if (Unsafe.SizeOf <T>() == sizeof(short)) { Marshal.Copy(Unsafe.As <short[]>(source.Array), source.Start, destination.PointerAtOffset, count); return; } else if (Unsafe.SizeOf <T>() == sizeof(byte)) { Marshal.Copy(Unsafe.As <byte[]>(source.Array), source.Start, destination.PointerAtOffset, count); return; } } Unsafe.CopyBlock((void *)destination.PointerAtOffset, (void *)source.PointerAtOffset, (uint)byteCount); }
private void CopyFromXyzw(PixelArea <TColor> area, int targetX, int targetY, int width, int height) { for (int y = 0; y < height; y++) { BufferSpan <byte> source = area.GetRowSpan(y); BufferSpan <TColor> destination = this.GetRowSpan(targetX, targetY + y); Operations.PackFromXyzwBytes(source, destination, width); } }
/// <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 <Color> sourceColors, BufferSpan <Vector4> destVectors, int count) { if (!Vector.IsHardwareAccelerated) { throw new InvalidOperationException( "Color.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; uint *src = (uint *)sourceColors.PointerAtOffset; uint *srcEnd = src + count; using (PinnedBuffer <uint> tempBuf = new PinnedBuffer <uint>( unpackedRawCount + Vector <uint> .Count)) { uint * tPtr = (uint *)tempBuf.Pointer; uint[] temp = tempBuf.Array; float[] fTemp = Unsafe.As <float[]>(temp); UnpackedRGBA *dst = (UnpackedRGBA *)tPtr; for (; src < srcEnd; src++, dst++) { // This call is the bottleneck now: dst->Load(*src); } 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 <uint>(tempBuf, (BufferSpan <byte>)destVectors, unpackedRawCount); } }
private void CopyToXyzw(PixelArea <TColor> area, int sourceX, int sourceY, int width, int height) { for (int y = 0; y < height; y++) { BufferSpan <TColor> source = this.GetRowSpan(sourceX, sourceY + y); BufferSpan <byte> destination = area.GetRowSpan(y); Operations.ToXyzwBytes(source, destination, width); } }
/// <summary> /// Returns a reference to specified element of the span. /// </summary> /// <param name="index">The index</param> /// <returns>The reference to the specified element</returns> public ref T this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { DebugGuard.MustBeLessThan(index, this.Length, nameof(index)); byte *ptr = (byte *)this.PointerAtOffset + BufferSpan.SizeOf <T>(index); return(ref Unsafe.AsRef <T>(ptr)); } }
public BufferSpan <T> Slice(int start) { DebugGuard.MustBeLessThan(start, this.Length, nameof(start)); BufferSpan <T> result = default(BufferSpan <T>); result.Array = this.Array; result.Start = this.Start + start; result.PointerAtOffset = this.PointerAtOffset + (Unsafe.SizeOf <T>() * start); result.Length = this.Length - start; return(result); }
/// <summary> /// Bulk version of <see cref="IPixel.ToZyxBytes(byte[], int)"/>. /// </summary> /// <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 ToZyxBytes(BufferSpan <TColor> sourceColors, BufferSpan <byte> destBytes, int count) { byte *sp = (byte *)sourceColors; byte[] dest = destBytes.Array; for (int i = destBytes.Start; i < destBytes.Start + (count * 3); i += 3) { TColor c = Unsafe.Read <TColor>(sp); c.ToZyxBytes(dest, i); sp += ColorSize; } }
/// <inheritdoc /> internal override unsafe void PackFromZyxwBytes(BufferSpan <byte> sourceBytes, BufferSpan <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; } }
public void Clear(int count) { DebugGuard.MustBeLessThanOrEqualTo(count, this.Length, nameof(count)); if (count < 256) { Unsafe.InitBlock((void *)this.PointerAtOffset, 0, BufferSpan.USizeOf <T>(count)); } else { System.Array.Clear(this.Array, this.Start, count); } }
public static unsafe void Copy <T>(BufferSpan <byte> source, BufferSpan <T> destination, int countInDest) where T : struct { int byteCount = SizeOf <T>(countInDest); if (byteCount > (int)ByteCountThreshold) { Marshal.Copy(source.Array, source.Start, destination.PointerAtOffset, byteCount); } else { Unsafe.CopyBlock((void *)destination.PointerAtOffset, (void *)source.PointerAtOffset, (uint)byteCount); } }
/// <inheritdoc /> internal override unsafe void ToZyxBytes(BufferSpan <Color> sourceColors, BufferSpan <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; } }
/// <summary> /// Bulk version of <see cref="IPixel.ToVector4()"/>. /// </summary> /// <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) { 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">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) { 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.PackFromVector4(Vector4)"/> /// </summary> /// <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) { 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> /// 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 void ToVector4SimdAligned(BufferSpan <Rgba32> sourceColors, BufferSpan <Vector4> destVectors, int count) { if (!Vector.IsHardwareAccelerated) { throw new InvalidOperationException( "Rgba32.PixelOperations.ToVector4SimdAligned() should not be called when Vector.IsHardwareAccelerated == false!"); } DebugGuard.IsTrue( count % Vector <uint> .Count == 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 sourceBase = ref Unsafe.As <Rgba32, uint>(ref sourceColors.DangerousGetPinnableReference());
/// <summary> /// Bulk version of <see cref="IPixel.PackFromVector4(Vector4)"/> /// </summary> /// <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) { ref Vector4 sourceRef = ref sourceVectors.DangerousGetPinnableReference();
/// <summary> /// Copies the pixels to another <see cref="PixelAccessor{TColor}"/> of the same size. /// </summary> /// <param name="target">The target pixel buffer accessor.</param> internal void CopyTo(PixelAccessor <TColor> target) { BufferSpan.Copy(this.pixelBuffer.Span, target.pixelBuffer.Span); }
/// <inheritdoc /> internal override void PackFromXyzwBytes(BufferSpan <byte> sourceBytes, BufferSpan <Color> destColors, int count) { BufferSpan.Copy(sourceBytes, destColors, count); }
public static ref Vector <T> FetchVector <T>(this BufferSpan <T> span) where T : struct { return(ref Unsafe.As <T, Vector <T> >(ref span.DangerousGetPinnableReference())); }
/// <inheritdoc /> internal override void ToXyzwBytes(BufferSpan <Color> sourceColors, BufferSpan <byte> destBytes, int count) { BufferSpan.Copy(sourceColors, destBytes, count); }
public static void Copy <T>(BufferSpan <T> source, BufferSpan <byte> destination, int countInSource) where T : struct { CopyImpl(source, destination, countInSource); }
/// <inheritdoc /> internal override unsafe void ToVector4(BufferSpan <ColorVector> sourceColors, BufferSpan <Vector4> destVectors, int count) { BufferSpan.Copy(sourceColors.AsBytes(), destVectors.AsBytes(), count * sizeof(Vector4)); }