2
2
#include " Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h"
3
3
#include " Cafe/HW/Latte/Renderer/Metal/LatteToMtl.h"
4
4
#include " Cafe/HW/Latte/Renderer/Metal/MetalCommon.h"
5
+ #include " Cemu/FileCache/FileCache.h"
6
+ #include " config/ActiveSettings.h"
5
7
6
8
#include " Cemu/Logging/CemuLogging.h"
7
9
#include " Common/precompiled.h"
8
10
11
+ bool s_isLoadingShadersMtl{ false };
12
+ class FileCache * s_mslCache{nullptr };
13
+
14
+ extern std::atomic_int g_compiled_shaders_total;
15
+ extern std::atomic_int g_compiled_shaders_async;
16
+
9
17
RendererShaderMtl::RendererShaderMtl (MetalRenderer* mtlRenderer, ShaderType type, uint64 baseHash, uint64 auxHash, bool isGameShader, bool isGfxPackShader, const std::string& mslCode)
10
18
: RendererShader(type, baseHash, auxHash, isGameShader, isGfxPackShader), m_mtlr{mtlRenderer}
11
19
{
12
- // Fragment functions are compiled just-in-time
20
+ if (LoadBinary ())
21
+ return ;
22
+
13
23
if (m_type == ShaderType::kFragment )
14
24
{
25
+ // Fragment functions are compiled just-in-time
15
26
m_mslCode = mslCode;
16
27
}
17
28
else
18
29
{
19
30
Compile (mslCode);
20
31
}
32
+
33
+ // Store the compiled shader in the cache
34
+ StoreBinary ();
35
+
36
+ // Count shader compilation
37
+ if (!s_isLoadingShadersMtl)
38
+ g_compiled_shaders_total++;
21
39
}
22
40
23
41
RendererShaderMtl::~RendererShaderMtl ()
@@ -69,17 +87,29 @@ void RendererShaderMtl::CompileFragmentFunction(CachedFBOMtl* activeFBO)
69
87
70
88
void RendererShaderMtl::ShaderCacheLoading_begin (uint64 cacheTitleId)
71
89
{
72
- cemuLog_log (LogType::MetalLogging, " RendererShaderMtl::ShaderCacheLoading_begin not implemented!" );
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 ;
73
101
}
74
102
75
103
void RendererShaderMtl::ShaderCacheLoading_end ()
76
104
{
77
- cemuLog_log (LogType::MetalLogging, " RendererShaderMtl::ShaderCacheLoading_end not implemented! " ) ;
105
+ s_isLoadingShadersMtl = false ;
78
106
}
79
107
80
108
void RendererShaderMtl::ShaderCacheLoading_Close ()
81
109
{
82
- cemuLog_log (LogType::MetalLogging, " RendererShaderMtl::ShaderCacheLoading_Close not implemented!" );
110
+ delete s_mslCache;
111
+ g_compiled_shaders_total = 0 ;
112
+ g_compiled_shaders_async = 0 ;
83
113
}
84
114
85
115
void RendererShaderMtl::Compile (const std::string& mslCode)
@@ -95,3 +125,33 @@ void RendererShaderMtl::Compile(const std::string& mslCode)
95
125
m_function = library->newFunction (NS::String::string (" main0" , NS::ASCIIStringEncoding));
96
126
library->release ();
97
127
}
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