using System; using System.Runtime.InteropServices; namespace Ryujinx.Graphics.Gpu.Shader.Cache.Definition { /// /// Header of the shader cache manifest. /// [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 0x10)] struct CacheManifestHeader { /// /// The version of the cache. /// public ulong Version; /// /// The graphics api used for this cache. /// public CacheGraphicsApi GraphicsApi; /// /// The hash type used for this cache. /// public CacheHashType HashType; /// /// CRC-16 checksum over the data in the file. /// public ushort TableChecksum; /// /// Construct a new cache manifest header. /// /// The version of the cache /// The graphics api used for this cache /// The hash type used for this cache public CacheManifestHeader(ulong version, CacheGraphicsApi graphicsApi, CacheHashType hashType) { Version = version; GraphicsApi = graphicsApi; HashType = hashType; TableChecksum = 0; } /// /// Update the checksum in the header. /// /// The data to perform the checksum on public void UpdateChecksum(ReadOnlySpan data) { TableChecksum = CalculateCrc16(data); } /// /// Calculate a CRC-16 over data. /// /// The data to perform the CRC-16 on /// A CRC-16 over data private static ushort CalculateCrc16(ReadOnlySpan data) { int crc = 0; const ushort poly = 0x1021; for (int i = 0; i < data.Length; i++) { crc ^= data[i] << 8; for (int j = 0; j < 8; j++) { crc <<= 1; if ((crc & 0x10000) != 0) { crc = (crc ^ poly) & 0xFFFF; } } } return (ushort)crc; } /// /// Check the validity of the header. /// /// The target graphics api in use /// The target hash type in use /// The data after this header /// True if the header is valid /// This doesn't check that versions match public bool IsValid(CacheGraphicsApi graphicsApi, CacheHashType hashType, ReadOnlySpan data) { return GraphicsApi == graphicsApi && HashType == hashType && TableChecksum == CalculateCrc16(data); } } }