using Ryujinx.Common;
using Ryujinx.Common.Configuration;
using Ryujinx.Graphics.Gpu.Shader.Cache.Definition;
using System;
using System.Collections.Generic;
using System.IO;
namespace Ryujinx.Graphics.Gpu.Shader.Cache
{
///
/// Global Manager of the shader cache.
///
class CacheManager : IDisposable
{
private CacheGraphicsApi _graphicsApi;
private CacheHashType _hashType;
private string _shaderProvider;
///
/// Cache storing raw Maxwell shaders as programs.
///
private CacheCollection _guestProgramCache;
///
/// Cache storing raw host programs.
///
private CacheCollection _hostProgramCache;
///
/// Version of the guest cache shader (to increment when guest cache structure change).
///
private const ulong GuestCacheVersion = 1717;
///
/// Create a new cache manager instance
///
/// The graphics api in use
/// The hash type in use for the cache
/// The name of the codegen provider
/// The guest application title ID
/// Version of the codegen
public CacheManager(CacheGraphicsApi graphicsApi, CacheHashType hashType, string shaderProvider, string titleId, ulong shaderCodeGenVersion)
{
_graphicsApi = graphicsApi;
_hashType = hashType;
_shaderProvider = shaderProvider;
string baseCacheDirectory = Path.Combine(AppDataManager.GamesDirPath, titleId, "cache", "shader");
_guestProgramCache = new CacheCollection(baseCacheDirectory, _hashType, CacheGraphicsApi.Guest, "", "program", GuestCacheVersion);
_hostProgramCache = new CacheCollection(baseCacheDirectory, _hashType, _graphicsApi, _shaderProvider, "host", shaderCodeGenVersion);
}
///
/// Entries to remove from the manifest.
///
/// Entries to remove from the manifest of all caches
public void RemoveManifestEntries(HashSet entries)
{
_guestProgramCache.RemoveManifestEntriesAsync(entries);
_hostProgramCache.RemoveManifestEntriesAsync(entries);
}
///
/// Queue a task to flush temporary files to the archives.
///
public void FlushToArchive()
{
_guestProgramCache.FlushToArchiveAsync();
_hostProgramCache.FlushToArchiveAsync();
}
///
/// Wait for all tasks before this given point to be done.
///
public void Synchronize()
{
_guestProgramCache.Synchronize();
_hostProgramCache.Synchronize();
}
///
/// Computes the hash of some data using the current cache hashing algorithm.
///
/// Some data to generate a hash for.
/// The hash of some data using the current hashing algorithm of the cache
public Hash128 ComputeHash(ReadOnlySpan data)
{
return XXHash128.ComputeHash(data);
}
///
/// Save a shader program not present in the program cache.
///
/// Target program code hash
/// Guest program raw data
/// Host program raw data
public void SaveProgram(ref Hash128 programCodeHash, byte[] guestProgram, byte[] hostProgram)
{
_guestProgramCache.AddValue(ref programCodeHash, guestProgram);
_hostProgramCache.AddValue(ref programCodeHash, hostProgram);
}
///
/// Add a host shader program not present in the program cache.
///
/// Target program code hash
/// Host program raw data
public void AddHostProgram(ref Hash128 programCodeHash, byte[] data)
{
_hostProgramCache.AddValue(ref programCodeHash, data);
}
///
/// Replace a host shader program present in the program cache.
///
/// Target program code hash
/// Host program raw data
public void ReplaceHostProgram(ref Hash128 programCodeHash, byte[] data)
{
_hostProgramCache.ReplaceValue(ref programCodeHash, data);
}
///
/// Get all guest program hashes.
///
/// All guest program hashes
public ReadOnlySpan GetGuestProgramList()
{
return _guestProgramCache.HashTable;
}
///
/// Get a host program by hash.
///
/// The given hash
/// The host program if present or null
public byte[] GetHostProgramByHash(ref Hash128 hash)
{
return _hostProgramCache.GetValueRaw(ref hash);
}
///
/// Get a guest program by hash.
///
/// The given hash
/// The guest program if present or null
public byte[] GetGuestProgramByHash(ref Hash128 hash)
{
return _guestProgramCache.GetValueRaw(ref hash);
}
public void Dispose()
{
Dispose(true);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
_guestProgramCache.Dispose();
_hostProgramCache.Dispose();
}
}
}
}