diff options
| author | TSR Berry <20988865+TSRBerry@users.noreply.github.com> | 2023-04-08 01:22:00 +0200 |
|---|---|---|
| committer | Mary <thog@protonmail.com> | 2023-04-27 23:51:14 +0200 |
| commit | cee712105850ac3385cd0091a923438167433f9f (patch) | |
| tree | 4a5274b21d8b7f938c0d0ce18736d3f2993b11b1 /Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheGuestStorage.cs | |
| parent | cd124bda587ef09668a971fa1cac1c3f0cfc9f21 (diff) | |
Move solution and projects to src
Diffstat (limited to 'Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheGuestStorage.cs')
| -rw-r--r-- | Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheGuestStorage.cs | 459 |
1 files changed, 0 insertions, 459 deletions
diff --git a/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheGuestStorage.cs b/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheGuestStorage.cs deleted file mode 100644 index 01034b49..00000000 --- a/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheGuestStorage.cs +++ /dev/null @@ -1,459 +0,0 @@ -using Ryujinx.Common; -using System; -using System.Collections.Generic; -using System.IO; -using System.Runtime.CompilerServices; - -namespace Ryujinx.Graphics.Gpu.Shader.DiskCache -{ - /// <summary> - /// On-disk shader cache storage for guest code. - /// </summary> - class DiskCacheGuestStorage - { - private const uint TocMagic = (byte)'T' | ((byte)'O' << 8) | ((byte)'C' << 16) | ((byte)'G' << 24); - - private const ushort VersionMajor = 1; - private const ushort VersionMinor = 1; - private const uint VersionPacked = ((uint)VersionMajor << 16) | VersionMinor; - - private const string TocFileName = "guest.toc"; - private const string DataFileName = "guest.data"; - - private readonly string _basePath; - - /// <summary> - /// TOC (Table of contents) file header. - /// </summary> - private struct TocHeader - { - /// <summary> - /// Magic value, for validation and identification purposes. - /// </summary> - public uint Magic; - - /// <summary> - /// File format version. - /// </summary> - public uint Version; - - /// <summary> - /// Header padding. - /// </summary> - public uint Padding; - - /// <summary> - /// Number of modifications to the file, also the shaders count. - /// </summary> - public uint ModificationsCount; - - /// <summary> - /// Reserved space, to be used in the future. Write as zero. - /// </summary> - public ulong Reserved; - - /// <summary> - /// Reserved space, to be used in the future. Write as zero. - /// </summary> - public ulong Reserved2; - } - - /// <summary> - /// TOC (Table of contents) file entry. - /// </summary> - private struct TocEntry - { - /// <summary> - /// Offset of the data on the data file. - /// </summary> - public uint Offset; - - /// <summary> - /// Code size. - /// </summary> - public uint CodeSize; - - /// <summary> - /// Constant buffer 1 data size. - /// </summary> - public uint Cb1DataSize; - - /// <summary> - /// Hash of the code and constant buffer data. - /// </summary> - public uint Hash; - } - - /// <summary> - /// TOC (Table of contents) memory cache entry. - /// </summary> - private struct TocMemoryEntry - { - /// <summary> - /// Offset of the data on the data file. - /// </summary> - public uint Offset; - - /// <summary> - /// Code size. - /// </summary> - public uint CodeSize; - - /// <summary> - /// Constant buffer 1 data size. - /// </summary> - public uint Cb1DataSize; - - /// <summary> - /// Index of the shader on the cache. - /// </summary> - public readonly int Index; - - /// <summary> - /// Creates a new TOC memory entry. - /// </summary> - /// <param name="offset">Offset of the data on the data file</param> - /// <param name="codeSize">Code size</param> - /// <param name="cb1DataSize">Constant buffer 1 data size</param> - /// <param name="index">Index of the shader on the cache</param> - public TocMemoryEntry(uint offset, uint codeSize, uint cb1DataSize, int index) - { - Offset = offset; - CodeSize = codeSize; - Cb1DataSize = cb1DataSize; - Index = index; - } - } - - private Dictionary<uint, List<TocMemoryEntry>> _toc; - private uint _tocModificationsCount; - - private (byte[], byte[])[] _cache; - - /// <summary> - /// Creates a new disk cache guest storage. - /// </summary> - /// <param name="basePath">Base path of the disk shader cache</param> - public DiskCacheGuestStorage(string basePath) - { - _basePath = basePath; - } - - /// <summary> - /// Checks if the TOC (table of contents) file for the guest cache exists. - /// </summary> - /// <returns>True if the file exists, false otherwise</returns> - public bool TocFileExists() - { - return File.Exists(Path.Combine(_basePath, TocFileName)); - } - - /// <summary> - /// Checks if the data file for the guest cache exists. - /// </summary> - /// <returns>True if the file exists, false otherwise</returns> - public bool DataFileExists() - { - return File.Exists(Path.Combine(_basePath, DataFileName)); - } - - /// <summary> - /// Opens the guest cache TOC (table of contents) file. - /// </summary> - /// <returns>File stream</returns> - public Stream OpenTocFileStream() - { - return DiskCacheCommon.OpenFile(_basePath, TocFileName, writable: false); - } - - /// <summary> - /// Opens the guest cache data file. - /// </summary> - /// <returns>File stream</returns> - public Stream OpenDataFileStream() - { - return DiskCacheCommon.OpenFile(_basePath, DataFileName, writable: false); - } - - /// <summary> - /// Clear all content from the guest cache files. - /// </summary> - public void ClearCache() - { - using var tocFileStream = DiskCacheCommon.OpenFile(_basePath, TocFileName, writable: true); - using var dataFileStream = DiskCacheCommon.OpenFile(_basePath, DataFileName, writable: true); - - tocFileStream.SetLength(0); - dataFileStream.SetLength(0); - } - - /// <summary> - /// Loads the guest cache from file or memory cache. - /// </summary> - /// <param name="tocFileStream">Guest TOC file stream</param> - /// <param name="dataFileStream">Guest data file stream</param> - /// <param name="index">Guest shader index</param> - /// <returns>Guest code and constant buffer 1 data</returns> - public GuestCodeAndCbData LoadShader(Stream tocFileStream, Stream dataFileStream, int index) - { - if (_cache == null || index >= _cache.Length) - { - _cache = new (byte[], byte[])[Math.Max(index + 1, GetShadersCountFromLength(tocFileStream.Length))]; - } - - (byte[] guestCode, byte[] cb1Data) = _cache[index]; - - if (guestCode == null || cb1Data == null) - { - BinarySerializer tocReader = new BinarySerializer(tocFileStream); - tocFileStream.Seek(Unsafe.SizeOf<TocHeader>() + index * Unsafe.SizeOf<TocEntry>(), SeekOrigin.Begin); - - TocEntry entry = new TocEntry(); - tocReader.Read(ref entry); - - guestCode = new byte[entry.CodeSize]; - cb1Data = new byte[entry.Cb1DataSize]; - - if (entry.Offset >= (ulong)dataFileStream.Length) - { - throw new DiskCacheLoadException(DiskCacheLoadResult.FileCorruptedGeneric); - } - - dataFileStream.Seek((long)entry.Offset, SeekOrigin.Begin); - dataFileStream.Read(cb1Data); - BinarySerializer.ReadCompressed(dataFileStream, guestCode); - - _cache[index] = (guestCode, cb1Data); - } - - return new GuestCodeAndCbData(guestCode, cb1Data); - } - - /// <summary> - /// Clears guest code memory cache, forcing future loads to be from file. - /// </summary> - public void ClearMemoryCache() - { - _cache = null; - } - - /// <summary> - /// Calculates the guest shaders count from the TOC file length. - /// </summary> - /// <param name="length">TOC file length</param> - /// <returns>Shaders count</returns> - private static int GetShadersCountFromLength(long length) - { - return (int)((length - Unsafe.SizeOf<TocHeader>()) / Unsafe.SizeOf<TocEntry>()); - } - - /// <summary> - /// Adds a guest shader to the cache. - /// </summary> - /// <remarks> - /// If the shader is already on the cache, the existing index will be returned and nothing will be written. - /// </remarks> - /// <param name="data">Guest code</param> - /// <param name="cb1Data">Constant buffer 1 data accessed by the code</param> - /// <returns>Index of the shader on the cache</returns> - public int AddShader(ReadOnlySpan<byte> data, ReadOnlySpan<byte> cb1Data) - { - using var tocFileStream = DiskCacheCommon.OpenFile(_basePath, TocFileName, writable: true); - using var dataFileStream = DiskCacheCommon.OpenFile(_basePath, DataFileName, writable: true); - - TocHeader header = new TocHeader(); - - LoadOrCreateToc(tocFileStream, ref header); - - uint hash = CalcHash(data, cb1Data); - - if (_toc.TryGetValue(hash, out var list)) - { - foreach (var entry in list) - { - if (data.Length != entry.CodeSize || cb1Data.Length != entry.Cb1DataSize) - { - continue; - } - - dataFileStream.Seek((long)entry.Offset, SeekOrigin.Begin); - byte[] cachedCode = new byte[entry.CodeSize]; - byte[] cachedCb1Data = new byte[entry.Cb1DataSize]; - dataFileStream.Read(cachedCb1Data); - BinarySerializer.ReadCompressed(dataFileStream, cachedCode); - - if (data.SequenceEqual(cachedCode) && cb1Data.SequenceEqual(cachedCb1Data)) - { - return entry.Index; - } - } - } - - return WriteNewEntry(tocFileStream, dataFileStream, ref header, data, cb1Data, hash); - } - - /// <summary> - /// Loads the guest cache TOC file, or create a new one if not present. - /// </summary> - /// <param name="tocFileStream">Guest TOC file stream</param> - /// <param name="header">Set to the TOC file header</param> - private void LoadOrCreateToc(Stream tocFileStream, ref TocHeader header) - { - BinarySerializer reader = new BinarySerializer(tocFileStream); - - if (!reader.TryRead(ref header) || header.Magic != TocMagic || header.Version != VersionPacked) - { - CreateToc(tocFileStream, ref header); - } - - if (_toc == null || header.ModificationsCount != _tocModificationsCount) - { - if (!LoadTocEntries(tocFileStream, ref reader)) - { - CreateToc(tocFileStream, ref header); - } - - _tocModificationsCount = header.ModificationsCount; - } - } - - /// <summary> - /// Creates a new guest cache TOC file. - /// </summary> - /// <param name="tocFileStream">Guest TOC file stream</param> - /// <param name="header">Set to the TOC header</param> - private void CreateToc(Stream tocFileStream, ref TocHeader header) - { - BinarySerializer writer = new BinarySerializer(tocFileStream); - - header.Magic = TocMagic; - header.Version = VersionPacked; - header.Padding = 0; - header.ModificationsCount = 0; - header.Reserved = 0; - header.Reserved2 = 0; - - if (tocFileStream.Length > 0) - { - tocFileStream.Seek(0, SeekOrigin.Begin); - tocFileStream.SetLength(0); - } - - writer.Write(ref header); - } - - /// <summary> - /// Reads all the entries on the guest TOC file. - /// </summary> - /// <param name="tocFileStream">Guest TOC file stream</param> - /// <param name="reader">TOC file reader</param> - /// <returns>True if the operation was successful, false otherwise</returns> - private bool LoadTocEntries(Stream tocFileStream, ref BinarySerializer reader) - { - _toc = new Dictionary<uint, List<TocMemoryEntry>>(); - - TocEntry entry = new TocEntry(); - int index = 0; - - while (tocFileStream.Position < tocFileStream.Length) - { - if (!reader.TryRead(ref entry)) - { - return false; - } - - AddTocMemoryEntry(entry.Offset, entry.CodeSize, entry.Cb1DataSize, entry.Hash, index++); - } - - return true; - } - - /// <summary> - /// Writes a new guest code entry into the file. - /// </summary> - /// <param name="tocFileStream">TOC file stream</param> - /// <param name="dataFileStream">Data file stream</param> - /// <param name="header">TOC header, to be updated with the new count</param> - /// <param name="data">Guest code</param> - /// <param name="cb1Data">Constant buffer 1 data accessed by the guest code</param> - /// <param name="hash">Code and constant buffer data hash</param> - /// <returns>Entry index</returns> - private int WriteNewEntry( - Stream tocFileStream, - Stream dataFileStream, - ref TocHeader header, - ReadOnlySpan<byte> data, - ReadOnlySpan<byte> cb1Data, - uint hash) - { - BinarySerializer tocWriter = new BinarySerializer(tocFileStream); - - dataFileStream.Seek(0, SeekOrigin.End); - uint dataOffset = checked((uint)dataFileStream.Position); - uint codeSize = (uint)data.Length; - uint cb1DataSize = (uint)cb1Data.Length; - dataFileStream.Write(cb1Data); - BinarySerializer.WriteCompressed(dataFileStream, data, DiskCacheCommon.GetCompressionAlgorithm()); - - _tocModificationsCount = ++header.ModificationsCount; - tocFileStream.Seek(0, SeekOrigin.Begin); - tocWriter.Write(ref header); - - TocEntry entry = new TocEntry() - { - Offset = dataOffset, - CodeSize = codeSize, - Cb1DataSize = cb1DataSize, - Hash = hash - }; - - tocFileStream.Seek(0, SeekOrigin.End); - int index = (int)((tocFileStream.Position - Unsafe.SizeOf<TocHeader>()) / Unsafe.SizeOf<TocEntry>()); - - tocWriter.Write(ref entry); - - AddTocMemoryEntry(dataOffset, codeSize, cb1DataSize, hash, index); - - return index; - } - - /// <summary> - /// Adds an entry to the memory TOC cache. This can be used to avoid reading the TOC file all the time. - /// </summary> - /// <param name="dataOffset">Offset of the code and constant buffer data in the data file</param> - /// <param name="codeSize">Code size</param> - /// <param name="cb1DataSize">Constant buffer 1 data size</param> - /// <param name="hash">Code and constant buffer data hash</param> - /// <param name="index">Index of the data on the cache</param> - private void AddTocMemoryEntry(uint dataOffset, uint codeSize, uint cb1DataSize, uint hash, int index) - { - if (!_toc.TryGetValue(hash, out var list)) - { - _toc.Add(hash, list = new List<TocMemoryEntry>()); - } - - list.Add(new TocMemoryEntry(dataOffset, codeSize, cb1DataSize, index)); - } - - /// <summary> - /// Calculates the hash for a data pair. - /// </summary> - /// <param name="data">Data 1</param> - /// <param name="data2">Data 2</param> - /// <returns>Hash of both data</returns> - private static uint CalcHash(ReadOnlySpan<byte> data, ReadOnlySpan<byte> data2) - { - return CalcHash(data2) * 23 ^ CalcHash(data); - } - - /// <summary> - /// Calculates the hash for data. - /// </summary> - /// <param name="data">Data to be hashed</param> - /// <returns>Hash of the data</returns> - private static uint CalcHash(ReadOnlySpan<byte> data) - { - return (uint)XXHash128.ComputeHash(data).Low; - } - } -}
\ No newline at end of file |
