aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheGuestStorage.cs
diff options
context:
space:
mode:
authorTSR Berry <20988865+TSRBerry@users.noreply.github.com>2023-04-08 01:22:00 +0200
committerMary <thog@protonmail.com>2023-04-27 23:51:14 +0200
commitcee712105850ac3385cd0091a923438167433f9f (patch)
tree4a5274b21d8b7f938c0d0ce18736d3f2993b11b1 /Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheGuestStorage.cs
parentcd124bda587ef09668a971fa1cac1c3f0cfc9f21 (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.cs459
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