Browse Source

Enable Sse2, simplify

pull/2588/head
James Jackson-South 2 years ago
parent
commit
5da17f3992
  1. 31
      src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs
  2. 46
      src/ImageSharp/Formats/AnimationUtilities.cs
  3. 5
      src/ImageSharp/Formats/Gif/GifEncoderCore.cs
  4. 17
      src/ImageSharp/Formats/Png/PngMetadata.cs
  5. 1
      tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs

31
src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs

@ -1,6 +1,7 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Intrinsics;
@ -656,6 +657,36 @@ internal static partial class SimdUtils
return AdvSimd.BitwiseSelect(signedMask, right.AsInt16(), left.AsInt16()).AsByte();
}
/// <summary>
/// Blend packed 32-bit unsigned integers from <paramref name="left"/> and <paramref name="right"/> using <paramref name="mask"/>.
/// The high bit of each corresponding <paramref name="mask"/> byte determines the selection.
/// If the high bit is set the element of <paramref name="left"/> is selected.
/// The element of <paramref name="right"/> is selected otherwise.
/// </summary>
/// <param name="left">The left vector.</param>
/// <param name="right">The right vector.</param>
/// <param name="mask">The mask vector.</param>
/// <returns>The <see cref="Vector256{T}"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector128<uint> BlendVariable(Vector128<uint> left, Vector128<uint> right, Vector128<uint> mask)
=> BlendVariable(left.AsByte(), right.AsByte(), mask.AsByte()).AsUInt32();
/// <summary>
/// Count the number of leading zero bits in a mask.
/// Similar in behavior to the x86 instruction LZCNT.
/// </summary>
/// <param name="value">The value.</param>
public static ushort LeadingZeroCount(ushort value)
=> (ushort)(BitOperations.LeadingZeroCount(value) - 16);
/// <summary>
/// Count the number of trailing zero bits in an integer value.
/// Similar in behavior to the x86 instruction TZCNT.
/// </summary>
/// <param name="value">The value.</param>
public static ushort TrailingZeroCount(ushort value)
=> (ushort)(BitOperations.TrailingZeroCount(value << 16) - 16);
/// <summary>
/// <see cref="ByteToNormalizedFloat"/> as many elements as possible, slicing them down (keeping the remainder).
/// </summary>

46
src/ImageSharp/Formats/AnimationUtilities.cs

@ -128,6 +128,52 @@ internal static class AnimationUtilities
}
}
if (Sse2.IsSupported && remaining >= 4)
{
Vector128<uint> r128 = previousFrame != null ? Vector128.Create(bg.PackedValue) : Vector128<uint>.Zero;
Vector128<uint> vmb128 = Vector128<uint>.Zero;
if (blend)
{
vmb128 = Sse2.CompareEqual(vmb128, vmb128);
}
while (remaining >= 4)
{
Vector128<uint> p = Unsafe.Add(ref Unsafe.As<Vector256<byte>, Vector128<uint>>(ref previousBase), x);
Vector128<uint> c = Unsafe.Add(ref Unsafe.As<Vector256<byte>, Vector128<uint>>(ref currentBase), x);
Vector128<uint> eq = Sse2.CompareEqual(p, c);
Vector128<uint> r = SimdUtils.HwIntrinsics.BlendVariable(c, r128, Sse2.And(eq, vmb128));
if (nextFrame != null)
{
Vector128<int> n = Sse2.ShiftRightLogical(Unsafe.Add(ref Unsafe.As<Vector256<byte>, Vector128<uint>>(ref nextBase), x), 24).AsInt32();
eq = Sse2.AndNot(Sse2.CompareGreaterThan(Sse2.ShiftRightLogical(c, 24).AsInt32(), n).AsUInt32(), eq);
}
Unsafe.Add(ref Unsafe.As<Vector256<byte>, Vector128<byte>>(ref resultBase), x) = r.AsByte();
ushort msk = (ushort)(uint)Sse2.MoveMask(eq.AsByte());
msk = (ushort)~msk;
if (msk != 0)
{
// If is diff is found, the left side is marked by the min of previously found left side and the start position.
// The right is the max of the previously found right side and the end position.
int start = i + (SimdUtils.HwIntrinsics.TrailingZeroCount(msk) / sizeof(uint));
int end = i + (4 - (SimdUtils.HwIntrinsics.LeadingZeroCount(msk) / sizeof(uint)));
left = Math.Min(left, start);
right = Math.Max(right, end);
hasRowDiff = true;
hasDiff = true;
}
x++;
i += 4;
remaining -= 4;
}
}
// TODO: AdvSimd ??
for (i = remaining; i > 0; i--)
{
x = (uint)(length - i);

5
src/ImageSharp/Formats/Gif/GifEncoderCore.cs

@ -168,7 +168,7 @@ internal sealed class GifEncoderCore : IImageEncoderInternals
stream.WriteByte(GifConstants.EndIntroducer);
quantized.Dispose();
quantized?.Dispose();
}
private static GifMetadata GetGifMetadata<TPixel>(Image<TPixel> image)
@ -251,6 +251,7 @@ internal sealed class GifEncoderCore : IImageEncoderInternals
{
// Gather the metadata for this frame.
ImageFrame<TPixel> currentFrame = image.Frames[i];
ImageFrame<TPixel>? nextFrame = i < image.Frames.Count - 1 ? image.Frames[i + 1] : null;
GifFrameMetadata gifMetadata = GetGifFrameMetadata(currentFrame, globalTransparencyIndex);
bool useLocal = this.colorTableMode == GifColorTableMode.Local || (gifMetadata.ColorTableMode == GifColorTableMode.Local);
@ -264,8 +265,6 @@ internal sealed class GifEncoderCore : IImageEncoderInternals
hasPaletteQuantizer = true;
}
ImageFrame<TPixel>? nextFrame = i < image.Frames.Count - 1 ? image.Frames[i + 1] : null;
this.EncodeAdditionalFrame(
stream,
previousFrame,

17
src/ImageSharp/Formats/Png/PngMetadata.cs

@ -90,13 +90,12 @@ public class PngMetadata : IDeepCloneable
{
// Should the conversion be from a format that uses a 24bit palette entries (gif)
// we need to clone and adjust the color table to allow for transparency.
ReadOnlyMemory<Color>? colorTable = metadata.ColorTable;
if (metadata.ColorTable.HasValue)
Color[]? colorTable = metadata.ColorTable.HasValue ? metadata.ColorTable.Value.ToArray() : null;
if (colorTable != null)
{
Color[] clone = metadata.ColorTable.Value.ToArray();
for (int i = 0; i < clone.Length; i++)
for (int i = 0; i < colorTable.Length; i++)
{
ref Color c = ref clone[i];
ref Color c = ref colorTable[i];
if (c == metadata.BackgroundColor)
{
// Png treats background as fully empty
@ -104,15 +103,13 @@ public class PngMetadata : IDeepCloneable
break;
}
}
colorTable = clone;
}
return new()
{
ColorType = colorTable.HasValue ? PngColorType.Palette : null,
BitDepth = colorTable.HasValue
? (PngBitDepth)Numerics.Clamp(ColorNumerics.GetBitsNeededForColorDepth(colorTable.Value.Length), 1, 8)
ColorType = colorTable != null ? PngColorType.Palette : null,
BitDepth = colorTable != null
? (PngBitDepth)Numerics.Clamp(ColorNumerics.GetBitsNeededForColorDepth(colorTable.Length), 1, 8)
: null,
ColorTable = colorTable,
RepeatCount = metadata.RepeatCount,

1
tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs

@ -1,7 +1,6 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Diagnostics.CodeAnalysis;
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Formats.Bmp;
using SixLabors.ImageSharp.Formats.Gif;

Loading…
Cancel
Save