|
|
|
@ -4,9 +4,15 @@ |
|
|
|
using System; |
|
|
|
using System.Buffers; |
|
|
|
using System.Runtime.CompilerServices; |
|
|
|
using System.Runtime.InteropServices; |
|
|
|
using SixLabors.ImageSharp.Memory; |
|
|
|
using SixLabors.ImageSharp.PixelFormats; |
|
|
|
|
|
|
|
#if SUPPORTS_RUNTIME_INTRINSICS
|
|
|
|
using System.Runtime.Intrinsics; |
|
|
|
using System.Runtime.Intrinsics.X86; |
|
|
|
#endif
|
|
|
|
|
|
|
|
namespace SixLabors.ImageSharp.Formats.Webp.Lossy |
|
|
|
{ |
|
|
|
internal static class YuvConversion |
|
|
|
@ -96,13 +102,74 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy |
|
|
|
/// <param name="row">The row to check.</param>
|
|
|
|
/// <returns>Returns true if alpha has non-0xff values.</returns>
|
|
|
|
[MethodImpl(InliningOptions.ShortMethod)] |
|
|
|
public static bool CheckNonOpaque(Span<Rgba32> row) |
|
|
|
public static unsafe bool CheckNonOpaque(Span<Rgba32> row) |
|
|
|
{ |
|
|
|
for (int x = 0; x < row.Length; x++) |
|
|
|
#if SUPPORTS_RUNTIME_INTRINSICS
|
|
|
|
if (Sse2.IsSupported) |
|
|
|
{ |
|
|
|
ReadOnlySpan<byte> rowBytes = MemoryMarshal.AsBytes(row); |
|
|
|
var alphaMask = Vector128.Create(0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255); |
|
|
|
Vector128<byte> all0x80 = Vector128.Create((byte)0x80).AsByte(); |
|
|
|
|
|
|
|
int i = 0; |
|
|
|
int length = (row.Length * 4) - 3; |
|
|
|
fixed (byte* src = rowBytes) |
|
|
|
{ |
|
|
|
for (; i + 64 <= length; i += 64) |
|
|
|
{ |
|
|
|
Vector128<byte> a0 = Sse2.LoadVector128(src + i).AsByte(); |
|
|
|
Vector128<byte> a1 = Sse2.LoadVector128(src + i + 16).AsByte(); |
|
|
|
Vector128<byte> a2 = Sse2.LoadVector128(src + i + 32).AsByte(); |
|
|
|
Vector128<byte> a3 = Sse2.LoadVector128(src + i + 48).AsByte(); |
|
|
|
Vector128<int> b0 = Sse2.And(a0, alphaMask).AsInt32(); |
|
|
|
Vector128<int> b1 = Sse2.And(a1, alphaMask).AsInt32(); |
|
|
|
Vector128<int> b2 = Sse2.And(a2, alphaMask).AsInt32(); |
|
|
|
Vector128<int> b3 = Sse2.And(a3, alphaMask).AsInt32(); |
|
|
|
Vector128<short> c0 = Sse2.PackSignedSaturate(b0, b1).AsInt16(); |
|
|
|
Vector128<short> c1 = Sse2.PackSignedSaturate(b2, b3).AsInt16(); |
|
|
|
Vector128<byte> d = Sse2.PackSignedSaturate(c0, c1).AsByte(); |
|
|
|
Vector128<byte> bits = Sse2.CompareEqual(d, all0x80); |
|
|
|
int mask = Sse2.MoveMask(bits); |
|
|
|
if (mask != 0xFFFF) |
|
|
|
{ |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
for (; i + 32 <= length; i += 32) |
|
|
|
{ |
|
|
|
Vector128<byte> a0 = Sse2.LoadVector128(src + i).AsByte(); |
|
|
|
Vector128<byte> a1 = Sse2.LoadVector128(src + i + 16).AsByte(); |
|
|
|
Vector128<int> b0 = Sse2.And(a0, alphaMask).AsInt32(); |
|
|
|
Vector128<int> b1 = Sse2.And(a1, alphaMask).AsInt32(); |
|
|
|
Vector128<short> c = Sse2.PackSignedSaturate(b0, b1).AsInt16(); |
|
|
|
Vector128<byte> d = Sse2.PackSignedSaturate(c, c).AsByte(); |
|
|
|
Vector128<byte> bits = Sse2.CompareEqual(d, all0x80); |
|
|
|
int mask = Sse2.MoveMask(bits); |
|
|
|
if (mask != 0xFFFF) |
|
|
|
{ |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
for (; i <= length; i += 4) |
|
|
|
{ |
|
|
|
if (src[i + 3] != 0xFF) |
|
|
|
{ |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
|
|
#endif
|
|
|
|
{ |
|
|
|
if (row[x].A != 255) |
|
|
|
for (int x = 0; x < row.Length; x++) |
|
|
|
{ |
|
|
|
return true; |
|
|
|
if (row[x].A != 0xFF) |
|
|
|
{ |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|