Skip to content

Commit

Permalink
save pipelines to a binary archive
Browse files Browse the repository at this point in the history
  • Loading branch information
SamoZ256 committed Aug 14, 2024
1 parent 53efb9e commit 3c1a747
Show file tree
Hide file tree
Showing 6 changed files with 150 additions and 93 deletions.
11 changes: 6 additions & 5 deletions src/Cafe/HW/Latte/Core/LatteBufferCache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,8 @@ class BufferCacheNode
{
if (m_hasCacheAlloc)
{
cemu_assert_debug(isInUse() == false);
// HACK
//cemu_assert_debug(isInUse() == false);
g_gpuBufferHeap->freeOffset(m_cacheOffset);
m_hasCacheAlloc = false;
}
Expand Down Expand Up @@ -441,7 +442,7 @@ class BufferCacheNode
if (uploadBegin >= uploadEnd)
return; // reserve range not within invalidation or range is zero sized


if (uploadBegin == m_invalidationRangeBegin)
{
m_invalidationRangeBegin = uploadEnd;
Expand Down Expand Up @@ -536,7 +537,7 @@ class BufferCacheNode
MPTR m_invalidationRangeBegin;
MPTR m_invalidationRangeEnd;

BufferCacheNode(MPTR rangeBegin, MPTR rangeEnd): m_rangeBegin(rangeBegin), m_rangeEnd(rangeEnd)
BufferCacheNode(MPTR rangeBegin, MPTR rangeEnd): m_rangeBegin(rangeBegin), m_rangeEnd(rangeEnd)
{
flagInUse();
cemu_assert_debug(rangeBegin < rangeEnd);
Expand Down Expand Up @@ -740,7 +741,7 @@ class BufferCacheNode
cemu_assert_debug(rangeEnd <= pageRangeEnd);
cemu_assert_debug((rangeBegin & 0xF) == 0);
cemu_assert_debug((rangeEnd & 0xF) == 0);

auto pageInfo = m_pageInfo.data() + pageIndex;
pageInfo->hasStreamoutData = true;

Expand Down Expand Up @@ -805,7 +806,7 @@ class BufferCacheNode
s_allCacheNodes.clear();
g_deallocateQueue.clear();
}

static void ProcessDeallocations()
{
for(auto& itr : g_deallocateQueue)
Expand Down
8 changes: 4 additions & 4 deletions src/Cafe/HW/Latte/Core/LatteShaderCache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
#include "Cafe/HW/Latte/Renderer/Renderer.h"
#include "Cafe/HW/Latte/Renderer/OpenGL/RendererShaderGL.h"
#include "Cafe/HW/Latte/Renderer/Vulkan/RendererShaderVk.h"
#include "Cafe/HW/Latte/Renderer/Metal/RendererShaderMtl.h"
#include "Cafe/HW/Latte/Renderer/Metal/MetalPipelineCache.h"
#include "Cafe/HW/Latte/Renderer/Vulkan/VulkanPipelineStableCache.h"

#include <imgui.h>
Expand Down Expand Up @@ -163,7 +163,7 @@ void LatteShaderCache_finish()
else if (g_renderer->GetType() == RendererAPI::OpenGL)
RendererShaderGL::ShaderCacheLoading_end();
else if (g_renderer->GetType() == RendererAPI::Metal)
RendererShaderMtl::ShaderCacheLoading_end();
MetalPipelineCache::ShaderCacheLoading_end();
}

uint32 LatteShaderCache_getShaderCacheExtraVersion(uint64 titleId)
Expand Down Expand Up @@ -247,7 +247,7 @@ void LatteShaderCache_Load()
else if (g_renderer->GetType() == RendererAPI::OpenGL)
RendererShaderGL::ShaderCacheLoading_begin(cacheTitleId);
else if (g_renderer->GetType() == RendererAPI::Metal)
RendererShaderMtl::ShaderCacheLoading_begin(cacheTitleId);
MetalPipelineCache::ShaderCacheLoading_begin(cacheTitleId);
// get cache file name
const auto pathGeneric = ActiveSettings::GetCachePath("shaderCache/transferable/{:016x}_shaders.bin", cacheTitleId);
const auto pathGenericPre1_25_0 = ActiveSettings::GetCachePath("shaderCache/transferable/{:016x}.bin", cacheTitleId); // before 1.25.0
Expand Down Expand Up @@ -780,7 +780,7 @@ void LatteShaderCache_Close()
else if (g_renderer->GetType() == RendererAPI::OpenGL)
RendererShaderGL::ShaderCacheLoading_Close();
else if (g_renderer->GetType() == RendererAPI::Metal)
RendererShaderMtl::ShaderCacheLoading_Close();
MetalPipelineCache::ShaderCacheLoading_Close();

// if Vulkan then also close pipeline cache
if (g_renderer->GetType() == RendererAPI::Vulkan)
Expand Down
131 changes: 124 additions & 7 deletions src/Cafe/HW/Latte/Renderer/Metal/MetalPipelineCache.cpp
Original file line number Diff line number Diff line change
@@ -1,13 +1,37 @@
#include "Cafe/HW/Latte/Renderer/Metal/MetalCommon.h"
#include "Cafe/HW/Latte/Renderer/Metal/MetalPipelineCache.h"
#include "Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h"
#include "Foundation/NSObject.hpp"
#include "HW/Latte/Renderer/Metal/CachedFBOMtl.h"
#include "HW/Latte/Renderer/Metal/LatteToMtl.h"
#include "HW/Latte/Renderer/Metal/RendererShaderMtl.h"
#include "HW/Latte/Renderer/Metal/LatteTextureViewMtl.h"

#include "HW/Latte/Core/FetchShader.h"
#include "HW/Latte/ISA/RegDefines.h"
#include "config/ActiveSettings.h"

#define INVALID_TITLE_ID 0xFFFFFFFFFFFFFFFF

uint64 s_cacheTitleId = INVALID_TITLE_ID;

extern std::atomic_int g_compiled_shaders_total;
extern std::atomic_int g_compiled_shaders_async;

void MetalPipelineCache::ShaderCacheLoading_begin(uint64 cacheTitleId)
{
s_cacheTitleId = cacheTitleId;
}

void MetalPipelineCache::ShaderCacheLoading_end()
{
}

void MetalPipelineCache::ShaderCacheLoading_Close()
{
g_compiled_shaders_total = 0;
g_compiled_shaders_async = 0;
}

MetalPipelineCache::~MetalPipelineCache()
{
Expand All @@ -16,6 +40,17 @@ MetalPipelineCache::~MetalPipelineCache()
pair.second->release();
}
m_pipelineCache.clear();

NS::Error* error = nullptr;
m_binaryArchive->serializeToURL(m_binaryArchiveURL, &error);
if (error)
{
debug_printf("failed to serialize binary archive: %s\n", error->localizedDescription()->utf8String());
error->release();
}
m_binaryArchive->release();

m_binaryArchiveURL->release();
}

MTL::RenderPipelineState* MetalPipelineCache::GetPipelineState(const LatteFetchShader* fetchShader, const LatteDecompilerShader* vertexShader, const LatteDecompilerShader* pixelShader, CachedFBOMtl* activeFBO, const LatteContextRegister& lcr)
Expand Down Expand Up @@ -151,16 +186,41 @@ MTL::RenderPipelineState* MetalPipelineCache::GetPipelineState(const LatteFetchS
}
}

NS::Error* error = nullptr;
pipeline = m_mtlr->GetDevice()->newRenderPipelineState(desc, &error);
desc->release();
vertexDescriptor->release();
LoadBinary(desc);

NS::Error* error = nullptr;
pipeline = m_mtlr->GetDevice()->newRenderPipelineState(desc, MTL::PipelineOptionFailOnBinaryArchiveMiss, nullptr, &error);

//static uint32 oldPipelineCount = 0;
//static uint32 newPipelineCount = 0;

// Pipeline wasn't found in the binary archive, we need to compile it
if (error)
{
debug_printf("error creating render pipeline state: %s\n", error->localizedDescription()->utf8String());
error->release();
return nullptr;
desc->setBinaryArchives(nullptr);

error->release();
error = nullptr;
pipeline = m_mtlr->GetDevice()->newRenderPipelineState(desc, &error);
if (error)
{
debug_printf("error creating render pipeline state: %s\n", error->localizedDescription()->utf8String());
error->release();
}
else
{
SaveBinary(desc);
}

//newPipelineCount++;
}
//else
//{
// oldPipelineCount++;
//}
//debug_printf("%u pipelines were found in the binary archive, %u new were created\n", oldPipelineCount, newPipelineCount);
desc->release();
vertexDescriptor->release();

return pipeline;
}
Expand Down Expand Up @@ -238,3 +298,60 @@ uint64 MetalPipelineCache::CalculatePipelineHash(const LatteFetchShader* fetchSh

return stateHash;
}

void MetalPipelineCache::TryLoadBinaryArchive()
{
if (m_binaryArchive || s_cacheTitleId == INVALID_TITLE_ID)
return;

const std::string cacheFilename = fmt::format("{:016x}_mtl_pipelines.bin", s_cacheTitleId);
const fs::path cachePath = ActiveSettings::GetCachePath("shaderCache/precompiled/{}", cacheFilename);
m_binaryArchiveURL = NS::URL::fileURLWithPath(NS::String::string((const char*)cachePath.generic_u8string().c_str(), NS::ASCIIStringEncoding));

MTL::BinaryArchiveDescriptor* desc = MTL::BinaryArchiveDescriptor::alloc()->init();
desc->setUrl(m_binaryArchiveURL);

NS::Error* error = nullptr;
m_binaryArchive = m_mtlr->GetDevice()->newBinaryArchive(desc, &error);
if (error)
{
desc->setUrl(nullptr);

error->release();
error = nullptr;
m_binaryArchive = m_mtlr->GetDevice()->newBinaryArchive(desc, &error);
if (error)
{
debug_printf("failed to create binary archive: %s\n", error->localizedDescription()->utf8String());
error->release();
}
}
desc->release();
}

void MetalPipelineCache::LoadBinary(MTL::RenderPipelineDescriptor* desc)
{
TryLoadBinaryArchive();

if (!m_binaryArchive)
return;

NS::Object* binArchives[] = {m_binaryArchive};
auto binaryArchives = NS::Array::alloc()->init(binArchives, 1);
desc->setBinaryArchives(binaryArchives);
binaryArchives->release();
}

void MetalPipelineCache::SaveBinary(MTL::RenderPipelineDescriptor* desc)
{
if (!m_binaryArchive)
return;

NS::Error* error = nullptr;
m_binaryArchive->addRenderPipelineFunctions(desc, &error);
if (error)
{
debug_printf("error saving render pipeline functions: %s\n", error->localizedDescription()->utf8String());
error->release();
}
}
13 changes: 13 additions & 0 deletions src/Cafe/HW/Latte/Renderer/Metal/MetalPipelineCache.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@
class MetalPipelineCache
{
public:
static void ShaderCacheLoading_begin(uint64 cacheTitleId);
static void ShaderCacheLoading_end();
static void ShaderCacheLoading_Close();

MetalPipelineCache(class MetalRenderer* metalRenderer) : m_mtlr{metalRenderer} {}
~MetalPipelineCache();

Expand All @@ -18,5 +22,14 @@ class MetalPipelineCache

std::map<uint64, MTL::RenderPipelineState*> m_pipelineCache;

NS::URL* m_binaryArchiveURL;
MTL::BinaryArchive* m_binaryArchive;

uint64 CalculatePipelineHash(const LatteFetchShader* fetchShader, const LatteDecompilerShader* vertexShader, const LatteDecompilerShader* pixelShader, class CachedFBOMtl* activeFBO, const LatteContextRegister& lcr);

void TryLoadBinaryArchive();

void LoadBinary(MTL::RenderPipelineDescriptor* desc);

void SaveBinary(MTL::RenderPipelineDescriptor* desc);
};
73 changes: 3 additions & 70 deletions src/Cafe/HW/Latte/Renderer/Metal/RendererShaderMtl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,18 @@
#include "Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h"
#include "Cafe/HW/Latte/Renderer/Metal/LatteToMtl.h"
#include "Cafe/HW/Latte/Renderer/Metal/MetalCommon.h"
#include "Cemu/FileCache/FileCache.h"
#include "config/ActiveSettings.h"
//#include "Cemu/FileCache/FileCache.h"
//#include "config/ActiveSettings.h"

#include "Cemu/Logging/CemuLogging.h"
#include "Common/precompiled.h"

bool s_isLoadingShadersMtl{ false };
class FileCache* s_mslCache{nullptr};

extern std::atomic_int g_compiled_shaders_total;
extern std::atomic_int g_compiled_shaders_async;

RendererShaderMtl::RendererShaderMtl(MetalRenderer* mtlRenderer, ShaderType type, uint64 baseHash, uint64 auxHash, bool isGameShader, bool isGfxPackShader, const std::string& mslCode)
: RendererShader(type, baseHash, auxHash, isGameShader, isGfxPackShader), m_mtlr{mtlRenderer}
{
if (LoadBinary())
return;

if (m_type == ShaderType::kFragment)
{
// Fragment functions are compiled just-in-time
Expand All @@ -30,12 +24,8 @@ RendererShaderMtl::RendererShaderMtl(MetalRenderer* mtlRenderer, ShaderType type
Compile(mslCode);
}

// Store the compiled shader in the cache
StoreBinary();

// Count shader compilation
if (!s_isLoadingShadersMtl)
g_compiled_shaders_total++;
g_compiled_shaders_total++;
}

RendererShaderMtl::~RendererShaderMtl()
Expand Down Expand Up @@ -85,33 +75,6 @@ void RendererShaderMtl::CompileFragmentFunction(CachedFBOMtl* activeFBO)
Compile(fullCode);
}

void RendererShaderMtl::ShaderCacheLoading_begin(uint64 cacheTitleId)
{
if (s_mslCache)
{
delete s_mslCache;
}
uint32 spirvCacheMagic = GeneratePrecompiledCacheId();
const std::string cacheFilename = fmt::format("{:016x}_msl.bin", cacheTitleId);
const fs::path cachePath = ActiveSettings::GetCachePath("shaderCache/precompiled/{}", cacheFilename);
s_mslCache = FileCache::Open(cachePath, true, spirvCacheMagic);
if (!s_mslCache)
cemuLog_log(LogType::Force, "Unable to open MSL cache {}", cacheFilename);
s_isLoadingShadersMtl = true;
}

void RendererShaderMtl::ShaderCacheLoading_end()
{
s_isLoadingShadersMtl = false;
}

void RendererShaderMtl::ShaderCacheLoading_Close()
{
delete s_mslCache;
g_compiled_shaders_total = 0;
g_compiled_shaders_async = 0;
}

void RendererShaderMtl::Compile(const std::string& mslCode)
{
NS::Error* error = nullptr;
Expand All @@ -125,33 +88,3 @@ void RendererShaderMtl::Compile(const std::string& mslCode)
m_function = library->newFunction(NS::String::string("main0", NS::ASCIIStringEncoding));
library->release();
}

bool RendererShaderMtl::LoadBinary()
{
// HACK: since fragment functions are compiled just-in-time, we cannot load them from the cache
if (m_type == ShaderType::kFragment)
return false;

uint64 h1, h2;
GenerateShaderPrecompiledCacheFilename(m_type, m_baseHash, m_auxHash, h1, h2);
if (!s_mslCache->GetFile({h1, h2 }, m_binary))
return false;

// TODO: implement
return false;

return true;
}

void RendererShaderMtl::StoreBinary()
{
if (m_binary.size() == 0)
{
// TODO: retrieve the binary from the function
return;
}

uint64 h1, h2;
GenerateShaderPrecompiledCacheFilename(m_type, m_baseHash, m_auxHash, h1, h2);
s_mslCache->AddFileAsync({h1, h2 }, m_binary.data(), m_binary.size());
}
Loading

0 comments on commit 3c1a747

Please sign in to comment.