mirror of https://github.com/SixLabors/ImageSharp
1 changed files with 91 additions and 0 deletions
@ -0,0 +1,91 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System.Runtime.CompilerServices; |
|||
using System.Runtime.InteropServices; |
|||
using System.Runtime.Intrinsics; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Jxl.Processing; |
|||
|
|||
/// <summary>
|
|||
/// Inverse Move to Front implementation
|
|||
/// </summary>
|
|||
internal static class JxlInverseMtf |
|||
{ |
|||
// NOTE: here we use Vector512 to store 64 bytes in a
|
|||
// more efficient manner. However, it doesn't necessarily
|
|||
// require 512-bit CPU vector support.
|
|||
// If the user's CPU has 256-bit vectors, the JIT will emit
|
|||
// such instructions for each half. Likewise, if the user's
|
|||
// CPU only goes up to 128-bit vectors, the JIT will emit
|
|||
// 128-bit vector code for each quarter. And if the CPU
|
|||
// doesn't support SIMD at all, the JIT will emit scalar
|
|||
// instructions.
|
|||
public static void MoveToFront(Span<byte> v, byte index) |
|||
{ |
|||
byte value = v[index]; |
|||
byte i = index; |
|||
|
|||
ref byte vR = ref MemoryMarshal.GetReference(v); |
|||
|
|||
if (i < 4) |
|||
{ |
|||
for (; i != 0; --i) |
|||
{ |
|||
v[i] = v[i - 1]; |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
int tail = i & 63; |
|||
|
|||
if (tail != 0) |
|||
{ |
|||
i -= (byte)tail; |
|||
Vector512<byte> vec = Vector512.LoadUnsafe(ref Unsafe.Add(ref vR, i)); |
|||
Vector512<byte> prev = Vector512.LoadUnsafe(ref Unsafe.Add(ref vR, i + 1)); |
|||
|
|||
// TODO: optimize this?
|
|||
Span<byte> maskBytes = stackalloc byte[64]; |
|||
|
|||
for (int j = 0; j < 64; j++) |
|||
{ |
|||
maskBytes[j] = (byte)(j < tail ? 0xFF : 0); |
|||
} |
|||
|
|||
Vector512<byte> mask = Vector512.Create<byte>(maskBytes); |
|||
Vector512<byte> filter = Vector512.ConditionalSelect(mask, vec, prev); |
|||
filter.StoreUnsafe(ref Unsafe.Add(ref vR, i + 1)); |
|||
} |
|||
|
|||
while (i != 0) |
|||
{ |
|||
i -= 64; |
|||
Vector512<byte> vec = Vector512.LoadUnsafe(ref Unsafe.Add(ref vR, i)); |
|||
vec.StoreUnsafe(ref Unsafe.Add(ref vR, i + 1)); |
|||
} |
|||
} |
|||
|
|||
v[0] = value; |
|||
} |
|||
|
|||
public static void InverseMoveToFrontTransform(Span<byte> v, int vLength) |
|||
{ |
|||
Span<byte> mtf = stackalloc byte[256 + 64]; |
|||
for (int i = 0; i < 256; i++) |
|||
{ |
|||
mtf[i] = (byte)i; |
|||
} |
|||
|
|||
for (int i = 0; i < vLength; i++) |
|||
{ |
|||
byte index = v[i]; |
|||
v[i] = mtf[index]; |
|||
|
|||
if (index != 0) |
|||
{ |
|||
MoveToFront(mtf, index); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue