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
8 changes: 2 additions & 6 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -87,13 +87,15 @@
*.eot binary
*.exe binary
*.otf binary
*.pbm binary
ynse01 marked this conversation as resolved.
Show resolved Hide resolved
*.pdf binary
*.ppt binary
*.pptx binary
*.pvr binary
*.snk binary
*.ttc binary
*.ttf binary
*.wbmp binary
*.woff binary
*.woff2 binary
*.xls binary
Expand Down Expand Up @@ -124,9 +126,3 @@
*.dds filter=lfs diff=lfs merge=lfs -text
*.ktx filter=lfs diff=lfs merge=lfs -text
*.ktx2 filter=lfs diff=lfs merge=lfs -text
*.pam filter=lfs diff=lfs merge=lfs -text
*.pbm filter=lfs diff=lfs merge=lfs -text
*.pgm filter=lfs diff=lfs merge=lfs -text
*.ppm filter=lfs diff=lfs merge=lfs -text
*.pnm filter=lfs diff=lfs merge=lfs -text
*.wbmp filter=lfs diff=lfs merge=lfs -text
2 changes: 2 additions & 0 deletions src/ImageSharp/Advanced/AotCompilerTools.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ private static void SeedPixelFormats()

Seed<A8>();
Seed<Argb32>();
Seed<Abgr32>();
Seed<Bgr24>();
Seed<Bgr565>();
Seed<Bgra32>();
Expand Down Expand Up @@ -148,6 +149,7 @@ private static unsafe void AotCompileImage<TPixel>()
Image<TPixel> img = default;
img.CloneAs<A8>(default);
img.CloneAs<Argb32>(default);
img.CloneAs<Abgr32>(default);
img.CloneAs<Bgr24>(default);
img.CloneAs<Bgr565>(default);
img.CloneAs<Bgra32>(default);
Expand Down
24 changes: 24 additions & 0 deletions src/ImageSharp/Color/Color.Conversions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,17 @@ public Color(Bgra32 pixel)
this.boxedHighPrecisionPixel = null;
}

/// <summary>
/// Initializes a new instance of the <see cref="Color"/> struct.
/// </summary>
/// <param name="pixel">The <see cref="Abgr32"/> containing the color information.</param>
[MethodImpl(InliningOptions.ShortMethod)]
public Color(Abgr32 pixel)
{
this.data = new Rgba64(pixel);
this.boxedHighPrecisionPixel = null;
}

/// <summary>
/// Initializes a new instance of the <see cref="Color"/> struct.
/// </summary>
Expand Down Expand Up @@ -177,6 +188,19 @@ internal Argb32 ToArgb32()
return value;
}

[MethodImpl(InliningOptions.ShortMethod)]
internal Abgr32 ToAbgr32()
{
if (this.boxedHighPrecisionPixel is null)
{
return this.data.ToAbgr32();
}

Abgr32 value = default;
value.FromScaledVector4(this.boxedHighPrecisionPixel.ToScaledVector4());
return value;
}

[MethodImpl(InliningOptions.ShortMethod)]
internal Rgb24 ToRgb24()
{
Expand Down
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
69 changes: 52 additions & 17 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,42 @@ 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;
}
}
}

internal readonly struct XWZYShuffle4 : IShuffle4
{
public byte Control
{
[MethodImpl(InliningOptions.ShortMethod)]
get => SimdUtils.Shuffle.MmShuffle(1, 2, 3, 0);
}

[MethodImpl(InliningOptions.ShortMethod)]
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));
nuint n = (nuint)(uint)source.Length / 4;

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

// packed = [W Z Y X]
// tmp1 = [0 Z 0 X]
// tmp2 = [W 0 Y 0]
// tmp3=ROTL(16, tmp2) = [Y 0 W 0]
// tmp1 + tmp3 = [Y Z W X]
uint tmp1 = packed & 0x00FF00FF;
uint tmp2 = packed & 0xFF00FF00;
uint tmp3 = BitOperations.RotateLeft(tmp2, 16);

Unsafe.Add(ref dBase, (int)i) = tmp1 + tmp3;
}
}
}
Expand Down
9 changes: 9 additions & 0 deletions src/ImageSharp/ImageSharp.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,11 @@
<AutoGen>True</AutoGen>
<DependentUpon>Block8x8F.Generated.tt</DependentUpon>
</Compile>
<Compile Update="PixelFormats\PixelImplementations\PixelOperations\Generated\Abgr32.PixelOperations.Generated.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Abgr32.PixelOperations.Generated.tt</DependentUpon>
</Compile>
<Compile Update="PixelFormats\PixelOperations{TPixel}.Generated.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
Expand Down Expand Up @@ -166,6 +171,10 @@
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>Block8x8F.Generated.cs</LastGenOutput>
</None>
<None Update="PixelFormats\PixelImplementations\PixelOperations\Generated\Abgr32.PixelOperations.Generated.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>Abgr32.PixelOperations.Generated.cs</LastGenOutput>
</None>
<None Update="PixelFormats\PixelOperations{TPixel}.Generated.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>PixelOperations{TPixel}.Generated.cs</LastGenOutput>
Expand Down
6 changes: 6 additions & 0 deletions src/ImageSharp/PixelFormats/IPixel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,12 @@ public interface IPixel
/// <param name="source">The <see cref="Bgra32"/> value.</param>
void FromBgra32(Bgra32 source);

/// <summary>
/// Initializes the pixel instance from an <see cref="Abgr32"/> value.
/// </summary>
/// <param name="source">The <see cref="Abgr32"/> value.</param>
void FromAbgr32(Abgr32 source);

/// <summary>
/// Initializes the pixel instance from an <see cref="L8"/> value.
/// </summary>
Expand Down
4 changes: 4 additions & 0 deletions src/ImageSharp/PixelFormats/PixelImplementations/A8.cs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@ public partial struct A8 : IPixel<A8>, IPackedVector<byte>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgra32(Bgra32 source) => this.PackedValue = source.A;

/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromAbgr32(Abgr32 source) => this.PackedValue = source.A;

/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4());
Expand Down
Loading