implement pipeline cache serializing

This commit is contained in:
Samuliak 2024-10-15 07:48:59 +02:00
parent e9e510d2cd
commit 6b47d4f61e
No known key found for this signature in database
3 changed files with 66 additions and 35 deletions

View file

@ -64,7 +64,7 @@ FileCache* s_shaderCacheGeneric = nullptr; // contains hardware and version inde
#define SHADER_CACHE_TYPE_PIXEL (2) #define SHADER_CACHE_TYPE_PIXEL (2)
bool LatteShaderCache_readSeparableShader(uint8* shaderInfoData, sint32 shaderInfoSize); bool LatteShaderCache_readSeparableShader(uint8* shaderInfoData, sint32 shaderInfoSize);
void LatteShaderCache_LoadVulkanPipelineCache(uint64 cacheTitleId); void LatteShaderCache_LoadPipelineCache(uint64 cacheTitleId);
bool LatteShaderCache_updatePipelineLoadingProgress(); bool LatteShaderCache_updatePipelineLoadingProgress();
void LatteShaderCache_ShowProgress(const std::function <bool(void)>& loadUpdateFunc, bool isPipelines); void LatteShaderCache_ShowProgress(const std::function <bool(void)>& loadUpdateFunc, bool isPipelines);
@ -347,9 +347,9 @@ void LatteShaderCache_Load()
cemuLog_log(LogType::Force, "Shader cache loaded with {} shaders. Commited mem {}MB. Took {}ms", numLoadedShaders, (sint32)(memCommited/1024/1024), timeLoad); cemuLog_log(LogType::Force, "Shader cache loaded with {} shaders. Commited mem {}MB. Took {}ms", numLoadedShaders, (sint32)(memCommited/1024/1024), timeLoad);
#endif #endif
LatteShaderCache_finish(); LatteShaderCache_finish();
// if Vulkan then also load pipeline cache // if Vulkan or Metal then also load pipeline cache
if (g_renderer->GetType() == RendererAPI::Vulkan) if (g_renderer->GetType() == RendererAPI::Vulkan || g_renderer->GetType() == RendererAPI::Metal)
LatteShaderCache_LoadVulkanPipelineCache(cacheTitleId); LatteShaderCache_LoadPipelineCache(cacheTitleId);
g_renderer->BeginFrame(true); g_renderer->BeginFrame(true);
@ -504,13 +504,18 @@ void LatteShaderCache_ShowProgress(const std::function <bool(void)>& loadUpdateF
} }
} }
void LatteShaderCache_LoadVulkanPipelineCache(uint64 cacheTitleId) void LatteShaderCache_LoadPipelineCache(uint64 cacheTitleId)
{ {
auto& pipelineCache = VulkanPipelineStableCache::GetInstance(); if (g_renderer->GetType() == RendererAPI::Vulkan)
g_shaderCacheLoaderState.pipelineFileCount = pipelineCache.BeginLoading(cacheTitleId); g_shaderCacheLoaderState.pipelineFileCount = VulkanPipelineStableCache::GetInstance().BeginLoading(cacheTitleId);
else if (g_renderer->GetType() == RendererAPI::Metal)
g_shaderCacheLoaderState.pipelineFileCount = MetalPipelineCache::GetInstance().BeginLoading(cacheTitleId);
g_shaderCacheLoaderState.loadedPipelines = 0; g_shaderCacheLoaderState.loadedPipelines = 0;
LatteShaderCache_ShowProgress(LatteShaderCache_updatePipelineLoadingProgress, true); LatteShaderCache_ShowProgress(LatteShaderCache_updatePipelineLoadingProgress, true);
pipelineCache.EndLoading(); if (g_renderer->GetType() == RendererAPI::Vulkan)
VulkanPipelineStableCache::GetInstance().EndLoading();
else if (g_renderer->GetType() == RendererAPI::Metal)
MetalPipelineCache::GetInstance().EndLoading();
if(Latte_GetStopSignal()) if(Latte_GetStopSignal())
LatteThread_Exit(); LatteThread_Exit();
} }
@ -518,7 +523,12 @@ void LatteShaderCache_LoadVulkanPipelineCache(uint64 cacheTitleId)
bool LatteShaderCache_updatePipelineLoadingProgress() bool LatteShaderCache_updatePipelineLoadingProgress()
{ {
uint32 pipelinesMissingShaders = 0; uint32 pipelinesMissingShaders = 0;
return VulkanPipelineStableCache::GetInstance().UpdateLoading(g_shaderCacheLoaderState.loadedPipelines, pipelinesMissingShaders); if (g_renderer->GetType() == RendererAPI::Vulkan)
return VulkanPipelineStableCache::GetInstance().UpdateLoading(g_shaderCacheLoaderState.loadedPipelines, pipelinesMissingShaders);
else if (g_renderer->GetType() == RendererAPI::Metal)
return MetalPipelineCache::GetInstance().UpdateLoading(g_shaderCacheLoaderState.loadedPipelines, pipelinesMissingShaders);
return false;
} }
uint64 LatteShaderCache_getShaderNameInTransferableCache(uint64 baseHash, uint32 shaderType) uint64 LatteShaderCache_getShaderNameInTransferableCache(uint64 baseHash, uint32 shaderType)
@ -783,9 +793,11 @@ void LatteShaderCache_Close()
else if (g_renderer->GetType() == RendererAPI::Metal) else if (g_renderer->GetType() == RendererAPI::Metal)
RendererShaderMtl::ShaderCacheLoading_Close(); RendererShaderMtl::ShaderCacheLoading_Close();
// if Vulkan then also close pipeline cache // if Vulkan or Metal then also close pipeline cache
if (g_renderer->GetType() == RendererAPI::Vulkan) if (g_renderer->GetType() == RendererAPI::Vulkan)
VulkanPipelineStableCache::GetInstance().Close(); VulkanPipelineStableCache::GetInstance().Close();
else if (g_renderer->GetType() == RendererAPI::Metal)
MetalPipelineCache::GetInstance().Close();
} }
#include <wx/msgdlg.h> #include <wx/msgdlg.h>

View file

@ -15,6 +15,43 @@
#include "config/ActiveSettings.h" #include "config/ActiveSettings.h"
#include <openssl/sha.h> #include <openssl/sha.h>
MetalPipelineCache* g_mtlPipelineCache = nullptr;
MetalPipelineCache& MetalPipelineCache::GetInstance()
{
return *g_mtlPipelineCache;
}
MetalPipelineCache::MetalPipelineCache(class MetalRenderer* metalRenderer) : m_mtlr{metalRenderer}
{
g_mtlPipelineCache = this;
}
MetalPipelineCache::~MetalPipelineCache()
{
for (auto& [key, value] : m_pipelineCache)
{
value->release();
}
}
MTL::RenderPipelineState* MetalPipelineCache::GetRenderPipelineState(const LatteFetchShader* fetchShader, const LatteDecompilerShader* vertexShader, const LatteDecompilerShader* geometryShader, const LatteDecompilerShader* pixelShader, class CachedFBOMtl* lastUsedFBO, class CachedFBOMtl* activeFBO, const LatteContextRegister& lcr)
{
uint64 hash = CalculatePipelineHash(fetchShader, vertexShader, geometryShader, pixelShader, lastUsedFBO, activeFBO, lcr);
auto& pipeline = m_pipelineCache[hash];
if (pipeline)
return pipeline;
MetalPipelineCompiler compiler(m_mtlr);
compiler.InitFromState(fetchShader, vertexShader, geometryShader, pixelShader, lastUsedFBO, activeFBO, lcr);
pipeline = compiler.Compile(false, true);
if (!HasPipelineCached(vertexShader->baseHash, hash))
AddCurrentStateToCache(vertexShader->baseHash, hash);
return pipeline;
}
uint64 MetalPipelineCache::CalculatePipelineHash(const LatteFetchShader* fetchShader, const LatteDecompilerShader* vertexShader, const LatteDecompilerShader* geometryShader, const LatteDecompilerShader* pixelShader, class CachedFBOMtl* lastUsedFBO, class CachedFBOMtl* activeFBO, const LatteContextRegister& lcr) uint64 MetalPipelineCache::CalculatePipelineHash(const LatteFetchShader* fetchShader, const LatteDecompilerShader* vertexShader, const LatteDecompilerShader* geometryShader, const LatteDecompilerShader* pixelShader, class CachedFBOMtl* lastUsedFBO, class CachedFBOMtl* activeFBO, const LatteContextRegister& lcr)
{ {
// Hash // Hash
@ -117,27 +154,6 @@ uint64 MetalPipelineCache::CalculatePipelineHash(const LatteFetchShader* fetchSh
return stateHash; return stateHash;
} }
MetalPipelineCache::~MetalPipelineCache()
{
for (auto& [key, value] : m_pipelineCache)
{
value->release();
}
}
MTL::RenderPipelineState* MetalPipelineCache::GetRenderPipelineState(const LatteFetchShader* fetchShader, const LatteDecompilerShader* vertexShader, const LatteDecompilerShader* geometryShader, const LatteDecompilerShader* pixelShader, class CachedFBOMtl* lastUsedFBO, class CachedFBOMtl* activeFBO, const LatteContextRegister& lcr)
{
auto& pipeline = m_pipelineCache[CalculatePipelineHash(fetchShader, vertexShader, geometryShader, pixelShader, lastUsedFBO, activeFBO, lcr)];
if (pipeline)
return pipeline;
MetalPipelineCompiler compiler(m_mtlr);
compiler.InitFromState(fetchShader, vertexShader, geometryShader, pixelShader, lastUsedFBO, activeFBO, lcr);
pipeline = compiler.Compile(false, true);
return pipeline;
}
struct struct
{ {
uint32 pipelineLoadIndex; uint32 pipelineLoadIndex;
@ -181,7 +197,7 @@ uint32 MetalPipelineCache::BeginLoading(uint64 cacheTitleId)
s_cache = FileCache::Open(pathCacheFile, true, LatteShaderCache_getPipelineCacheExtraVersion(cacheTitleId)); s_cache = FileCache::Open(pathCacheFile, true, LatteShaderCache_getPipelineCacheExtraVersion(cacheTitleId));
if (!s_cache) if (!s_cache)
{ {
cemuLog_log(LogType::Force, "Failed to open or create Vulkan pipeline cache file: {}", _pathToUtf8(pathCacheFile)); cemuLog_log(LogType::Force, "Failed to open or create Metal pipeline cache file: {}", _pathToUtf8(pathCacheFile));
return 0; return 0;
} }
else else
@ -436,7 +452,7 @@ bool MetalPipelineCache::DeserializePipeline(MemStreamReader& memReader, CachedP
// version // version
if (memReader.readBE<uint8>() != 1) if (memReader.readBE<uint8>() != 1)
{ {
cemuLog_log(LogType::Force, "Cached Vulkan pipeline corrupted or has unknown version"); cemuLog_log(LogType::Force, "Cached Metal pipeline corrupted or has unknown version");
return false; return false;
} }
// shader hashes // shader hashes

View file

@ -7,7 +7,7 @@
// TODO: binary archives // TODO: binary archives
class MetalPipelineCache class MetalPipelineCache
{ {
public: private:
struct PipelineHash struct PipelineHash
{ {
PipelineHash(uint64 h0, uint64 h1) : h0(h0), h1(h1) {}; PipelineHash(uint64 h0, uint64 h1) : h0(h0), h1(h1) {};
@ -30,7 +30,10 @@ public:
}; };
}; };
MetalPipelineCache(class MetalRenderer* metalRenderer) : m_mtlr{metalRenderer} {} public:
static MetalPipelineCache& GetInstance();
MetalPipelineCache(class MetalRenderer* metalRenderer);
~MetalPipelineCache(); ~MetalPipelineCache();
MTL::RenderPipelineState* GetRenderPipelineState(const LatteFetchShader* fetchShader, const LatteDecompilerShader* vertexShader, const LatteDecompilerShader* geometryShader, const LatteDecompilerShader* pixelShader, class CachedFBOMtl* lastUsedFBO, class CachedFBOMtl* activeFBO, const LatteContextRegister& lcr); MTL::RenderPipelineState* GetRenderPipelineState(const LatteFetchShader* fetchShader, const LatteDecompilerShader* vertexShader, const LatteDecompilerShader* geometryShader, const LatteDecompilerShader* pixelShader, class CachedFBOMtl* lastUsedFBO, class CachedFBOMtl* activeFBO, const LatteContextRegister& lcr);