diff --git a/src/Ryujinx.Common/GraphicsDriver/NVThreadedOptimization.cs b/src/Ryujinx.Common/GraphicsDriver/NVThreadedOptimization.cs index f7b11783d..a8036ed90 100644 --- a/src/Ryujinx.Common/GraphicsDriver/NVThreadedOptimization.cs +++ b/src/Ryujinx.Common/GraphicsDriver/NVThreadedOptimization.cs @@ -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 { diff --git a/src/Ryujinx.Common/Hash128.cs b/src/Ryujinx.Common/Hash128.cs index e0ffd230e..be73b6e39 100644 --- a/src/Ryujinx.Common/Hash128.cs +++ b/src/Ryujinx.Common/Hash128.cs @@ -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 + public struct Hash128(ulong low, ulong high) : IEquatable { - 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 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 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 acc, ReadOnlySpan input, ReadOnlySpan secret) { - return Low == cmpObj.Low && High == cmpObj.High; + if (Avx2.IsSupported) + { + fixed (ulong* pAcc = acc) + { + fixed (byte* pInput = input, pSecret = secret) + { + Vector256* xAcc = (Vector256*)pAcc; + Vector256* xInput = (Vector256*)pInput; + Vector256* xSecret = (Vector256*)pSecret; + + for (ulong i = 0; i < StripeLen / 32; i++) + { + Vector256 dataVec = xInput[i]; + Vector256 keyVec = xSecret[i]; + Vector256 dataKey = Avx2.Xor(dataVec, keyVec); + Vector256 dataKeyLo = Avx2.Shuffle(dataKey.AsUInt32(), 0b00110001); + Vector256 product = Avx2.Multiply(dataKey.AsUInt32(), dataKeyLo); + Vector256 dataSwap = Avx2.Shuffle(dataVec.AsUInt32(), 0b01001110); + Vector256 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* xAcc = (Vector128*)pAcc; + Vector128* xInput = (Vector128*)pInput; + Vector128* xSecret = (Vector128*)pSecret; + + for (ulong i = 0; i < StripeLen / 16; i++) + { + Vector128 dataVec = xInput[i]; + Vector128 keyVec = xSecret[i]; + Vector128 dataKey = Sse2.Xor(dataVec, keyVec); + Vector128 dataKeyLo = Sse2.Shuffle(dataKey.AsUInt32(), 0b00110001); + Vector128 product = Sse2.Multiply(dataKey.AsUInt32(), dataKeyLo); + Vector128 dataSwap = Sse2.Shuffle(dataVec.AsUInt32(), 0b01001110); + Vector128 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 acc, ReadOnlySpan secret) { - return HashCode.Combine(Low, High); + if (Avx2.IsSupported) + { + fixed (ulong* pAcc = acc) + { + fixed (byte* pSecret = secret) + { + Vector256 prime32 = Vector256.Create(Prime32_1); + Vector256* xAcc = (Vector256*)pAcc; + Vector256* xSecret = (Vector256*)pSecret; + + for (ulong i = 0; i < StripeLen / 32; i++) + { + Vector256 accVec = xAcc[i]; + Vector256 shifted = Avx2.ShiftRightLogical(accVec, 47); + Vector256 dataVec = Avx2.Xor(accVec, shifted); + + Vector256 keyVec = xSecret[i]; + Vector256 dataKey = Avx2.Xor(dataVec.AsUInt32(), keyVec.AsUInt32()); + + Vector256 dataKeyHi = Avx2.Shuffle(dataKey.AsUInt32(), 0b00110001); + Vector256 prodLo = Avx2.Multiply(dataKey, prime32); + Vector256 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 prime32 = Vector128.Create(Prime32_1); + Vector128* xAcc = (Vector128*)pAcc; + Vector128* xSecret = (Vector128*)pSecret; + + for (ulong i = 0; i < StripeLen / 16; i++) + { + Vector128 accVec = xAcc[i]; + Vector128 shifted = Sse2.ShiftRightLogical(accVec, 47); + Vector128 dataVec = Sse2.Xor(accVec, shifted); + + Vector128 keyVec = xSecret[i]; + Vector128 dataKey = Sse2.Xor(dataVec.AsUInt32(), keyVec.AsUInt32()); + + Vector128 dataKeyHi = Sse2.Shuffle(dataKey.AsUInt32(), 0b00110001); + Vector128 prodLo = Sse2.Multiply(dataKey, prime32); + Vector128 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 acc, ReadOnlySpan input, ReadOnlySpan secret, int nbStripes) + { + for (int n = 0; n < nbStripes; n++) + { + ReadOnlySpan inData = input[(n * StripeLen)..]; + Xxh3Accumulate512(acc, inData, secret[(n * SecretConsumeRate)..]); + } + } + + private static void Xxh3HashLongInternalLoop(Span acc, ReadOnlySpan input, ReadOnlySpan 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 p = input[^StripeLen..]; + Xxh3Accumulate512(acc, p, secret[(secret.Length - StripeLen - SecretLastAccStart)..]); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static ulong Xxh3Mix2Accs(Span acc, ReadOnlySpan secret) + { + return Mul128Fold64( + acc[0] ^ BinaryPrimitives.ReadUInt64LittleEndian(secret), + acc[1] ^ BinaryPrimitives.ReadUInt64LittleEndian(secret[8..])); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static ulong Xxh3MergeAccs(Span acc, ReadOnlySpan 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 input, ReadOnlySpan secret) + { + Span 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 input, ReadOnlySpan 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 input, ReadOnlySpan 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 input, ReadOnlySpan 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 input, ReadOnlySpan 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 input, ReadOnlySpan 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 input, ReadOnlySpan input2, ReadOnlySpan 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 input, ReadOnlySpan 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 input, ReadOnlySpan 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 input, ReadOnlySpan 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 } } diff --git a/src/Ryujinx.Common/Utilities/JsonHelper.cs b/src/Ryujinx.Common/Utilities/JsonHelper.cs index 95daec27a..65b8cb109 100644 --- a/src/Ryujinx.Common/Utilities/JsonHelper.cs +++ b/src/Ryujinx.Common/Utilities/JsonHelper.cs @@ -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 { diff --git a/src/Ryujinx.Common/XXHash128.cs b/src/Ryujinx.Common/XXHash128.cs deleted file mode 100644 index 686867c9d..000000000 --- a/src/Ryujinx.Common/XXHash128.cs +++ /dev/null @@ -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 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 acc, ReadOnlySpan input, ReadOnlySpan secret) - { - if (Avx2.IsSupported) - { - fixed (ulong* pAcc = acc) - { - fixed (byte* pInput = input, pSecret = secret) - { - Vector256* xAcc = (Vector256*)pAcc; - Vector256* xInput = (Vector256*)pInput; - Vector256* xSecret = (Vector256*)pSecret; - - for (ulong i = 0; i < StripeLen / 32; i++) - { - Vector256 dataVec = xInput[i]; - Vector256 keyVec = xSecret[i]; - Vector256 dataKey = Avx2.Xor(dataVec, keyVec); - Vector256 dataKeyLo = Avx2.Shuffle(dataKey.AsUInt32(), 0b00110001); - Vector256 product = Avx2.Multiply(dataKey.AsUInt32(), dataKeyLo); - Vector256 dataSwap = Avx2.Shuffle(dataVec.AsUInt32(), 0b01001110); - Vector256 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* xAcc = (Vector128*)pAcc; - Vector128* xInput = (Vector128*)pInput; - Vector128* xSecret = (Vector128*)pSecret; - - for (ulong i = 0; i < StripeLen / 16; i++) - { - Vector128 dataVec = xInput[i]; - Vector128 keyVec = xSecret[i]; - Vector128 dataKey = Sse2.Xor(dataVec, keyVec); - Vector128 dataKeyLo = Sse2.Shuffle(dataKey.AsUInt32(), 0b00110001); - Vector128 product = Sse2.Multiply(dataKey.AsUInt32(), dataKeyLo); - Vector128 dataSwap = Sse2.Shuffle(dataVec.AsUInt32(), 0b01001110); - Vector128 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 acc, ReadOnlySpan secret) - { - if (Avx2.IsSupported) - { - fixed (ulong* pAcc = acc) - { - fixed (byte* pSecret = secret) - { - Vector256 prime32 = Vector256.Create(Prime32_1); - Vector256* xAcc = (Vector256*)pAcc; - Vector256* xSecret = (Vector256*)pSecret; - - for (ulong i = 0; i < StripeLen / 32; i++) - { - Vector256 accVec = xAcc[i]; - Vector256 shifted = Avx2.ShiftRightLogical(accVec, 47); - Vector256 dataVec = Avx2.Xor(accVec, shifted); - - Vector256 keyVec = xSecret[i]; - Vector256 dataKey = Avx2.Xor(dataVec.AsUInt32(), keyVec.AsUInt32()); - - Vector256 dataKeyHi = Avx2.Shuffle(dataKey.AsUInt32(), 0b00110001); - Vector256 prodLo = Avx2.Multiply(dataKey, prime32); - Vector256 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 prime32 = Vector128.Create(Prime32_1); - Vector128* xAcc = (Vector128*)pAcc; - Vector128* xSecret = (Vector128*)pSecret; - - for (ulong i = 0; i < StripeLen / 16; i++) - { - Vector128 accVec = xAcc[i]; - Vector128 shifted = Sse2.ShiftRightLogical(accVec, 47); - Vector128 dataVec = Sse2.Xor(accVec, shifted); - - Vector128 keyVec = xSecret[i]; - Vector128 dataKey = Sse2.Xor(dataVec.AsUInt32(), keyVec.AsUInt32()); - - Vector128 dataKeyHi = Sse2.Shuffle(dataKey.AsUInt32(), 0b00110001); - Vector128 prodLo = Sse2.Multiply(dataKey, prime32); - Vector128 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 acc, ReadOnlySpan input, ReadOnlySpan secret, int nbStripes) - { - for (int n = 0; n < nbStripes; n++) - { - ReadOnlySpan inData = input[(n * StripeLen)..]; - Xxh3Accumulate512(acc, inData, secret[(n * SecretConsumeRate)..]); - } - } - - private static void Xxh3HashLongInternalLoop(Span acc, ReadOnlySpan input, ReadOnlySpan 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 p = input[^StripeLen..]; - Xxh3Accumulate512(acc, p, secret[(secret.Length - StripeLen - SecretLastAccStart)..]); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static ulong Xxh3Mix2Accs(Span acc, ReadOnlySpan secret) - { - return Mul128Fold64( - acc[0] ^ BinaryPrimitives.ReadUInt64LittleEndian(secret), - acc[1] ^ BinaryPrimitives.ReadUInt64LittleEndian(secret[8..])); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static ulong Xxh3MergeAccs(Span acc, ReadOnlySpan 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 input, ReadOnlySpan secret) - { - Span 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 input, ReadOnlySpan 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 input, ReadOnlySpan 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 input, ReadOnlySpan 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 input, ReadOnlySpan 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 input, ReadOnlySpan 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 input, ReadOnlySpan input2, ReadOnlySpan 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 input, ReadOnlySpan 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 input, ReadOnlySpan 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 input, ReadOnlySpan 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 input) - { - return Xxh3128bitsInternal(input, Xxh3KSecret, 0UL); - } - } -} diff --git a/src/Ryujinx.HLE/FileSystem/ContentManager.cs b/src/Ryujinx.HLE/FileSystem/ContentManager.cs index e6c0fce08..293ff411c 100644 --- a/src/Ryujinx.HLE/FileSystem/ContentManager.cs +++ b/src/Ryujinx.HLE/FileSystem/ContentManager.cs @@ -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> 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() diff --git a/src/Ryujinx.UI.Common/Helper/SetupValidator.cs b/src/Ryujinx.UI.Common/Helper/SetupValidator.cs index a954be26f..5e2d3a584 100644 --- a/src/Ryujinx.UI.Common/Helper/SetupValidator.cs +++ b/src/Ryujinx.UI.Common/Helper/SetupValidator.cs @@ -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; } } } diff --git a/src/Ryujinx.UI.Common/Helper/ShortcutHelper.cs b/src/Ryujinx.UI.Common/Helper/ShortcutHelper.cs index 1849f40cb..8c006a227 100644 --- a/src/Ryujinx.UI.Common/Helper/ShortcutHelper.cs +++ b/src/Ryujinx.UI.Common/Helper/ShortcutHelper.cs @@ -140,11 +140,11 @@ namespace Ryujinx.UI.Common.Helper argsList.Add($"\"{appFilePath}\""); - return String.Join(" ", argsList); + return string.Join(" ", argsList); } /// - /// 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. /// /// The source bitmap image that will be saved as an .ico file /// The location that the new .ico file will be saved too (Make sure to include '.ico' in the path). diff --git a/src/Ryujinx.UI.Common/Helper/TitleUpdatesHelper.cs b/src/Ryujinx.UI.Common/Helper/TitleUpdatesHelper.cs index 9dc3d4f73..6edd613b3 100644 --- a/src/Ryujinx.UI.Common/Helper/TitleUpdatesHelper.cs +++ b/src/Ryujinx.UI.Common/Helper/TitleUpdatesHelper.cs @@ -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 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 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"); } } diff --git a/src/Ryujinx/AppHost.cs b/src/Ryujinx/AppHost.cs index a4301fdd3..c27e70313 100644 --- a/src/Ryujinx/AppHost.cs +++ b/src/Ryujinx/AppHost.cs @@ -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);