Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Abgr32 pixel type, extend IPixel<T> #1886

Merged
merged 12 commits into from
Dec 18, 2021
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
ynse01 marked this conversation as resolved.
Show resolved Hide resolved
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));
ynse01 marked this conversation as resolved.
Show resolved Hide resolved
}
}
#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;
ynse01 marked this conversation as resolved.
Show resolved Hide resolved

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);
ynse01 marked this conversation as resolved.
Show resolved Hide resolved

// 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