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);
}
}
}