misc: More minor code style changes.

This commit is contained in:
Evan Husted 2024-10-12 21:43:02 -05:00
parent a989d28e03
commit df9450d2ad
9 changed files with 562 additions and 639 deletions

View file

@ -2,6 +2,7 @@ using Ryujinx.Common.GraphicsDriver.NVAPI;
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// ReSharper disable InconsistentNaming
namespace Ryujinx.Common.GraphicsDriver
{

View file

@ -1,48 +1,556 @@
using System;
using System.Buffers.Binary;
using System.Diagnostics;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Intrinsics.X86;
using System.Runtime.Intrinsics;
// ReSharper disable InconsistentNaming
namespace Ryujinx.Common
{
[StructLayout(LayoutKind.Sequential)]
public struct Hash128 : IEquatable<Hash128>
public struct Hash128(ulong low, ulong high) : IEquatable<Hash128>
{
public ulong Low;
public ulong High;
public ulong Low = low;
public ulong High = high;
public Hash128(ulong low, ulong high)
public readonly override string ToString() => $"{High:x16}{Low:x16}";
public static bool operator ==(Hash128 x, Hash128 y) => x.Equals(y);
public static bool operator !=(Hash128 x, Hash128 y) => !x.Equals(y);
public readonly override bool Equals(object obj) => obj is Hash128 hash128 && Equals(hash128);
public readonly bool Equals(Hash128 cmpObj) => Low == cmpObj.Low && High == cmpObj.High;
public readonly override int GetHashCode() => HashCode.Combine(Low, High);
public static Hash128 ComputeHash(ReadOnlySpan<byte> input) => Xxh3128bitsInternal(input, Xxh3KSecret, 0UL);
#region Hash computation
private const int StripeLen = 64;
private const int AccNb = StripeLen / sizeof(ulong);
private const int SecretConsumeRate = 8;
private const int SecretLastAccStart = 7;
private const int SecretMergeAccsStart = 11;
private const int SecretSizeMin = 136;
private const int MidSizeStartOffset = 3;
private const int MidSizeLastOffset = 17;
private const uint Prime32_1 = 0x9E3779B1U;
private const uint Prime32_2 = 0x85EBCA77U;
private const uint Prime32_3 = 0xC2B2AE3DU;
private const uint Prime32_4 = 0x27D4EB2FU;
private const uint Prime32_5 = 0x165667B1U;
private const ulong Prime64_1 = 0x9E3779B185EBCA87UL;
private const ulong Prime64_2 = 0xC2B2AE3D27D4EB4FUL;
private const ulong Prime64_3 = 0x165667B19E3779F9UL;
private const ulong Prime64_4 = 0x85EBCA77C2B2AE63UL;
private const ulong Prime64_5 = 0x27D4EB2F165667C5UL;
private static readonly ulong[] _xxh3InitAcc =
[
Prime32_3,
Prime64_1,
Prime64_2,
Prime64_3,
Prime64_4,
Prime32_2,
Prime64_5,
Prime32_1
];
private static ReadOnlySpan<byte> Xxh3KSecret =>
[
0xb8, 0xfe, 0x6c, 0x39, 0x23, 0xa4, 0x4b, 0xbe, 0x7c, 0x01, 0x81, 0x2c, 0xf7, 0x21, 0xad, 0x1c,
0xde, 0xd4, 0x6d, 0xe9, 0x83, 0x90, 0x97, 0xdb, 0x72, 0x40, 0xa4, 0xa4, 0xb7, 0xb3, 0x67, 0x1f,
0xcb, 0x79, 0xe6, 0x4e, 0xcc, 0xc0, 0xe5, 0x78, 0x82, 0x5a, 0xd0, 0x7d, 0xcc, 0xff, 0x72, 0x21,
0xb8, 0x08, 0x46, 0x74, 0xf7, 0x43, 0x24, 0x8e, 0xe0, 0x35, 0x90, 0xe6, 0x81, 0x3a, 0x26, 0x4c,
0x3c, 0x28, 0x52, 0xbb, 0x91, 0xc3, 0x00, 0xcb, 0x88, 0xd0, 0x65, 0x8b, 0x1b, 0x53, 0x2e, 0xa3,
0x71, 0x64, 0x48, 0x97, 0xa2, 0x0d, 0xf9, 0x4e, 0x38, 0x19, 0xef, 0x46, 0xa9, 0xde, 0xac, 0xd8,
0xa8, 0xfa, 0x76, 0x3f, 0xe3, 0x9c, 0x34, 0x3f, 0xf9, 0xdc, 0xbb, 0xc7, 0xc7, 0x0b, 0x4f, 0x1d,
0x8a, 0x51, 0xe0, 0x4b, 0xcd, 0xb4, 0x59, 0x31, 0xc8, 0x9f, 0x7e, 0xc9, 0xd9, 0x78, 0x73, 0x64,
0xea, 0xc5, 0xac, 0x83, 0x34, 0xd3, 0xeb, 0xc3, 0xc5, 0x81, 0xa0, 0xff, 0xfa, 0x13, 0x63, 0xeb,
0x17, 0x0d, 0xdd, 0x51, 0xb7, 0xf0, 0xda, 0x49, 0xd3, 0x16, 0x55, 0x26, 0x29, 0xd4, 0x68, 0x9e,
0x2b, 0x16, 0xbe, 0x58, 0x7d, 0x47, 0xa1, 0xfc, 0x8f, 0xf8, 0xb8, 0xd1, 0x7a, 0xd0, 0x31, 0xce,
0x45, 0xcb, 0x3a, 0x8f, 0x95, 0x16, 0x04, 0x28, 0xaf, 0xd7, 0xfb, 0xca, 0xbb, 0x4b, 0x40, 0x7e
];
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static ulong Mult32To64(ulong x, ulong y) => (uint)x * (ulong)(uint)y;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Hash128 Mult64To128(ulong lhs, ulong rhs)
{
Low = low;
High = high;
ulong high = Math.BigMul(lhs, rhs, out ulong low);
return new Hash128
{
Low = low,
High = high,
};
}
public readonly override string ToString()
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static ulong Mul128Fold64(ulong lhs, ulong rhs)
{
return $"{High:x16}{Low:x16}";
Hash128 product = Mult64To128(lhs, rhs);
return product.Low ^ product.High;
}
public static bool operator ==(Hash128 x, Hash128 y)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static ulong XorShift64(ulong v64, int shift)
{
return x.Equals(y);
Debug.Assert(0 <= shift && shift < 64);
return v64 ^ (v64 >> shift);
}
public static bool operator !=(Hash128 x, Hash128 y)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static ulong Xxh3Avalanche(ulong h64)
{
return !x.Equals(y);
h64 = XorShift64(h64, 37);
h64 *= 0x165667919E3779F9UL;
h64 = XorShift64(h64, 32);
return h64;
}
public readonly override bool Equals(object obj)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static ulong Xxh64Avalanche(ulong h64)
{
return obj is Hash128 hash128 && Equals(hash128);
h64 ^= h64 >> 33;
h64 *= Prime64_2;
h64 ^= h64 >> 29;
h64 *= Prime64_3;
h64 ^= h64 >> 32;
return h64;
}
public readonly bool Equals(Hash128 cmpObj)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private unsafe static void Xxh3Accumulate512(Span<ulong> acc, ReadOnlySpan<byte> input, ReadOnlySpan<byte> secret)
{
return Low == cmpObj.Low && High == cmpObj.High;
if (Avx2.IsSupported)
{
fixed (ulong* pAcc = acc)
{
fixed (byte* pInput = input, pSecret = secret)
{
Vector256<ulong>* xAcc = (Vector256<ulong>*)pAcc;
Vector256<byte>* xInput = (Vector256<byte>*)pInput;
Vector256<byte>* xSecret = (Vector256<byte>*)pSecret;
for (ulong i = 0; i < StripeLen / 32; i++)
{
Vector256<byte> dataVec = xInput[i];
Vector256<byte> keyVec = xSecret[i];
Vector256<byte> dataKey = Avx2.Xor(dataVec, keyVec);
Vector256<uint> dataKeyLo = Avx2.Shuffle(dataKey.AsUInt32(), 0b00110001);
Vector256<ulong> product = Avx2.Multiply(dataKey.AsUInt32(), dataKeyLo);
Vector256<uint> dataSwap = Avx2.Shuffle(dataVec.AsUInt32(), 0b01001110);
Vector256<ulong> sum = Avx2.Add(xAcc[i], dataSwap.AsUInt64());
xAcc[i] = Avx2.Add(product, sum);
}
}
}
}
else if (Sse2.IsSupported)
{
fixed (ulong* pAcc = acc)
{
fixed (byte* pInput = input, pSecret = secret)
{
Vector128<ulong>* xAcc = (Vector128<ulong>*)pAcc;
Vector128<byte>* xInput = (Vector128<byte>*)pInput;
Vector128<byte>* xSecret = (Vector128<byte>*)pSecret;
for (ulong i = 0; i < StripeLen / 16; i++)
{
Vector128<byte> dataVec = xInput[i];
Vector128<byte> keyVec = xSecret[i];
Vector128<byte> dataKey = Sse2.Xor(dataVec, keyVec);
Vector128<uint> dataKeyLo = Sse2.Shuffle(dataKey.AsUInt32(), 0b00110001);
Vector128<ulong> product = Sse2.Multiply(dataKey.AsUInt32(), dataKeyLo);
Vector128<uint> dataSwap = Sse2.Shuffle(dataVec.AsUInt32(), 0b01001110);
Vector128<ulong> sum = Sse2.Add(xAcc[i], dataSwap.AsUInt64());
xAcc[i] = Sse2.Add(product, sum);
}
}
}
}
else
{
for (int i = 0; i < AccNb; i++)
{
ulong dataVal = BinaryPrimitives.ReadUInt64LittleEndian(input[(i * sizeof(ulong))..]);
ulong dataKey = dataVal ^ BinaryPrimitives.ReadUInt64LittleEndian(secret[(i * sizeof(ulong))..]);
acc[i ^ 1] += dataVal;
acc[i] += Mult32To64((uint)dataKey, dataKey >> 32);
}
}
}
public readonly override int GetHashCode()
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private unsafe static void Xxh3ScrambleAcc(Span<ulong> acc, ReadOnlySpan<byte> secret)
{
return HashCode.Combine(Low, High);
if (Avx2.IsSupported)
{
fixed (ulong* pAcc = acc)
{
fixed (byte* pSecret = secret)
{
Vector256<uint> prime32 = Vector256.Create(Prime32_1);
Vector256<ulong>* xAcc = (Vector256<ulong>*)pAcc;
Vector256<byte>* xSecret = (Vector256<byte>*)pSecret;
for (ulong i = 0; i < StripeLen / 32; i++)
{
Vector256<ulong> accVec = xAcc[i];
Vector256<ulong> shifted = Avx2.ShiftRightLogical(accVec, 47);
Vector256<ulong> dataVec = Avx2.Xor(accVec, shifted);
Vector256<byte> keyVec = xSecret[i];
Vector256<uint> dataKey = Avx2.Xor(dataVec.AsUInt32(), keyVec.AsUInt32());
Vector256<uint> dataKeyHi = Avx2.Shuffle(dataKey.AsUInt32(), 0b00110001);
Vector256<ulong> prodLo = Avx2.Multiply(dataKey, prime32);
Vector256<ulong> prodHi = Avx2.Multiply(dataKeyHi, prime32);
xAcc[i] = Avx2.Add(prodLo, Avx2.ShiftLeftLogical(prodHi, 32));
}
}
}
}
else if (Sse2.IsSupported)
{
fixed (ulong* pAcc = acc)
{
fixed (byte* pSecret = secret)
{
Vector128<uint> prime32 = Vector128.Create(Prime32_1);
Vector128<ulong>* xAcc = (Vector128<ulong>*)pAcc;
Vector128<byte>* xSecret = (Vector128<byte>*)pSecret;
for (ulong i = 0; i < StripeLen / 16; i++)
{
Vector128<ulong> accVec = xAcc[i];
Vector128<ulong> shifted = Sse2.ShiftRightLogical(accVec, 47);
Vector128<ulong> dataVec = Sse2.Xor(accVec, shifted);
Vector128<byte> keyVec = xSecret[i];
Vector128<uint> dataKey = Sse2.Xor(dataVec.AsUInt32(), keyVec.AsUInt32());
Vector128<uint> dataKeyHi = Sse2.Shuffle(dataKey.AsUInt32(), 0b00110001);
Vector128<ulong> prodLo = Sse2.Multiply(dataKey, prime32);
Vector128<ulong> prodHi = Sse2.Multiply(dataKeyHi, prime32);
xAcc[i] = Sse2.Add(prodLo, Sse2.ShiftLeftLogical(prodHi, 32));
}
}
}
}
else
{
for (int i = 0; i < AccNb; i++)
{
ulong key64 = BinaryPrimitives.ReadUInt64LittleEndian(secret[(i * sizeof(ulong))..]);
ulong acc64 = acc[i];
acc64 = XorShift64(acc64, 47);
acc64 ^= key64;
acc64 *= Prime32_1;
acc[i] = acc64;
}
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void Xxh3Accumulate(Span<ulong> acc, ReadOnlySpan<byte> input, ReadOnlySpan<byte> secret, int nbStripes)
{
for (int n = 0; n < nbStripes; n++)
{
ReadOnlySpan<byte> inData = input[(n * StripeLen)..];
Xxh3Accumulate512(acc, inData, secret[(n * SecretConsumeRate)..]);
}
}
private static void Xxh3HashLongInternalLoop(Span<ulong> acc, ReadOnlySpan<byte> input, ReadOnlySpan<byte> secret)
{
int nbStripesPerBlock = (secret.Length - StripeLen) / SecretConsumeRate;
int blockLen = StripeLen * nbStripesPerBlock;
int nbBlocks = (input.Length - 1) / blockLen;
Debug.Assert(secret.Length >= SecretSizeMin);
for (int n = 0; n < nbBlocks; n++)
{
Xxh3Accumulate(acc, input[(n * blockLen)..], secret, nbStripesPerBlock);
Xxh3ScrambleAcc(acc, secret[^StripeLen..]);
}
Debug.Assert(input.Length > StripeLen);
int nbStripes = (input.Length - 1 - (blockLen * nbBlocks)) / StripeLen;
Debug.Assert(nbStripes <= (secret.Length / SecretConsumeRate));
Xxh3Accumulate(acc, input[(nbBlocks * blockLen)..], secret, nbStripes);
ReadOnlySpan<byte> p = input[^StripeLen..];
Xxh3Accumulate512(acc, p, secret[(secret.Length - StripeLen - SecretLastAccStart)..]);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static ulong Xxh3Mix2Accs(Span<ulong> acc, ReadOnlySpan<byte> secret)
{
return Mul128Fold64(
acc[0] ^ BinaryPrimitives.ReadUInt64LittleEndian(secret),
acc[1] ^ BinaryPrimitives.ReadUInt64LittleEndian(secret[8..]));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static ulong Xxh3MergeAccs(Span<ulong> acc, ReadOnlySpan<byte> secret, ulong start)
{
ulong result64 = start;
for (int i = 0; i < 4; i++)
{
result64 += Xxh3Mix2Accs(acc[(2 * i)..], secret[(16 * i)..]);
}
return Xxh3Avalanche(result64);
}
[SkipLocalsInit]
private static Hash128 Xxh3HashLong128bInternal(ReadOnlySpan<byte> input, ReadOnlySpan<byte> secret)
{
Span<ulong> acc = stackalloc ulong[AccNb];
_xxh3InitAcc.CopyTo(acc);
Xxh3HashLongInternalLoop(acc, input, secret);
Debug.Assert(acc.Length == 8);
Debug.Assert(secret.Length >= acc.Length * sizeof(ulong) + SecretMergeAccsStart);
return new Hash128
{
Low = Xxh3MergeAccs(acc, secret[SecretMergeAccsStart..], (ulong)input.Length * Prime64_1),
High = Xxh3MergeAccs(
acc,
secret[(secret.Length - acc.Length * sizeof(ulong) - SecretMergeAccsStart)..],
~((ulong)input.Length * Prime64_2)),
};
}
private static Hash128 Xxh3Len1To3128b(ReadOnlySpan<byte> input, ReadOnlySpan<byte> secret, ulong seed)
{
Debug.Assert(1 <= input.Length && input.Length <= 3);
byte c1 = input[0];
byte c2 = input[input.Length >> 1];
byte c3 = input[^1];
uint combinedL = ((uint)c1 << 16) | ((uint)c2 << 24) | c3 | ((uint)input.Length << 8);
uint combinedH = BitOperations.RotateLeft(BinaryPrimitives.ReverseEndianness(combinedL), 13);
ulong bitFlipL = (BinaryPrimitives.ReadUInt32LittleEndian(secret) ^ BinaryPrimitives.ReadUInt32LittleEndian(secret[4..])) + seed;
ulong bitFlipH = (BinaryPrimitives.ReadUInt32LittleEndian(secret[8..]) ^ BinaryPrimitives.ReadUInt32LittleEndian(secret[12..])) - seed;
ulong keyedLo = combinedL ^ bitFlipL;
ulong keyedHi = combinedH ^ bitFlipH;
return new Hash128
{
Low = Xxh64Avalanche(keyedLo),
High = Xxh64Avalanche(keyedHi),
};
}
private static Hash128 Xxh3Len4To8128b(ReadOnlySpan<byte> input, ReadOnlySpan<byte> secret, ulong seed)
{
Debug.Assert(4 <= input.Length && input.Length <= 8);
seed ^= BinaryPrimitives.ReverseEndianness((uint)seed) << 32;
uint inputLo = BinaryPrimitives.ReadUInt32LittleEndian(input);
uint inputHi = BinaryPrimitives.ReadUInt32LittleEndian(input[^4..]);
ulong input64 = inputLo + ((ulong)inputHi << 32);
ulong bitFlip = (BinaryPrimitives.ReadUInt64LittleEndian(secret[16..]) ^ BinaryPrimitives.ReadUInt64LittleEndian(secret[24..])) + seed;
ulong keyed = input64 ^ bitFlip;
Hash128 m128 = Mult64To128(keyed, Prime64_1 + ((ulong)input.Length << 2));
m128.High += m128.Low << 1;
m128.Low ^= m128.High >> 3;
m128.Low = XorShift64(m128.Low, 35);
m128.Low *= 0x9FB21C651E98DF25UL;
m128.Low = XorShift64(m128.Low, 28);
m128.High = Xxh3Avalanche(m128.High);
return m128;
}
private static Hash128 Xxh3Len9To16128b(ReadOnlySpan<byte> input, ReadOnlySpan<byte> secret, ulong seed)
{
Debug.Assert(9 <= input.Length && input.Length <= 16);
ulong bitFlipL = (BinaryPrimitives.ReadUInt64LittleEndian(secret[32..]) ^ BinaryPrimitives.ReadUInt64LittleEndian(secret[40..])) - seed;
ulong bitFlipH = (BinaryPrimitives.ReadUInt64LittleEndian(secret[48..]) ^ BinaryPrimitives.ReadUInt64LittleEndian(secret[56..])) + seed;
ulong inputLo = BinaryPrimitives.ReadUInt64LittleEndian(input);
ulong inputHi = BinaryPrimitives.ReadUInt64LittleEndian(input[^8..]);
Hash128 m128 = Mult64To128(inputLo ^ inputHi ^ bitFlipL, Prime64_1);
m128.Low += ((ulong)input.Length - 1) << 54;
inputHi ^= bitFlipH;
m128.High += inputHi + Mult32To64((uint)inputHi, Prime32_2 - 1);
m128.Low ^= BinaryPrimitives.ReverseEndianness(m128.High);
Hash128 h128 = Mult64To128(m128.Low, Prime64_2);
h128.High += m128.High * Prime64_2;
h128.Low = Xxh3Avalanche(h128.Low);
h128.High = Xxh3Avalanche(h128.High);
return h128;
}
private static Hash128 Xxh3Len0To16128b(ReadOnlySpan<byte> input, ReadOnlySpan<byte> secret, ulong seed)
{
Debug.Assert(input.Length <= 16);
if (input.Length > 8)
{
return Xxh3Len9To16128b(input, secret, seed);
}
if (input.Length >= 4)
{
return Xxh3Len4To8128b(input, secret, seed);
}
if (input.Length != 0)
{
return Xxh3Len1To3128b(input, secret, seed);
}
Hash128 h128 = new();
ulong bitFlipL = BinaryPrimitives.ReadUInt64LittleEndian(secret[64..]) ^ BinaryPrimitives.ReadUInt64LittleEndian(secret[72..]);
ulong bitFlipH = BinaryPrimitives.ReadUInt64LittleEndian(secret[80..]) ^ BinaryPrimitives.ReadUInt64LittleEndian(secret[88..]);
h128.Low = Xxh64Avalanche(seed ^ bitFlipL);
h128.High = Xxh64Avalanche(seed ^ bitFlipH);
return h128;
}
private static ulong Xxh3Mix16b(ReadOnlySpan<byte> input, ReadOnlySpan<byte> secret, ulong seed)
{
ulong inputLo = BinaryPrimitives.ReadUInt64LittleEndian(input);
ulong inputHi = BinaryPrimitives.ReadUInt64LittleEndian(input[8..]);
return Mul128Fold64(
inputLo ^ (BinaryPrimitives.ReadUInt64LittleEndian(secret) + seed),
inputHi ^ (BinaryPrimitives.ReadUInt64LittleEndian(secret[8..]) - seed));
}
private static Hash128 Xxh128Mix32b(Hash128 acc, ReadOnlySpan<byte> input, ReadOnlySpan<byte> input2, ReadOnlySpan<byte> secret, ulong seed)
{
acc.Low += Xxh3Mix16b(input, secret, seed);
acc.Low ^= BinaryPrimitives.ReadUInt64LittleEndian(input2) + BinaryPrimitives.ReadUInt64LittleEndian(input2[8..]);
acc.High += Xxh3Mix16b(input2, secret[16..], seed);
acc.High ^= BinaryPrimitives.ReadUInt64LittleEndian(input) + BinaryPrimitives.ReadUInt64LittleEndian(input[8..]);
return acc;
}
private static Hash128 Xxh3Len17To128128b(ReadOnlySpan<byte> input, ReadOnlySpan<byte> secret, ulong seed)
{
Debug.Assert(secret.Length >= SecretSizeMin);
Debug.Assert(16 < input.Length && input.Length <= 128);
Hash128 acc = new()
{
Low = (ulong)input.Length * Prime64_1,
High = 0,
};
if (input.Length > 32)
{
if (input.Length > 64)
{
if (input.Length > 96)
{
acc = Xxh128Mix32b(acc, input[48..], input[^64..], secret[96..], seed);
}
acc = Xxh128Mix32b(acc, input[32..], input[^48..], secret[64..], seed);
}
acc = Xxh128Mix32b(acc, input[16..], input[^32..], secret[32..], seed);
}
acc = Xxh128Mix32b(acc, input, input[^16..], secret, seed);
Hash128 h128 = new()
{
Low = acc.Low + acc.High,
High = acc.Low * Prime64_1 + acc.High * Prime64_4 + ((ulong)input.Length - seed) * Prime64_2,
};
h128.Low = Xxh3Avalanche(h128.Low);
h128.High = 0UL - Xxh3Avalanche(h128.High);
return h128;
}
private static Hash128 Xxh3Len129To240128b(ReadOnlySpan<byte> input, ReadOnlySpan<byte> secret, ulong seed)
{
Debug.Assert(secret.Length >= SecretSizeMin);
Debug.Assert(128 < input.Length && input.Length <= 240);
Hash128 acc = new();
int nbRounds = input.Length / 32;
acc.Low = (ulong)input.Length * Prime64_1;
acc.High = 0;
for (int i = 0; i < 4; i++)
{
acc = Xxh128Mix32b(acc, input[(32 * i)..], input[(32 * i + 16)..], secret[(32 * i)..], seed);
}
acc.Low = Xxh3Avalanche(acc.Low);
acc.High = Xxh3Avalanche(acc.High);
Debug.Assert(nbRounds >= 4);
for (int i = 4; i < nbRounds; i++)
{
acc = Xxh128Mix32b(acc, input[(32 * i)..], input[(32 * i + 16)..], secret[(MidSizeStartOffset + 32 * (i - 4))..], seed);
}
acc = Xxh128Mix32b(acc, input[^16..], input[^32..], secret[(SecretSizeMin - MidSizeLastOffset - 16)..], 0UL - seed);
Hash128 h128 = new()
{
Low = acc.Low + acc.High,
High = acc.Low * Prime64_1 + acc.High * Prime64_4 + ((ulong)input.Length - seed) * Prime64_2,
};
h128.Low = Xxh3Avalanche(h128.Low);
h128.High = 0UL - Xxh3Avalanche(h128.High);
return h128;
}
private static Hash128 Xxh3128bitsInternal(ReadOnlySpan<byte> input, ReadOnlySpan<byte> secret, ulong seed)
{
Debug.Assert(secret.Length >= SecretSizeMin);
return input.Length switch
{
<= 16 => Xxh3Len0To16128b(input, secret, seed),
<= 128 => Xxh3Len17To128128b(input, secret, seed),
<= 240 => Xxh3Len129To240128b(input, secret, seed),
_ => Xxh3HashLong128bInternal(input, secret)
};
}
#endregion
}
}

View file

@ -75,15 +75,10 @@ namespace Ryujinx.Common.Utilities
if (char.IsUpper(c))
{
if (i == 0 || char.IsUpper(name[i - 1]))
{
builder.Append(char.ToLowerInvariant(c));
}
else
{
if (!(i == 0 || char.IsUpper(name[i - 1])))
builder.Append('_');
builder.Append(char.ToLowerInvariant(c));
}
builder.Append(char.ToLowerInvariant(c));
}
else
{

View file

@ -1,548 +0,0 @@
using System;
using System.Buffers.Binary;
using System.Diagnostics;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86;
namespace Ryujinx.Common
{
public static class XXHash128
{
private const int StripeLen = 64;
private const int AccNb = StripeLen / sizeof(ulong);
private const int SecretConsumeRate = 8;
private const int SecretLastAccStart = 7;
private const int SecretMergeAccsStart = 11;
private const int SecretSizeMin = 136;
private const int MidSizeStartOffset = 3;
private const int MidSizeLastOffset = 17;
private const uint Prime32_1 = 0x9E3779B1U;
private const uint Prime32_2 = 0x85EBCA77U;
private const uint Prime32_3 = 0xC2B2AE3DU;
private const uint Prime32_4 = 0x27D4EB2FU;
private const uint Prime32_5 = 0x165667B1U;
private const ulong Prime64_1 = 0x9E3779B185EBCA87UL;
private const ulong Prime64_2 = 0xC2B2AE3D27D4EB4FUL;
private const ulong Prime64_3 = 0x165667B19E3779F9UL;
private const ulong Prime64_4 = 0x85EBCA77C2B2AE63UL;
private const ulong Prime64_5 = 0x27D4EB2F165667C5UL;
private static readonly ulong[] _xxh3InitAcc = {
Prime32_3,
Prime64_1,
Prime64_2,
Prime64_3,
Prime64_4,
Prime32_2,
Prime64_5,
Prime32_1,
};
private static ReadOnlySpan<byte> Xxh3KSecret => new byte[]
{
0xb8, 0xfe, 0x6c, 0x39, 0x23, 0xa4, 0x4b, 0xbe, 0x7c, 0x01, 0x81, 0x2c, 0xf7, 0x21, 0xad, 0x1c,
0xde, 0xd4, 0x6d, 0xe9, 0x83, 0x90, 0x97, 0xdb, 0x72, 0x40, 0xa4, 0xa4, 0xb7, 0xb3, 0x67, 0x1f,
0xcb, 0x79, 0xe6, 0x4e, 0xcc, 0xc0, 0xe5, 0x78, 0x82, 0x5a, 0xd0, 0x7d, 0xcc, 0xff, 0x72, 0x21,
0xb8, 0x08, 0x46, 0x74, 0xf7, 0x43, 0x24, 0x8e, 0xe0, 0x35, 0x90, 0xe6, 0x81, 0x3a, 0x26, 0x4c,
0x3c, 0x28, 0x52, 0xbb, 0x91, 0xc3, 0x00, 0xcb, 0x88, 0xd0, 0x65, 0x8b, 0x1b, 0x53, 0x2e, 0xa3,
0x71, 0x64, 0x48, 0x97, 0xa2, 0x0d, 0xf9, 0x4e, 0x38, 0x19, 0xef, 0x46, 0xa9, 0xde, 0xac, 0xd8,
0xa8, 0xfa, 0x76, 0x3f, 0xe3, 0x9c, 0x34, 0x3f, 0xf9, 0xdc, 0xbb, 0xc7, 0xc7, 0x0b, 0x4f, 0x1d,
0x8a, 0x51, 0xe0, 0x4b, 0xcd, 0xb4, 0x59, 0x31, 0xc8, 0x9f, 0x7e, 0xc9, 0xd9, 0x78, 0x73, 0x64,
0xea, 0xc5, 0xac, 0x83, 0x34, 0xd3, 0xeb, 0xc3, 0xc5, 0x81, 0xa0, 0xff, 0xfa, 0x13, 0x63, 0xeb,
0x17, 0x0d, 0xdd, 0x51, 0xb7, 0xf0, 0xda, 0x49, 0xd3, 0x16, 0x55, 0x26, 0x29, 0xd4, 0x68, 0x9e,
0x2b, 0x16, 0xbe, 0x58, 0x7d, 0x47, 0xa1, 0xfc, 0x8f, 0xf8, 0xb8, 0xd1, 0x7a, 0xd0, 0x31, 0xce,
0x45, 0xcb, 0x3a, 0x8f, 0x95, 0x16, 0x04, 0x28, 0xaf, 0xd7, 0xfb, 0xca, 0xbb, 0x4b, 0x40, 0x7e,
};
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static ulong Mult32To64(ulong x, ulong y)
{
return (uint)x * (ulong)(uint)y;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Hash128 Mult64To128(ulong lhs, ulong rhs)
{
ulong high = Math.BigMul(lhs, rhs, out ulong low);
return new Hash128
{
Low = low,
High = high,
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static ulong Mul128Fold64(ulong lhs, ulong rhs)
{
Hash128 product = Mult64To128(lhs, rhs);
return product.Low ^ product.High;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static ulong XorShift64(ulong v64, int shift)
{
Debug.Assert(0 <= shift && shift < 64);
return v64 ^ (v64 >> shift);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static ulong Xxh3Avalanche(ulong h64)
{
h64 = XorShift64(h64, 37);
h64 *= 0x165667919E3779F9UL;
h64 = XorShift64(h64, 32);
return h64;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static ulong Xxh64Avalanche(ulong h64)
{
h64 ^= h64 >> 33;
h64 *= Prime64_2;
h64 ^= h64 >> 29;
h64 *= Prime64_3;
h64 ^= h64 >> 32;
return h64;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private unsafe static void Xxh3Accumulate512(Span<ulong> acc, ReadOnlySpan<byte> input, ReadOnlySpan<byte> secret)
{
if (Avx2.IsSupported)
{
fixed (ulong* pAcc = acc)
{
fixed (byte* pInput = input, pSecret = secret)
{
Vector256<ulong>* xAcc = (Vector256<ulong>*)pAcc;
Vector256<byte>* xInput = (Vector256<byte>*)pInput;
Vector256<byte>* xSecret = (Vector256<byte>*)pSecret;
for (ulong i = 0; i < StripeLen / 32; i++)
{
Vector256<byte> dataVec = xInput[i];
Vector256<byte> keyVec = xSecret[i];
Vector256<byte> dataKey = Avx2.Xor(dataVec, keyVec);
Vector256<uint> dataKeyLo = Avx2.Shuffle(dataKey.AsUInt32(), 0b00110001);
Vector256<ulong> product = Avx2.Multiply(dataKey.AsUInt32(), dataKeyLo);
Vector256<uint> dataSwap = Avx2.Shuffle(dataVec.AsUInt32(), 0b01001110);
Vector256<ulong> sum = Avx2.Add(xAcc[i], dataSwap.AsUInt64());
xAcc[i] = Avx2.Add(product, sum);
}
}
}
}
else if (Sse2.IsSupported)
{
fixed (ulong* pAcc = acc)
{
fixed (byte* pInput = input, pSecret = secret)
{
Vector128<ulong>* xAcc = (Vector128<ulong>*)pAcc;
Vector128<byte>* xInput = (Vector128<byte>*)pInput;
Vector128<byte>* xSecret = (Vector128<byte>*)pSecret;
for (ulong i = 0; i < StripeLen / 16; i++)
{
Vector128<byte> dataVec = xInput[i];
Vector128<byte> keyVec = xSecret[i];
Vector128<byte> dataKey = Sse2.Xor(dataVec, keyVec);
Vector128<uint> dataKeyLo = Sse2.Shuffle(dataKey.AsUInt32(), 0b00110001);
Vector128<ulong> product = Sse2.Multiply(dataKey.AsUInt32(), dataKeyLo);
Vector128<uint> dataSwap = Sse2.Shuffle(dataVec.AsUInt32(), 0b01001110);
Vector128<ulong> sum = Sse2.Add(xAcc[i], dataSwap.AsUInt64());
xAcc[i] = Sse2.Add(product, sum);
}
}
}
}
else
{
for (int i = 0; i < AccNb; i++)
{
ulong dataVal = BinaryPrimitives.ReadUInt64LittleEndian(input[(i * sizeof(ulong))..]);
ulong dataKey = dataVal ^ BinaryPrimitives.ReadUInt64LittleEndian(secret[(i * sizeof(ulong))..]);
acc[i ^ 1] += dataVal;
acc[i] += Mult32To64((uint)dataKey, dataKey >> 32);
}
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private unsafe static void Xxh3ScrambleAcc(Span<ulong> acc, ReadOnlySpan<byte> secret)
{
if (Avx2.IsSupported)
{
fixed (ulong* pAcc = acc)
{
fixed (byte* pSecret = secret)
{
Vector256<uint> prime32 = Vector256.Create(Prime32_1);
Vector256<ulong>* xAcc = (Vector256<ulong>*)pAcc;
Vector256<byte>* xSecret = (Vector256<byte>*)pSecret;
for (ulong i = 0; i < StripeLen / 32; i++)
{
Vector256<ulong> accVec = xAcc[i];
Vector256<ulong> shifted = Avx2.ShiftRightLogical(accVec, 47);
Vector256<ulong> dataVec = Avx2.Xor(accVec, shifted);
Vector256<byte> keyVec = xSecret[i];
Vector256<uint> dataKey = Avx2.Xor(dataVec.AsUInt32(), keyVec.AsUInt32());
Vector256<uint> dataKeyHi = Avx2.Shuffle(dataKey.AsUInt32(), 0b00110001);
Vector256<ulong> prodLo = Avx2.Multiply(dataKey, prime32);
Vector256<ulong> prodHi = Avx2.Multiply(dataKeyHi, prime32);
xAcc[i] = Avx2.Add(prodLo, Avx2.ShiftLeftLogical(prodHi, 32));
}
}
}
}
else if (Sse2.IsSupported)
{
fixed (ulong* pAcc = acc)
{
fixed (byte* pSecret = secret)
{
Vector128<uint> prime32 = Vector128.Create(Prime32_1);
Vector128<ulong>* xAcc = (Vector128<ulong>*)pAcc;
Vector128<byte>* xSecret = (Vector128<byte>*)pSecret;
for (ulong i = 0; i < StripeLen / 16; i++)
{
Vector128<ulong> accVec = xAcc[i];
Vector128<ulong> shifted = Sse2.ShiftRightLogical(accVec, 47);
Vector128<ulong> dataVec = Sse2.Xor(accVec, shifted);
Vector128<byte> keyVec = xSecret[i];
Vector128<uint> dataKey = Sse2.Xor(dataVec.AsUInt32(), keyVec.AsUInt32());
Vector128<uint> dataKeyHi = Sse2.Shuffle(dataKey.AsUInt32(), 0b00110001);
Vector128<ulong> prodLo = Sse2.Multiply(dataKey, prime32);
Vector128<ulong> prodHi = Sse2.Multiply(dataKeyHi, prime32);
xAcc[i] = Sse2.Add(prodLo, Sse2.ShiftLeftLogical(prodHi, 32));
}
}
}
}
else
{
for (int i = 0; i < AccNb; i++)
{
ulong key64 = BinaryPrimitives.ReadUInt64LittleEndian(secret[(i * sizeof(ulong))..]);
ulong acc64 = acc[i];
acc64 = XorShift64(acc64, 47);
acc64 ^= key64;
acc64 *= Prime32_1;
acc[i] = acc64;
}
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void Xxh3Accumulate(Span<ulong> acc, ReadOnlySpan<byte> input, ReadOnlySpan<byte> secret, int nbStripes)
{
for (int n = 0; n < nbStripes; n++)
{
ReadOnlySpan<byte> inData = input[(n * StripeLen)..];
Xxh3Accumulate512(acc, inData, secret[(n * SecretConsumeRate)..]);
}
}
private static void Xxh3HashLongInternalLoop(Span<ulong> acc, ReadOnlySpan<byte> input, ReadOnlySpan<byte> secret)
{
int nbStripesPerBlock = (secret.Length - StripeLen) / SecretConsumeRate;
int blockLen = StripeLen * nbStripesPerBlock;
int nbBlocks = (input.Length - 1) / blockLen;
Debug.Assert(secret.Length >= SecretSizeMin);
for (int n = 0; n < nbBlocks; n++)
{
Xxh3Accumulate(acc, input[(n * blockLen)..], secret, nbStripesPerBlock);
Xxh3ScrambleAcc(acc, secret[^StripeLen..]);
}
Debug.Assert(input.Length > StripeLen);
int nbStripes = (input.Length - 1 - (blockLen * nbBlocks)) / StripeLen;
Debug.Assert(nbStripes <= (secret.Length / SecretConsumeRate));
Xxh3Accumulate(acc, input[(nbBlocks * blockLen)..], secret, nbStripes);
ReadOnlySpan<byte> p = input[^StripeLen..];
Xxh3Accumulate512(acc, p, secret[(secret.Length - StripeLen - SecretLastAccStart)..]);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static ulong Xxh3Mix2Accs(Span<ulong> acc, ReadOnlySpan<byte> secret)
{
return Mul128Fold64(
acc[0] ^ BinaryPrimitives.ReadUInt64LittleEndian(secret),
acc[1] ^ BinaryPrimitives.ReadUInt64LittleEndian(secret[8..]));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static ulong Xxh3MergeAccs(Span<ulong> acc, ReadOnlySpan<byte> secret, ulong start)
{
ulong result64 = start;
for (int i = 0; i < 4; i++)
{
result64 += Xxh3Mix2Accs(acc[(2 * i)..], secret[(16 * i)..]);
}
return Xxh3Avalanche(result64);
}
[SkipLocalsInit]
private static Hash128 Xxh3HashLong128bInternal(ReadOnlySpan<byte> input, ReadOnlySpan<byte> secret)
{
Span<ulong> acc = stackalloc ulong[AccNb];
_xxh3InitAcc.CopyTo(acc);
Xxh3HashLongInternalLoop(acc, input, secret);
Debug.Assert(acc.Length == 8);
Debug.Assert(secret.Length >= acc.Length * sizeof(ulong) + SecretMergeAccsStart);
return new Hash128
{
Low = Xxh3MergeAccs(acc, secret[SecretMergeAccsStart..], (ulong)input.Length * Prime64_1),
High = Xxh3MergeAccs(
acc,
secret[(secret.Length - acc.Length * sizeof(ulong) - SecretMergeAccsStart)..],
~((ulong)input.Length * Prime64_2)),
};
}
private static Hash128 Xxh3Len1To3128b(ReadOnlySpan<byte> input, ReadOnlySpan<byte> secret, ulong seed)
{
Debug.Assert(1 <= input.Length && input.Length <= 3);
byte c1 = input[0];
byte c2 = input[input.Length >> 1];
byte c3 = input[^1];
uint combinedL = ((uint)c1 << 16) | ((uint)c2 << 24) | c3 | ((uint)input.Length << 8);
uint combinedH = BitOperations.RotateLeft(BinaryPrimitives.ReverseEndianness(combinedL), 13);
ulong bitFlipL = (BinaryPrimitives.ReadUInt32LittleEndian(secret) ^ BinaryPrimitives.ReadUInt32LittleEndian(secret[4..])) + seed;
ulong bitFlipH = (BinaryPrimitives.ReadUInt32LittleEndian(secret[8..]) ^ BinaryPrimitives.ReadUInt32LittleEndian(secret[12..])) - seed;
ulong keyedLo = combinedL ^ bitFlipL;
ulong keyedHi = combinedH ^ bitFlipH;
return new Hash128
{
Low = Xxh64Avalanche(keyedLo),
High = Xxh64Avalanche(keyedHi),
};
}
private static Hash128 Xxh3Len4To8128b(ReadOnlySpan<byte> input, ReadOnlySpan<byte> secret, ulong seed)
{
Debug.Assert(4 <= input.Length && input.Length <= 8);
seed ^= BinaryPrimitives.ReverseEndianness((uint)seed) << 32;
uint inputLo = BinaryPrimitives.ReadUInt32LittleEndian(input);
uint inputHi = BinaryPrimitives.ReadUInt32LittleEndian(input[^4..]);
ulong input64 = inputLo + ((ulong)inputHi << 32);
ulong bitFlip = (BinaryPrimitives.ReadUInt64LittleEndian(secret[16..]) ^ BinaryPrimitives.ReadUInt64LittleEndian(secret[24..])) + seed;
ulong keyed = input64 ^ bitFlip;
Hash128 m128 = Mult64To128(keyed, Prime64_1 + ((ulong)input.Length << 2));
m128.High += m128.Low << 1;
m128.Low ^= m128.High >> 3;
m128.Low = XorShift64(m128.Low, 35);
m128.Low *= 0x9FB21C651E98DF25UL;
m128.Low = XorShift64(m128.Low, 28);
m128.High = Xxh3Avalanche(m128.High);
return m128;
}
private static Hash128 Xxh3Len9To16128b(ReadOnlySpan<byte> input, ReadOnlySpan<byte> secret, ulong seed)
{
Debug.Assert(9 <= input.Length && input.Length <= 16);
ulong bitFlipL = (BinaryPrimitives.ReadUInt64LittleEndian(secret[32..]) ^ BinaryPrimitives.ReadUInt64LittleEndian(secret[40..])) - seed;
ulong bitFlipH = (BinaryPrimitives.ReadUInt64LittleEndian(secret[48..]) ^ BinaryPrimitives.ReadUInt64LittleEndian(secret[56..])) + seed;
ulong inputLo = BinaryPrimitives.ReadUInt64LittleEndian(input);
ulong inputHi = BinaryPrimitives.ReadUInt64LittleEndian(input[^8..]);
Hash128 m128 = Mult64To128(inputLo ^ inputHi ^ bitFlipL, Prime64_1);
m128.Low += ((ulong)input.Length - 1) << 54;
inputHi ^= bitFlipH;
m128.High += inputHi + Mult32To64((uint)inputHi, Prime32_2 - 1);
m128.Low ^= BinaryPrimitives.ReverseEndianness(m128.High);
Hash128 h128 = Mult64To128(m128.Low, Prime64_2);
h128.High += m128.High * Prime64_2;
h128.Low = Xxh3Avalanche(h128.Low);
h128.High = Xxh3Avalanche(h128.High);
return h128;
}
private static Hash128 Xxh3Len0To16128b(ReadOnlySpan<byte> input, ReadOnlySpan<byte> secret, ulong seed)
{
Debug.Assert(input.Length <= 16);
if (input.Length > 8)
{
return Xxh3Len9To16128b(input, secret, seed);
}
if (input.Length >= 4)
{
return Xxh3Len4To8128b(input, secret, seed);
}
if (input.Length != 0)
{
return Xxh3Len1To3128b(input, secret, seed);
}
Hash128 h128 = new();
ulong bitFlipL = BinaryPrimitives.ReadUInt64LittleEndian(secret[64..]) ^ BinaryPrimitives.ReadUInt64LittleEndian(secret[72..]);
ulong bitFlipH = BinaryPrimitives.ReadUInt64LittleEndian(secret[80..]) ^ BinaryPrimitives.ReadUInt64LittleEndian(secret[88..]);
h128.Low = Xxh64Avalanche(seed ^ bitFlipL);
h128.High = Xxh64Avalanche(seed ^ bitFlipH);
return h128;
}
private static ulong Xxh3Mix16b(ReadOnlySpan<byte> input, ReadOnlySpan<byte> secret, ulong seed)
{
ulong inputLo = BinaryPrimitives.ReadUInt64LittleEndian(input);
ulong inputHi = BinaryPrimitives.ReadUInt64LittleEndian(input[8..]);
return Mul128Fold64(
inputLo ^ (BinaryPrimitives.ReadUInt64LittleEndian(secret) + seed),
inputHi ^ (BinaryPrimitives.ReadUInt64LittleEndian(secret[8..]) - seed));
}
private static Hash128 Xxh128Mix32b(Hash128 acc, ReadOnlySpan<byte> input, ReadOnlySpan<byte> input2, ReadOnlySpan<byte> secret, ulong seed)
{
acc.Low += Xxh3Mix16b(input, secret, seed);
acc.Low ^= BinaryPrimitives.ReadUInt64LittleEndian(input2) + BinaryPrimitives.ReadUInt64LittleEndian(input2[8..]);
acc.High += Xxh3Mix16b(input2, secret[16..], seed);
acc.High ^= BinaryPrimitives.ReadUInt64LittleEndian(input) + BinaryPrimitives.ReadUInt64LittleEndian(input[8..]);
return acc;
}
private static Hash128 Xxh3Len17To128128b(ReadOnlySpan<byte> input, ReadOnlySpan<byte> secret, ulong seed)
{
Debug.Assert(secret.Length >= SecretSizeMin);
Debug.Assert(16 < input.Length && input.Length <= 128);
Hash128 acc = new()
{
Low = (ulong)input.Length * Prime64_1,
High = 0,
};
if (input.Length > 32)
{
if (input.Length > 64)
{
if (input.Length > 96)
{
acc = Xxh128Mix32b(acc, input[48..], input[^64..], secret[96..], seed);
}
acc = Xxh128Mix32b(acc, input[32..], input[^48..], secret[64..], seed);
}
acc = Xxh128Mix32b(acc, input[16..], input[^32..], secret[32..], seed);
}
acc = Xxh128Mix32b(acc, input, input[^16..], secret, seed);
Hash128 h128 = new()
{
Low = acc.Low + acc.High,
High = acc.Low * Prime64_1 + acc.High * Prime64_4 + ((ulong)input.Length - seed) * Prime64_2,
};
h128.Low = Xxh3Avalanche(h128.Low);
h128.High = 0UL - Xxh3Avalanche(h128.High);
return h128;
}
private static Hash128 Xxh3Len129To240128b(ReadOnlySpan<byte> input, ReadOnlySpan<byte> secret, ulong seed)
{
Debug.Assert(secret.Length >= SecretSizeMin);
Debug.Assert(128 < input.Length && input.Length <= 240);
Hash128 acc = new();
int nbRounds = input.Length / 32;
acc.Low = (ulong)input.Length * Prime64_1;
acc.High = 0;
for (int i = 0; i < 4; i++)
{
acc = Xxh128Mix32b(acc, input[(32 * i)..], input[(32 * i + 16)..], secret[(32 * i)..], seed);
}
acc.Low = Xxh3Avalanche(acc.Low);
acc.High = Xxh3Avalanche(acc.High);
Debug.Assert(nbRounds >= 4);
for (int i = 4; i < nbRounds; i++)
{
acc = Xxh128Mix32b(acc, input[(32 * i)..], input[(32 * i + 16)..], secret[(MidSizeStartOffset + 32 * (i - 4))..], seed);
}
acc = Xxh128Mix32b(acc, input[^16..], input[^32..], secret[(SecretSizeMin - MidSizeLastOffset - 16)..], 0UL - seed);
Hash128 h128 = new()
{
Low = acc.Low + acc.High,
High = acc.Low * Prime64_1 + acc.High * Prime64_4 + ((ulong)input.Length - seed) * Prime64_2,
};
h128.Low = Xxh3Avalanche(h128.Low);
h128.High = 0UL - Xxh3Avalanche(h128.High);
return h128;
}
private static Hash128 Xxh3128bitsInternal(ReadOnlySpan<byte> input, ReadOnlySpan<byte> secret, ulong seed)
{
Debug.Assert(secret.Length >= SecretSizeMin);
if (input.Length <= 16)
{
return Xxh3Len0To16128b(input, secret, seed);
}
if (input.Length <= 128)
{
return Xxh3Len17To128128b(input, secret, seed);
}
if (input.Length <= 240)
{
return Xxh3Len129To240128b(input, secret, seed);
}
return Xxh3HashLong128bInternal(input, secret);
}
public static Hash128 ComputeHash(ReadOnlySpan<byte> input)
{
return Xxh3128bitsInternal(input, Xxh3KSecret, 0UL);
}
}
}

View file

@ -588,21 +588,15 @@ namespace Ryujinx.HLE.FileSystem
// LibHac.NcaHeader's DecryptHeader doesn't check if HeaderKey is empty and throws InvalidDataException instead
// So, we check it early for a better user experience.
if (_virtualFileSystem.KeySet.HeaderKey.IsZeros())
{
throw new MissingKeyException("HeaderKey is empty. Cannot decrypt NCA headers.");
}
Dictionary<ulong, List<(NcaContentType type, string path)>> updateNcas = new();
if (Directory.Exists(firmwarePackage))
{
return VerifyAndGetVersionDirectory(firmwarePackage);
}
if (!File.Exists(firmwarePackage))
{
throw new FileNotFoundException("Firmware file does not exist.");
}
FileInfo info = new(firmwarePackage);
@ -612,30 +606,22 @@ namespace Ryujinx.HLE.FileSystem
{
case ".zip":
using (ZipArchive archive = ZipFile.OpenRead(firmwarePackage))
{
return VerifyAndGetVersionZip(archive);
}
case ".xci":
Xci xci = new(_virtualFileSystem.KeySet, file.AsStorage());
if (xci.HasPartition(XciPartitionType.Update))
{
XciPartition partition = xci.OpenPartition(XciPartitionType.Update);
return VerifyAndGetVersion(partition);
}
else
{
if (!xci.HasPartition(XciPartitionType.Update))
throw new InvalidFirmwarePackageException("Update not found in xci file.");
}
default:
break;
XciPartition partition = xci.OpenPartition(XciPartitionType.Update);
return VerifyAndGetVersion(partition);
}
SystemVersion VerifyAndGetVersionDirectory(string firmwareDirectory)
{
return VerifyAndGetVersion(new LocalFileSystem(firmwareDirectory));
}
return null;
SystemVersion VerifyAndGetVersionDirectory(string firmwareDirectory)
=> VerifyAndGetVersion(new LocalFileSystem(firmwareDirectory));
SystemVersion VerifyAndGetVersionZip(ZipArchive archive)
{
@ -925,8 +911,6 @@ namespace Ryujinx.HLE.FileSystem
return systemVersion;
}
return null;
}
public SystemVersion GetCurrentFirmwareVersion()

View file

@ -75,12 +75,11 @@ namespace Ryujinx.UI.Common.Helper
return true;
}
catch (Exception) { }
catch
{
// ignored
}
}
outError = error;
return false;
}
}
@ -96,19 +95,15 @@ namespace Ryujinx.UI.Common.Helper
string baseApplicationExtension = Path.GetExtension(baseApplicationPath).ToLowerInvariant();
// NOTE: We don't force homebrew developers to install a system firmware.
if (baseApplicationExtension == ".nro" || baseApplicationExtension == ".nso")
{
error = UserError.Success;
if (baseApplicationExtension is not (".nro" or ".nso"))
return IsFirmwareValid(contentManager, out error);
return true;
}
return IsFirmwareValid(contentManager, out error);
error = UserError.Success;
}
error = UserError.ApplicationNotFound;
return false;
return error is UserError.Success;
}
}
}

View file

@ -140,11 +140,11 @@ namespace Ryujinx.UI.Common.Helper
argsList.Add($"\"{appFilePath}\"");
return String.Join(" ", argsList);
return string.Join(" ", argsList);
}
/// <summary>
/// Creates a Icon (.ico) file using the source bitmap image at the specified file path.
/// Creates an Icon (.ico) file using the source bitmap image at the specified file path.
/// </summary>
/// <param name="source">The source bitmap image that will be saved as an .ico file</param>
/// <param name="filePath">The location that the new .ico file will be saved too (Make sure to include '.ico' in the path).</param>

View file

@ -87,10 +87,7 @@ namespace Ryujinx.UI.Common.Helper
foreach (string path in titleUpdateMetadata.Paths)
{
if (!File.Exists(path))
{
continue;
}
if (!File.Exists(path)) continue;
try
{
@ -99,22 +96,15 @@ namespace Ryujinx.UI.Common.Helper
Dictionary<ulong, ContentMetaData> updates =
pfs.GetContentData(ContentMetaType.Patch, vfs, checkLevel);
Nca patchNca = null;
Nca controlNca = null;
if (!updates.TryGetValue(applicationIdBase, out ContentMetaData content))
{
continue;
}
patchNca = content.GetNcaByType(vfs.KeySet, ContentType.Program);
controlNca = content.GetNcaByType(vfs.KeySet, ContentType.Control);
Nca patchNca = content.GetNcaByType(vfs.KeySet, ContentType.Program);
Nca controlNca = content.GetNcaByType(vfs.KeySet, ContentType.Control);
if (controlNca == null || patchNca == null)
{
if (controlNca is null || patchNca is null)
continue;
}
ApplicationControlProperty controlData = new();
using UniqueRef<IFile> nacpFile = new();
@ -138,7 +128,7 @@ namespace Ryujinx.UI.Common.Helper
catch (InvalidDataException)
{
Logger.Warning?.Print(LogClass.Application,
$"The header key is incorrect or missing and therefore the NCA header content type check has failed. Errored File: {path}");
$"The header key is incorrect or missing and therefore the NCA header content type check has failed. Malformed File: {path}");
}
catch (IOException exception)
{
@ -154,9 +144,7 @@ namespace Ryujinx.UI.Common.Helper
return result;
}
private static string PathToGameUpdatesJson(ulong applicationIdBase)
{
return Path.Combine(AppDataManager.GamesDirPath, applicationIdBase.ToString("x16"), "updates.json");
}
private static string PathToGameUpdatesJson(ulong applicationIdBase)
=> Path.Combine(AppDataManager.GamesDirPath, applicationIdBase.ToString("x16"), "updates.json");
}
}

View file

@ -367,12 +367,12 @@ namespace Ryujinx.Ava
}
var colorType = e.IsBgra ? SKColorType.Bgra8888 : SKColorType.Rgba8888;
using SKBitmap bitmap = new SKBitmap(new SKImageInfo(e.Width, e.Height, colorType, SKAlphaType.Premul));
using SKBitmap bitmap = new(new SKImageInfo(e.Width, e.Height, colorType, SKAlphaType.Premul));
Marshal.Copy(e.Data, 0, bitmap.GetPixels(), e.Data.Length);
using SKBitmap bitmapToSave = new SKBitmap(bitmap.Width, bitmap.Height);
using SKCanvas canvas = new SKCanvas(bitmapToSave);
using SKBitmap bitmapToSave = new(bitmap.Width, bitmap.Height);
using SKCanvas canvas = new(bitmapToSave);
canvas.Clear(SKColors.Black);