Skip to content
Merged
26 changes: 26 additions & 0 deletions src/ImageSharp/Common/Helpers/BitOperations.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.

using System.Runtime.CompilerServices;

#if !NETCOREAPP3_1
namespace SixLabors.ImageSharp.Common.Helpers
{
/// <summary>
/// Polyfill for System.Numerics.BitOperations class, introduced in .NET Core 3.0.
/// <see href="https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Numerics/BitOperations.cs"/>
/// </summary>
public static class BitOperations
{
/// <summary>
/// Rotates the specified value left by the specified number of bits.
/// </summary>
/// <param name="value">The value to rotate.</param>
/// <param name="offset">The number of bits to roate with.</param>
/// <returns>The rotated value.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static uint RotateLeft(uint value, int offset)
=> (value << offset) | (value >> (32 - offset));
}
}
#endif
46 changes: 24 additions & 22 deletions src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@

using System;
using System.Buffers.Binary;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Common.Helpers;

// The JIT can detect and optimize rotation idioms ROTL (Rotate Left)
// and ROTR (Rotate Right) emitting efficient CPU instructions:
Expand Down Expand Up @@ -97,15 +99,15 @@ public void RunFallbackShuffle(ReadOnlySpan<byte> source, Span<byte> dest)
{
ref uint sBase = ref Unsafe.As<byte, uint>(ref MemoryMarshal.GetReference(source));
ref uint dBase = ref Unsafe.As<byte, uint>(ref MemoryMarshal.GetReference(dest));
int n = source.Length / 4;
nuint n = (nuint)(uint)source.Length / 4;

for (int i = 0; i < n; i++)
for (nuint i = 0; i < n; i++)
{
uint packed = Unsafe.Add(ref sBase, i);
uint packed = Unsafe.Add(ref sBase, (int)i);

// packed = [W Z Y X]
// ROTL(8, packed) = [Z Y X W]
Unsafe.Add(ref dBase, i) = (packed << 8) | (packed >> 24);
Unsafe.Add(ref dBase, (int)i) = (packed << 8) | (packed >> 24);
}
}
}
Expand All @@ -123,15 +125,15 @@ public void RunFallbackShuffle(ReadOnlySpan<byte> source, Span<byte> dest)
{
ref uint sBase = ref Unsafe.As<byte, uint>(ref MemoryMarshal.GetReference(source));
ref uint dBase = ref Unsafe.As<byte, uint>(ref MemoryMarshal.GetReference(dest));
int n = source.Length / 4;
nuint n = (nuint)(uint)source.Length / 4;

for (int i = 0; i < n; i++)
for (nuint i = 0; i < n; i++)
{
uint packed = Unsafe.Add(ref sBase, i);
uint packed = Unsafe.Add(ref sBase, (int)i);

// packed = [W Z Y X]
// REVERSE(packedArgb) = [X Y Z W]
Unsafe.Add(ref dBase, i) = BinaryPrimitives.ReverseEndianness(packed);
Unsafe.Add(ref dBase, (int)i) = BinaryPrimitives.ReverseEndianness(packed);
}
}
}
Expand All @@ -149,15 +151,15 @@ public void RunFallbackShuffle(ReadOnlySpan<byte> source, Span<byte> dest)
{
ref uint sBase = ref Unsafe.As<byte, uint>(ref MemoryMarshal.GetReference(source));
ref uint dBase = ref Unsafe.As<byte, uint>(ref MemoryMarshal.GetReference(dest));
int n = source.Length / 4;
nuint n = (nuint)(uint)source.Length / 4;

for (int i = 0; i < n; i++)
for (nuint i = 0; i < n; i++)
{
uint packed = Unsafe.Add(ref sBase, i);
uint packed = Unsafe.Add(ref sBase, (int)i);

// packed = [W Z Y X]
// ROTR(8, packedArgb) = [Y Z W X]
Unsafe.Add(ref dBase, i) = (packed >> 8) | (packed << 24);
Unsafe.Add(ref dBase, (int)i) = (packed >> 8) | (packed << 24);
}
}
}
Expand All @@ -175,11 +177,11 @@ public void RunFallbackShuffle(ReadOnlySpan<byte> source, Span<byte> dest)
{
ref uint sBase = ref Unsafe.As<byte, uint>(ref MemoryMarshal.GetReference(source));
ref uint dBase = ref Unsafe.As<byte, uint>(ref MemoryMarshal.GetReference(dest));
int n = source.Length / 4;
nuint n = (nuint)(uint)source.Length / 4;

for (int i = 0; i < n; i++)
for (nuint i = 0; i < n; i++)
{
uint packed = Unsafe.Add(ref sBase, i);
uint packed = Unsafe.Add(ref sBase, (int)i);

// packed = [W Z Y X]
// tmp1 = [W 0 Y 0]
Expand All @@ -188,9 +190,9 @@ public void RunFallbackShuffle(ReadOnlySpan<byte> source, Span<byte> dest)
// tmp1 + tmp3 = [W X Y Z]
uint tmp1 = packed & 0xFF00FF00;
uint tmp2 = packed & 0x00FF00FF;
uint tmp3 = (tmp2 << 16) | (tmp2 >> 16);
uint tmp3 = BitOperations.RotateLeft(tmp2, 16);

Unsafe.Add(ref dBase, i) = tmp1 + tmp3;
Unsafe.Add(ref dBase, (int)i) = tmp1 + tmp3;
}
}
}
Expand All @@ -208,11 +210,11 @@ public void RunFallbackShuffle(ReadOnlySpan<byte> source, Span<byte> dest)
{
ref uint sBase = ref Unsafe.As<byte, uint>(ref MemoryMarshal.GetReference(source));
ref uint dBase = ref Unsafe.As<byte, uint>(ref MemoryMarshal.GetReference(dest));
int n = source.Length / 4;
nuint n = (nuint)(uint)source.Length / 4;

for (int i = 0; i < n; i++)
for (nuint i = 0; i < n; i++)
{
uint packed = Unsafe.Add(ref sBase, i);
uint packed = Unsafe.Add(ref sBase, (int)i);

// packed = [W Z Y X]
// tmp1 = [0 Z 0 X]
Expand All @@ -221,9 +223,9 @@ public void RunFallbackShuffle(ReadOnlySpan<byte> source, Span<byte> dest)
// tmp1 + tmp3 = [Y Z W X]
uint tmp1 = packed & 0x00FF00FF;
uint tmp2 = packed & 0xFF00FF00;
uint tmp3 = (tmp2 << 16) | (tmp2 >> 16);
uint tmp3 = BitOperations.RotateLeft(tmp2, 16);

Unsafe.Add(ref dBase, i) = tmp1 + tmp3;
Unsafe.Add(ref dBase, (int)i) = tmp1 + tmp3;
}
}
}
Expand Down
8 changes: 5 additions & 3 deletions src/ImageSharp/PixelFormats/PixelImplementations/Abgr32.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.

using System;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
Expand Down Expand Up @@ -214,9 +215,10 @@ public uint PackedValue
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgr24(Bgr24 source)
{
this.R = source.R;
this.G = source.G;
this.B = source.B;
// We can assign the Bgr24 value directly to last three bytes of this instance.
ref byte thisRef = ref Unsafe.As<Abgr32, byte>(ref this);
ref byte thisRefFromB = ref Unsafe.AddByteOffset(ref thisRef, new IntPtr(1));
Unsafe.As<byte, Bgr24>(ref thisRefFromB) = source;
this.A = byte.MaxValue;
}

Expand Down
7 changes: 4 additions & 3 deletions src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs
Original file line number Diff line number Diff line change
Expand Up @@ -189,9 +189,10 @@ public void FromRgb24(Rgb24 source)
[MethodImpl(InliningOptions.ShortMethod)]
public void FromAbgr32(Abgr32 source)
{
this.R = source.R;
this.G = source.G;
this.B = source.B;
// We can assign this instances value directly to last three bytes of the Abgr32.
ref byte sourceRef = ref Unsafe.As<Abgr32, byte>(ref source);
ref byte sourceRefFromB = ref Unsafe.AddByteOffset(ref sourceRef, new IntPtr(1));
this = Unsafe.As<byte, Bgr24>(ref sourceRefFromB);
}

/// <inheritdoc/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -204,10 +204,10 @@ public override void ToL8(
ref Abgr32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref L8 destRef = ref MemoryMarshal.GetReference(destinationPixels);

for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Abgr32 sp = ref Unsafe.Add(ref sourceRef, i);
ref L8 dp = ref Unsafe.Add(ref destRef, i);
ref Abgr32 sp = ref Unsafe.Add(ref sourceRef, (int)i);
ref L8 dp = ref Unsafe.Add(ref destRef, (int)i);

dp.FromAbgr32(sp);
}
Expand All @@ -224,10 +224,10 @@ public override void ToL16(
ref Abgr32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref L16 destRef = ref MemoryMarshal.GetReference(destinationPixels);

for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Abgr32 sp = ref Unsafe.Add(ref sourceRef, i);
ref L16 dp = ref Unsafe.Add(ref destRef, i);
ref Abgr32 sp = ref Unsafe.Add(ref sourceRef, (int)i);
ref L16 dp = ref Unsafe.Add(ref destRef, (int)i);

dp.FromAbgr32(sp);
}
Expand All @@ -244,10 +244,10 @@ public override void ToLa16(
ref Abgr32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref La16 destRef = ref MemoryMarshal.GetReference(destinationPixels);

for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Abgr32 sp = ref Unsafe.Add(ref sourceRef, i);
ref La16 dp = ref Unsafe.Add(ref destRef, i);
ref Abgr32 sp = ref Unsafe.Add(ref sourceRef, (int)i);
ref La16 dp = ref Unsafe.Add(ref destRef, (int)i);

dp.FromAbgr32(sp);
}
Expand All @@ -264,10 +264,10 @@ public override void ToLa32(
ref Abgr32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref La32 destRef = ref MemoryMarshal.GetReference(destinationPixels);

for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Abgr32 sp = ref Unsafe.Add(ref sourceRef, i);
ref La32 dp = ref Unsafe.Add(ref destRef, i);
ref Abgr32 sp = ref Unsafe.Add(ref sourceRef, (int)i);
ref La32 dp = ref Unsafe.Add(ref destRef, (int)i);

dp.FromAbgr32(sp);
}
Expand All @@ -284,10 +284,10 @@ public override void ToRgb48(
ref Abgr32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgb48 destRef = ref MemoryMarshal.GetReference(destinationPixels);

for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Abgr32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb48 dp = ref Unsafe.Add(ref destRef, i);
ref Abgr32 sp = ref Unsafe.Add(ref sourceRef, (int)i);
ref Rgb48 dp = ref Unsafe.Add(ref destRef, (int)i);

dp.FromAbgr32(sp);
}
Expand All @@ -304,10 +304,10 @@ public override void ToRgba64(
ref Abgr32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgba64 destRef = ref MemoryMarshal.GetReference(destinationPixels);

for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Abgr32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgba64 dp = ref Unsafe.Add(ref destRef, i);
ref Abgr32 sp = ref Unsafe.Add(ref sourceRef, (int)i);
ref Rgba64 dp = ref Unsafe.Add(ref destRef, (int)i);

dp.FromAbgr32(sp);
}
Expand All @@ -324,10 +324,10 @@ public override void ToBgra5551(
ref Abgr32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Bgra5551 destRef = ref MemoryMarshal.GetReference(destinationPixels);

for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Abgr32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Bgra5551 dp = ref Unsafe.Add(ref destRef, i);
ref Abgr32 sp = ref Unsafe.Add(ref sourceRef, (int)i);
ref Bgra5551 dp = ref Unsafe.Add(ref destRef, (int)i);

dp.FromAbgr32(sp);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -204,10 +204,10 @@ public override void ToL8(
ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref L8 destRef = ref MemoryMarshal.GetReference(destinationPixels);

for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i);
ref L8 dp = ref Unsafe.Add(ref destRef, i);
ref Argb32 sp = ref Unsafe.Add(ref sourceRef, (int)i);
ref L8 dp = ref Unsafe.Add(ref destRef, (int)i);

dp.FromArgb32(sp);
}
Expand All @@ -224,10 +224,10 @@ public override void ToL16(
ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref L16 destRef = ref MemoryMarshal.GetReference(destinationPixels);

for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i);
ref L16 dp = ref Unsafe.Add(ref destRef, i);
ref Argb32 sp = ref Unsafe.Add(ref sourceRef, (int)i);
ref L16 dp = ref Unsafe.Add(ref destRef, (int)i);

dp.FromArgb32(sp);
}
Expand All @@ -244,10 +244,10 @@ public override void ToLa16(
ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref La16 destRef = ref MemoryMarshal.GetReference(destinationPixels);

for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i);
ref La16 dp = ref Unsafe.Add(ref destRef, i);
ref Argb32 sp = ref Unsafe.Add(ref sourceRef, (int)i);
ref La16 dp = ref Unsafe.Add(ref destRef, (int)i);

dp.FromArgb32(sp);
}
Expand All @@ -264,10 +264,10 @@ public override void ToLa32(
ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref La32 destRef = ref MemoryMarshal.GetReference(destinationPixels);

for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i);
ref La32 dp = ref Unsafe.Add(ref destRef, i);
ref Argb32 sp = ref Unsafe.Add(ref sourceRef, (int)i);
ref La32 dp = ref Unsafe.Add(ref destRef, (int)i);

dp.FromArgb32(sp);
}
Expand All @@ -284,10 +284,10 @@ public override void ToRgb48(
ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgb48 destRef = ref MemoryMarshal.GetReference(destinationPixels);

for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb48 dp = ref Unsafe.Add(ref destRef, i);
ref Argb32 sp = ref Unsafe.Add(ref sourceRef, (int)i);
ref Rgb48 dp = ref Unsafe.Add(ref destRef, (int)i);

dp.FromArgb32(sp);
}
Expand All @@ -304,10 +304,10 @@ public override void ToRgba64(
ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgba64 destRef = ref MemoryMarshal.GetReference(destinationPixels);

for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgba64 dp = ref Unsafe.Add(ref destRef, i);
ref Argb32 sp = ref Unsafe.Add(ref sourceRef, (int)i);
ref Rgba64 dp = ref Unsafe.Add(ref destRef, (int)i);

dp.FromArgb32(sp);
}
Expand All @@ -324,10 +324,10 @@ public override void ToBgra5551(
ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Bgra5551 destRef = ref MemoryMarshal.GetReference(destinationPixels);

for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Bgra5551 dp = ref Unsafe.Add(ref destRef, i);
ref Argb32 sp = ref Unsafe.Add(ref sourceRef, (int)i);
ref Bgra5551 dp = ref Unsafe.Add(ref destRef, (int)i);

dp.FromArgb32(sp);
}
Expand Down
Loading