Skip to content

Commit 3c1a747

Browse files
committed
save pipelines to a binary archive
1 parent 53efb9e commit 3c1a747

File tree

6 files changed

+150
-93
lines changed

6 files changed

+150
-93
lines changed

src/Cafe/HW/Latte/Core/LatteBufferCache.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,8 @@ class BufferCacheNode
290290
{
291291
if (m_hasCacheAlloc)
292292
{
293-
cemu_assert_debug(isInUse() == false);
293+
// HACK
294+
//cemu_assert_debug(isInUse() == false);
294295
g_gpuBufferHeap->freeOffset(m_cacheOffset);
295296
m_hasCacheAlloc = false;
296297
}
@@ -441,7 +442,7 @@ class BufferCacheNode
441442
if (uploadBegin >= uploadEnd)
442443
return; // reserve range not within invalidation or range is zero sized
443444

444-
445+
445446
if (uploadBegin == m_invalidationRangeBegin)
446447
{
447448
m_invalidationRangeBegin = uploadEnd;
@@ -536,7 +537,7 @@ class BufferCacheNode
536537
MPTR m_invalidationRangeBegin;
537538
MPTR m_invalidationRangeEnd;
538539

539-
BufferCacheNode(MPTR rangeBegin, MPTR rangeEnd): m_rangeBegin(rangeBegin), m_rangeEnd(rangeEnd)
540+
BufferCacheNode(MPTR rangeBegin, MPTR rangeEnd): m_rangeBegin(rangeBegin), m_rangeEnd(rangeEnd)
540541
{
541542
flagInUse();
542543
cemu_assert_debug(rangeBegin < rangeEnd);
@@ -740,7 +741,7 @@ class BufferCacheNode
740741
cemu_assert_debug(rangeEnd <= pageRangeEnd);
741742
cemu_assert_debug((rangeBegin & 0xF) == 0);
742743
cemu_assert_debug((rangeEnd & 0xF) == 0);
743-
744+
744745
auto pageInfo = m_pageInfo.data() + pageIndex;
745746
pageInfo->hasStreamoutData = true;
746747

@@ -805,7 +806,7 @@ class BufferCacheNode
805806
s_allCacheNodes.clear();
806807
g_deallocateQueue.clear();
807808
}
808-
809+
809810
static void ProcessDeallocations()
810811
{
811812
for(auto& itr : g_deallocateQueue)

src/Cafe/HW/Latte/Core/LatteShaderCache.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
#include "Cafe/HW/Latte/Renderer/Renderer.h"
1212
#include "Cafe/HW/Latte/Renderer/OpenGL/RendererShaderGL.h"
1313
#include "Cafe/HW/Latte/Renderer/Vulkan/RendererShaderVk.h"
14-
#include "Cafe/HW/Latte/Renderer/Metal/RendererShaderMtl.h"
14+
#include "Cafe/HW/Latte/Renderer/Metal/MetalPipelineCache.h"
1515
#include "Cafe/HW/Latte/Renderer/Vulkan/VulkanPipelineStableCache.h"
1616

1717
#include <imgui.h>
@@ -163,7 +163,7 @@ void LatteShaderCache_finish()
163163
else if (g_renderer->GetType() == RendererAPI::OpenGL)
164164
RendererShaderGL::ShaderCacheLoading_end();
165165
else if (g_renderer->GetType() == RendererAPI::Metal)
166-
RendererShaderMtl::ShaderCacheLoading_end();
166+
MetalPipelineCache::ShaderCacheLoading_end();
167167
}
168168

169169
uint32 LatteShaderCache_getShaderCacheExtraVersion(uint64 titleId)
@@ -247,7 +247,7 @@ void LatteShaderCache_Load()
247247
else if (g_renderer->GetType() == RendererAPI::OpenGL)
248248
RendererShaderGL::ShaderCacheLoading_begin(cacheTitleId);
249249
else if (g_renderer->GetType() == RendererAPI::Metal)
250-
RendererShaderMtl::ShaderCacheLoading_begin(cacheTitleId);
250+
MetalPipelineCache::ShaderCacheLoading_begin(cacheTitleId);
251251
// get cache file name
252252
const auto pathGeneric = ActiveSettings::GetCachePath("shaderCache/transferable/{:016x}_shaders.bin", cacheTitleId);
253253
const auto pathGenericPre1_25_0 = ActiveSettings::GetCachePath("shaderCache/transferable/{:016x}.bin", cacheTitleId); // before 1.25.0
@@ -780,7 +780,7 @@ void LatteShaderCache_Close()
780780
else if (g_renderer->GetType() == RendererAPI::OpenGL)
781781
RendererShaderGL::ShaderCacheLoading_Close();
782782
else if (g_renderer->GetType() == RendererAPI::Metal)
783-
RendererShaderMtl::ShaderCacheLoading_Close();
783+
MetalPipelineCache::ShaderCacheLoading_Close();
784784

785785
// if Vulkan then also close pipeline cache
786786
if (g_renderer->GetType() == RendererAPI::Vulkan)

src/Cafe/HW/Latte/Renderer/Metal/MetalPipelineCache.cpp

Lines changed: 124 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,37 @@
11
#include "Cafe/HW/Latte/Renderer/Metal/MetalCommon.h"
22
#include "Cafe/HW/Latte/Renderer/Metal/MetalPipelineCache.h"
33
#include "Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h"
4+
#include "Foundation/NSObject.hpp"
45
#include "HW/Latte/Renderer/Metal/CachedFBOMtl.h"
56
#include "HW/Latte/Renderer/Metal/LatteToMtl.h"
67
#include "HW/Latte/Renderer/Metal/RendererShaderMtl.h"
78
#include "HW/Latte/Renderer/Metal/LatteTextureViewMtl.h"
89

910
#include "HW/Latte/Core/FetchShader.h"
1011
#include "HW/Latte/ISA/RegDefines.h"
12+
#include "config/ActiveSettings.h"
13+
14+
#define INVALID_TITLE_ID 0xFFFFFFFFFFFFFFFF
15+
16+
uint64 s_cacheTitleId = INVALID_TITLE_ID;
17+
18+
extern std::atomic_int g_compiled_shaders_total;
19+
extern std::atomic_int g_compiled_shaders_async;
20+
21+
void MetalPipelineCache::ShaderCacheLoading_begin(uint64 cacheTitleId)
22+
{
23+
s_cacheTitleId = cacheTitleId;
24+
}
25+
26+
void MetalPipelineCache::ShaderCacheLoading_end()
27+
{
28+
}
29+
30+
void MetalPipelineCache::ShaderCacheLoading_Close()
31+
{
32+
g_compiled_shaders_total = 0;
33+
g_compiled_shaders_async = 0;
34+
}
1135

1236
MetalPipelineCache::~MetalPipelineCache()
1337
{
@@ -16,6 +40,17 @@ MetalPipelineCache::~MetalPipelineCache()
1640
pair.second->release();
1741
}
1842
m_pipelineCache.clear();
43+
44+
NS::Error* error = nullptr;
45+
m_binaryArchive->serializeToURL(m_binaryArchiveURL, &error);
46+
if (error)
47+
{
48+
debug_printf("failed to serialize binary archive: %s\n", error->localizedDescription()->utf8String());
49+
error->release();
50+
}
51+
m_binaryArchive->release();
52+
53+
m_binaryArchiveURL->release();
1954
}
2055

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

154-
NS::Error* error = nullptr;
155-
pipeline = m_mtlr->GetDevice()->newRenderPipelineState(desc, &error);
156-
desc->release();
157-
vertexDescriptor->release();
189+
LoadBinary(desc);
190+
191+
NS::Error* error = nullptr;
192+
pipeline = m_mtlr->GetDevice()->newRenderPipelineState(desc, MTL::PipelineOptionFailOnBinaryArchiveMiss, nullptr, &error);
193+
194+
//static uint32 oldPipelineCount = 0;
195+
//static uint32 newPipelineCount = 0;
196+
197+
// Pipeline wasn't found in the binary archive, we need to compile it
158198
if (error)
159199
{
160-
debug_printf("error creating render pipeline state: %s\n", error->localizedDescription()->utf8String());
161-
error->release();
162-
return nullptr;
200+
desc->setBinaryArchives(nullptr);
201+
202+
error->release();
203+
error = nullptr;
204+
pipeline = m_mtlr->GetDevice()->newRenderPipelineState(desc, &error);
205+
if (error)
206+
{
207+
debug_printf("error creating render pipeline state: %s\n", error->localizedDescription()->utf8String());
208+
error->release();
209+
}
210+
else
211+
{
212+
SaveBinary(desc);
213+
}
214+
215+
//newPipelineCount++;
163216
}
217+
//else
218+
//{
219+
// oldPipelineCount++;
220+
//}
221+
//debug_printf("%u pipelines were found in the binary archive, %u new were created\n", oldPipelineCount, newPipelineCount);
222+
desc->release();
223+
vertexDescriptor->release();
164224

165225
return pipeline;
166226
}
@@ -238,3 +298,60 @@ uint64 MetalPipelineCache::CalculatePipelineHash(const LatteFetchShader* fetchSh
238298

239299
return stateHash;
240300
}
301+
302+
void MetalPipelineCache::TryLoadBinaryArchive()
303+
{
304+
if (m_binaryArchive || s_cacheTitleId == INVALID_TITLE_ID)
305+
return;
306+
307+
const std::string cacheFilename = fmt::format("{:016x}_mtl_pipelines.bin", s_cacheTitleId);
308+
const fs::path cachePath = ActiveSettings::GetCachePath("shaderCache/precompiled/{}", cacheFilename);
309+
m_binaryArchiveURL = NS::URL::fileURLWithPath(NS::String::string((const char*)cachePath.generic_u8string().c_str(), NS::ASCIIStringEncoding));
310+
311+
MTL::BinaryArchiveDescriptor* desc = MTL::BinaryArchiveDescriptor::alloc()->init();
312+
desc->setUrl(m_binaryArchiveURL);
313+
314+
NS::Error* error = nullptr;
315+
m_binaryArchive = m_mtlr->GetDevice()->newBinaryArchive(desc, &error);
316+
if (error)
317+
{
318+
desc->setUrl(nullptr);
319+
320+
error->release();
321+
error = nullptr;
322+
m_binaryArchive = m_mtlr->GetDevice()->newBinaryArchive(desc, &error);
323+
if (error)
324+
{
325+
debug_printf("failed to create binary archive: %s\n", error->localizedDescription()->utf8String());
326+
error->release();
327+
}
328+
}
329+
desc->release();
330+
}
331+
332+
void MetalPipelineCache::LoadBinary(MTL::RenderPipelineDescriptor* desc)
333+
{
334+
TryLoadBinaryArchive();
335+
336+
if (!m_binaryArchive)
337+
return;
338+
339+
NS::Object* binArchives[] = {m_binaryArchive};
340+
auto binaryArchives = NS::Array::alloc()->init(binArchives, 1);
341+
desc->setBinaryArchives(binaryArchives);
342+
binaryArchives->release();
343+
}
344+
345+
void MetalPipelineCache::SaveBinary(MTL::RenderPipelineDescriptor* desc)
346+
{
347+
if (!m_binaryArchive)
348+
return;
349+
350+
NS::Error* error = nullptr;
351+
m_binaryArchive->addRenderPipelineFunctions(desc, &error);
352+
if (error)
353+
{
354+
debug_printf("error saving render pipeline functions: %s\n", error->localizedDescription()->utf8String());
355+
error->release();
356+
}
357+
}

src/Cafe/HW/Latte/Renderer/Metal/MetalPipelineCache.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88
class MetalPipelineCache
99
{
1010
public:
11+
static void ShaderCacheLoading_begin(uint64 cacheTitleId);
12+
static void ShaderCacheLoading_end();
13+
static void ShaderCacheLoading_Close();
14+
1115
MetalPipelineCache(class MetalRenderer* metalRenderer) : m_mtlr{metalRenderer} {}
1216
~MetalPipelineCache();
1317

@@ -18,5 +22,14 @@ class MetalPipelineCache
1822

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

25+
NS::URL* m_binaryArchiveURL;
26+
MTL::BinaryArchive* m_binaryArchive;
27+
2128
uint64 CalculatePipelineHash(const LatteFetchShader* fetchShader, const LatteDecompilerShader* vertexShader, const LatteDecompilerShader* pixelShader, class CachedFBOMtl* activeFBO, const LatteContextRegister& lcr);
29+
30+
void TryLoadBinaryArchive();
31+
32+
void LoadBinary(MTL::RenderPipelineDescriptor* desc);
33+
34+
void SaveBinary(MTL::RenderPipelineDescriptor* desc);
2235
};

src/Cafe/HW/Latte/Renderer/Metal/RendererShaderMtl.cpp

Lines changed: 3 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,18 @@
22
#include "Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h"
33
#include "Cafe/HW/Latte/Renderer/Metal/LatteToMtl.h"
44
#include "Cafe/HW/Latte/Renderer/Metal/MetalCommon.h"
5-
#include "Cemu/FileCache/FileCache.h"
6-
#include "config/ActiveSettings.h"
5+
//#include "Cemu/FileCache/FileCache.h"
6+
//#include "config/ActiveSettings.h"
77

88
#include "Cemu/Logging/CemuLogging.h"
99
#include "Common/precompiled.h"
1010

11-
bool s_isLoadingShadersMtl{ false };
12-
class FileCache* s_mslCache{nullptr};
13-
1411
extern std::atomic_int g_compiled_shaders_total;
1512
extern std::atomic_int g_compiled_shaders_async;
1613

1714
RendererShaderMtl::RendererShaderMtl(MetalRenderer* mtlRenderer, ShaderType type, uint64 baseHash, uint64 auxHash, bool isGameShader, bool isGfxPackShader, const std::string& mslCode)
1815
: RendererShader(type, baseHash, auxHash, isGameShader, isGfxPackShader), m_mtlr{mtlRenderer}
1916
{
20-
if (LoadBinary())
21-
return;
22-
2317
if (m_type == ShaderType::kFragment)
2418
{
2519
// Fragment functions are compiled just-in-time
@@ -30,12 +24,8 @@ RendererShaderMtl::RendererShaderMtl(MetalRenderer* mtlRenderer, ShaderType type
3024
Compile(mslCode);
3125
}
3226

33-
// Store the compiled shader in the cache
34-
StoreBinary();
35-
3627
// Count shader compilation
37-
if (!s_isLoadingShadersMtl)
38-
g_compiled_shaders_total++;
28+
g_compiled_shaders_total++;
3929
}
4030

4131
RendererShaderMtl::~RendererShaderMtl()
@@ -85,33 +75,6 @@ void RendererShaderMtl::CompileFragmentFunction(CachedFBOMtl* activeFBO)
8575
Compile(fullCode);
8676
}
8777

88-
void RendererShaderMtl::ShaderCacheLoading_begin(uint64 cacheTitleId)
89-
{
90-
if (s_mslCache)
91-
{
92-
delete s_mslCache;
93-
}
94-
uint32 spirvCacheMagic = GeneratePrecompiledCacheId();
95-
const std::string cacheFilename = fmt::format("{:016x}_msl.bin", cacheTitleId);
96-
const fs::path cachePath = ActiveSettings::GetCachePath("shaderCache/precompiled/{}", cacheFilename);
97-
s_mslCache = FileCache::Open(cachePath, true, spirvCacheMagic);
98-
if (!s_mslCache)
99-
cemuLog_log(LogType::Force, "Unable to open MSL cache {}", cacheFilename);
100-
s_isLoadingShadersMtl = true;
101-
}
102-
103-
void RendererShaderMtl::ShaderCacheLoading_end()
104-
{
105-
s_isLoadingShadersMtl = false;
106-
}
107-
108-
void RendererShaderMtl::ShaderCacheLoading_Close()
109-
{
110-
delete s_mslCache;
111-
g_compiled_shaders_total = 0;
112-
g_compiled_shaders_async = 0;
113-
}
114-
11578
void RendererShaderMtl::Compile(const std::string& mslCode)
11679
{
11780
NS::Error* error = nullptr;
@@ -125,33 +88,3 @@ void RendererShaderMtl::Compile(const std::string& mslCode)
12588
m_function = library->newFunction(NS::String::string("main0", NS::ASCIIStringEncoding));
12689
library->release();
12790
}
128-
129-
bool RendererShaderMtl::LoadBinary()
130-
{
131-
// HACK: since fragment functions are compiled just-in-time, we cannot load them from the cache
132-
if (m_type == ShaderType::kFragment)
133-
return false;
134-
135-
uint64 h1, h2;
136-
GenerateShaderPrecompiledCacheFilename(m_type, m_baseHash, m_auxHash, h1, h2);
137-
if (!s_mslCache->GetFile({h1, h2 }, m_binary))
138-
return false;
139-
140-
// TODO: implement
141-
return false;
142-
143-
return true;
144-
}
145-
146-
void RendererShaderMtl::StoreBinary()
147-
{
148-
if (m_binary.size() == 0)
149-
{
150-
// TODO: retrieve the binary from the function
151-
return;
152-
}
153-
154-
uint64 h1, h2;
155-
GenerateShaderPrecompiledCacheFilename(m_type, m_baseHash, m_auxHash, h1, h2);
156-
s_mslCache->AddFileAsync({h1, h2 }, m_binary.data(), m_binary.size());
157-
}

0 commit comments

Comments
 (0)