1 // Copyright 2018 Dolphin Emulator Project
2 // Licensed under GPLv2+
3 // Refer to the license.txt file included.
4 
5 #include "VideoCommon/ShaderCache.h"
6 
7 #include "Common/Assert.h"
8 #include "Common/FileUtil.h"
9 #include "Common/MsgHandler.h"
10 #include "Core/ConfigManager.h"
11 
12 #include "VideoCommon/FramebufferManager.h"
13 #include "VideoCommon/FramebufferShaderGen.h"
14 #include "VideoCommon/RenderBase.h"
15 #include "VideoCommon/Statistics.h"
16 #include "VideoCommon/VertexLoaderManager.h"
17 #include "VideoCommon/VertexManagerBase.h"
18 #include "VideoCommon/VideoCommon.h"
19 #include "VideoCommon/VideoConfig.h"
20 
21 #include <imgui.h>
22 
23 std::unique_ptr<VideoCommon::ShaderCache> g_shader_cache;
24 
25 namespace VideoCommon
26 {
ShaderCache()27 ShaderCache::ShaderCache() : m_api_type{APIType::Nothing}
28 {
29 }
30 
~ShaderCache()31 ShaderCache::~ShaderCache()
32 {
33   ClearCaches();
34 }
35 
Initialize()36 bool ShaderCache::Initialize()
37 {
38   m_api_type = g_ActiveConfig.backend_info.api_type;
39   m_host_config = ShaderHostConfig::GetCurrent();
40 
41   if (!CompileSharedPipelines())
42     return false;
43 
44   m_async_shader_compiler = g_renderer->CreateAsyncShaderCompiler();
45   return true;
46 }
47 
InitializeShaderCache()48 void ShaderCache::InitializeShaderCache()
49 {
50   m_async_shader_compiler->ResizeWorkerThreads(g_ActiveConfig.GetShaderPrecompilerThreads());
51 
52   // Load shader and UID caches.
53   if (g_ActiveConfig.bShaderCache && m_api_type != APIType::Nothing)
54   {
55     LoadCaches();
56     LoadPipelineUIDCache();
57   }
58 
59   // Queue ubershader precompiling if required.
60   if (g_ActiveConfig.UsingUberShaders())
61     QueueUberShaderPipelines();
62 
63   // Compile all known UIDs.
64   CompileMissingPipelines();
65   if (g_ActiveConfig.bWaitForShadersBeforeStarting)
66     WaitForAsyncCompiler();
67 
68   // Switch to the runtime shader compiler thread configuration.
69   m_async_shader_compiler->ResizeWorkerThreads(g_ActiveConfig.GetShaderCompilerThreads());
70 }
71 
Reload()72 void ShaderCache::Reload()
73 {
74   WaitForAsyncCompiler();
75   ClosePipelineUIDCache();
76   ClearCaches();
77 
78   if (!CompileSharedPipelines())
79     PanicAlert("Failed to compile shared pipelines after reload.");
80 
81   if (g_ActiveConfig.bShaderCache)
82     LoadCaches();
83 
84   // Switch to the precompiling shader configuration while we rebuild.
85   m_async_shader_compiler->ResizeWorkerThreads(g_ActiveConfig.GetShaderPrecompilerThreads());
86 
87   // We don't need to explicitly recompile the individual ubershaders here, as the pipelines
88   // UIDs are still be in the map. Therefore, when these are rebuilt, the shaders will also
89   // be recompiled.
90   CompileMissingPipelines();
91   if (g_ActiveConfig.bWaitForShadersBeforeStarting)
92     WaitForAsyncCompiler();
93   m_async_shader_compiler->ResizeWorkerThreads(g_ActiveConfig.GetShaderCompilerThreads());
94 }
95 
RetrieveAsyncShaders()96 void ShaderCache::RetrieveAsyncShaders()
97 {
98   m_async_shader_compiler->RetrieveWorkItems();
99 }
100 
Shutdown()101 void ShaderCache::Shutdown()
102 {
103   // This may leave shaders uncommitted to the cache, but it's better than blocking shutdown
104   // until everything has finished compiling.
105   if (m_async_shader_compiler)
106     m_async_shader_compiler->StopWorkerThreads();
107 
108   ClosePipelineUIDCache();
109 }
110 
GetPipelineForUid(const GXPipelineUid & uid)111 const AbstractPipeline* ShaderCache::GetPipelineForUid(const GXPipelineUid& uid)
112 {
113   auto it = m_gx_pipeline_cache.find(uid);
114   if (it != m_gx_pipeline_cache.end() && !it->second.second)
115     return it->second.first.get();
116 
117   const bool exists_in_cache = it != m_gx_pipeline_cache.end();
118   std::unique_ptr<AbstractPipeline> pipeline;
119   std::optional<AbstractPipelineConfig> pipeline_config = GetGXPipelineConfig(uid);
120   if (pipeline_config)
121     pipeline = g_renderer->CreatePipeline(*pipeline_config);
122   if (g_ActiveConfig.bShaderCache && !exists_in_cache)
123     AppendGXPipelineUID(uid);
124   return InsertGXPipeline(uid, std::move(pipeline));
125 }
126 
GetPipelineForUidAsync(const GXPipelineUid & uid)127 std::optional<const AbstractPipeline*> ShaderCache::GetPipelineForUidAsync(const GXPipelineUid& uid)
128 {
129   auto it = m_gx_pipeline_cache.find(uid);
130   if (it != m_gx_pipeline_cache.end())
131   {
132     // .second is the pending flag, i.e. compiling in the background.
133     if (!it->second.second)
134       return it->second.first.get();
135     else
136       return {};
137   }
138 
139   AppendGXPipelineUID(uid);
140   QueuePipelineCompile(uid, COMPILE_PRIORITY_ONDEMAND_PIPELINE);
141   return {};
142 }
143 
GetUberPipelineForUid(const GXUberPipelineUid & uid)144 const AbstractPipeline* ShaderCache::GetUberPipelineForUid(const GXUberPipelineUid& uid)
145 {
146   auto it = m_gx_uber_pipeline_cache.find(uid);
147   if (it != m_gx_uber_pipeline_cache.end() && !it->second.second)
148     return it->second.first.get();
149 
150   std::unique_ptr<AbstractPipeline> pipeline;
151   std::optional<AbstractPipelineConfig> pipeline_config = GetGXPipelineConfig(uid);
152   if (pipeline_config)
153     pipeline = g_renderer->CreatePipeline(*pipeline_config);
154   return InsertGXUberPipeline(uid, std::move(pipeline));
155 }
156 
WaitForAsyncCompiler()157 void ShaderCache::WaitForAsyncCompiler()
158 {
159   while (m_async_shader_compiler->HasPendingWork() || m_async_shader_compiler->HasCompletedWork())
160   {
161     m_async_shader_compiler->WaitUntilCompletion([](size_t completed, size_t total) {
162       g_renderer->BeginUIFrame();
163 
164       const float scale = ImGui::GetIO().DisplayFramebufferScale.x;
165 
166       ImGui::SetNextWindowSize(ImVec2(400.0f * scale, 50.0f * scale), ImGuiCond_Always);
167       ImGui::SetNextWindowPosCenter(ImGuiCond_Always);
168       if (ImGui::Begin(Common::GetStringT("Compiling Shaders").c_str(), nullptr,
169                        ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoInputs |
170                            ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoSavedSettings |
171                            ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoNav |
172                            ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoFocusOnAppearing))
173       {
174         ImGui::Text("Compiling shaders: %zu/%zu", completed, total);
175         ImGui::ProgressBar(static_cast<float>(completed) /
176                                static_cast<float>(std::max(total, static_cast<size_t>(1))),
177                            ImVec2(-1.0f, 0.0f), "");
178       }
179       ImGui::End();
180 
181       g_renderer->EndUIFrame();
182     });
183     m_async_shader_compiler->RetrieveWorkItems();
184   }
185 }
186 
187 template <typename SerializedUidType, typename UidType>
SerializePipelineUid(const UidType & uid,SerializedUidType & serialized_uid)188 static void SerializePipelineUid(const UidType& uid, SerializedUidType& serialized_uid)
189 {
190   // Convert to disk format. Ensure all padding bytes are zero.
191   std::memset(&serialized_uid, 0, sizeof(serialized_uid));
192   serialized_uid.vertex_decl = uid.vertex_format->GetVertexDeclaration();
193   serialized_uid.vs_uid = uid.vs_uid;
194   serialized_uid.gs_uid = uid.gs_uid;
195   serialized_uid.ps_uid = uid.ps_uid;
196   serialized_uid.rasterization_state_bits = uid.rasterization_state.hex;
197   serialized_uid.depth_state_bits = uid.depth_state.hex;
198   serialized_uid.blending_state_bits = uid.blending_state.hex;
199 }
200 
201 template <typename UidType, typename SerializedUidType>
UnserializePipelineUid(const SerializedUidType & uid,UidType & real_uid)202 static void UnserializePipelineUid(const SerializedUidType& uid, UidType& real_uid)
203 {
204   real_uid.vertex_format = VertexLoaderManager::GetOrCreateMatchingFormat(uid.vertex_decl);
205   real_uid.vs_uid = uid.vs_uid;
206   real_uid.gs_uid = uid.gs_uid;
207   real_uid.ps_uid = uid.ps_uid;
208   real_uid.rasterization_state.hex = uid.rasterization_state_bits;
209   real_uid.depth_state.hex = uid.depth_state_bits;
210   real_uid.blending_state.hex = uid.blending_state_bits;
211 }
212 
213 template <ShaderStage stage, typename K, typename T>
LoadShaderCache(T & cache,APIType api_type,const char * type,bool include_gameid)214 void ShaderCache::LoadShaderCache(T& cache, APIType api_type, const char* type, bool include_gameid)
215 {
216   class CacheReader : public LinearDiskCacheReader<K, u8>
217   {
218   public:
219     CacheReader(T& cache_) : cache(cache_) {}
220     void Read(const K& key, const u8* value, u32 value_size)
221     {
222       auto shader = g_renderer->CreateShaderFromBinary(stage, value, value_size);
223       if (shader)
224       {
225         auto& entry = cache.shader_map[key];
226         entry.shader = std::move(shader);
227         entry.pending = false;
228 
229         switch (stage)
230         {
231         case ShaderStage::Vertex:
232           INCSTAT(g_stats.num_vertex_shaders_created);
233           INCSTAT(g_stats.num_vertex_shaders_alive);
234           break;
235         case ShaderStage::Pixel:
236           INCSTAT(g_stats.num_pixel_shaders_created);
237           INCSTAT(g_stats.num_pixel_shaders_alive);
238           break;
239         default:
240           break;
241         }
242       }
243     }
244 
245   private:
246     T& cache;
247   };
248 
249   std::string filename = GetDiskShaderCacheFileName(api_type, type, include_gameid, true);
250   CacheReader reader(cache);
251   u32 count = cache.disk_cache.OpenAndRead(filename, reader);
252   INFO_LOG(VIDEO, "Loaded %u cached shaders from %s", count, filename.c_str());
253 }
254 
255 template <typename T>
ClearShaderCache(T & cache)256 void ShaderCache::ClearShaderCache(T& cache)
257 {
258   cache.disk_cache.Sync();
259   cache.disk_cache.Close();
260   cache.shader_map.clear();
261 }
262 
263 template <typename KeyType, typename DiskKeyType, typename T>
LoadPipelineCache(T & cache,LinearDiskCache<DiskKeyType,u8> & disk_cache,APIType api_type,const char * type,bool include_gameid)264 void ShaderCache::LoadPipelineCache(T& cache, LinearDiskCache<DiskKeyType, u8>& disk_cache,
265                                     APIType api_type, const char* type, bool include_gameid)
266 {
267   class CacheReader : public LinearDiskCacheReader<DiskKeyType, u8>
268   {
269   public:
270     CacheReader(ShaderCache* this_ptr_, T& cache_) : this_ptr(this_ptr_), cache(cache_) {}
271     bool AnyFailed() const { return failed; }
272     void Read(const DiskKeyType& key, const u8* value, u32 value_size)
273     {
274       KeyType real_uid;
275       UnserializePipelineUid(key, real_uid);
276 
277       // Skip those which are already compiled.
278       if (failed || cache.find(real_uid) != cache.end())
279         return;
280 
281       auto config = this_ptr->GetGXPipelineConfig(real_uid);
282       if (!config)
283         return;
284 
285       auto pipeline = g_renderer->CreatePipeline(*config, value, value_size);
286       if (!pipeline)
287       {
288         // If any of the pipelines fail to create, consider the cache stale.
289         failed = true;
290         return;
291       }
292 
293       auto& entry = cache[real_uid];
294       entry.first = std::move(pipeline);
295       entry.second = false;
296     }
297 
298   private:
299     ShaderCache* this_ptr;
300     T& cache;
301     bool failed = false;
302   };
303 
304   std::string filename = GetDiskShaderCacheFileName(api_type, type, include_gameid, true);
305   CacheReader reader(this, cache);
306   u32 count = disk_cache.OpenAndRead(filename, reader);
307   INFO_LOG(VIDEO, "Loaded %u cached pipelines from %s", count, filename.c_str());
308 
309   // If any of the pipelines in the cache failed to create, it's likely because of a change of
310   // driver version, or system configuration. In this case, when the UID cache picks up the pipeline
311   // later on, we'll write a duplicate entry to the pipeline cache. There's also no point in keeping
312   // the old cache data around, so discard and recreate the disk cache.
313   if (reader.AnyFailed())
314   {
315     WARN_LOG(VIDEO, "Failed to load one or more pipelines from cache '%s'. Discarding.",
316              filename.c_str());
317     disk_cache.Close();
318     File::Delete(filename);
319     disk_cache.OpenAndRead(filename, reader);
320   }
321 }
322 
323 template <typename T, typename Y>
ClearPipelineCache(T & cache,Y & disk_cache)324 void ShaderCache::ClearPipelineCache(T& cache, Y& disk_cache)
325 {
326   disk_cache.Sync();
327   disk_cache.Close();
328 
329   // Set the pending flag to false, and destroy the pipeline.
330   for (auto& it : cache)
331   {
332     it.second.first.reset();
333     it.second.second = false;
334   }
335 }
336 
LoadCaches()337 void ShaderCache::LoadCaches()
338 {
339   // Ubershader caches, if present.
340   if (g_ActiveConfig.backend_info.bSupportsShaderBinaries)
341   {
342     LoadShaderCache<ShaderStage::Vertex, UberShader::VertexShaderUid>(m_uber_vs_cache, m_api_type,
343                                                                       "uber-vs", false);
344     LoadShaderCache<ShaderStage::Pixel, UberShader::PixelShaderUid>(m_uber_ps_cache, m_api_type,
345                                                                     "uber-ps", false);
346 
347     // We also share geometry shaders, as there aren't many variants.
348     if (m_host_config.backend_geometry_shaders)
349       LoadShaderCache<ShaderStage::Geometry, GeometryShaderUid>(m_gs_cache, m_api_type, "gs",
350                                                                 false);
351 
352     // Specialized shaders, gameid-specific.
353     LoadShaderCache<ShaderStage::Vertex, VertexShaderUid>(m_vs_cache, m_api_type, "specialized-vs",
354                                                           true);
355     LoadShaderCache<ShaderStage::Pixel, PixelShaderUid>(m_ps_cache, m_api_type, "specialized-ps",
356                                                         true);
357   }
358 
359   if (g_ActiveConfig.backend_info.bSupportsPipelineCacheData)
360   {
361     LoadPipelineCache<GXPipelineUid, SerializedGXPipelineUid>(
362         m_gx_pipeline_cache, m_gx_pipeline_disk_cache, m_api_type, "specialized-pipeline", true);
363     LoadPipelineCache<GXUberPipelineUid, SerializedGXUberPipelineUid>(
364         m_gx_uber_pipeline_cache, m_gx_uber_pipeline_disk_cache, m_api_type, "uber-pipeline",
365         false);
366   }
367 }
368 
ClearCaches()369 void ShaderCache::ClearCaches()
370 {
371   ClearPipelineCache(m_gx_pipeline_cache, m_gx_pipeline_disk_cache);
372   ClearShaderCache(m_vs_cache);
373   ClearShaderCache(m_gs_cache);
374   ClearShaderCache(m_ps_cache);
375 
376   ClearPipelineCache(m_gx_uber_pipeline_cache, m_gx_uber_pipeline_disk_cache);
377   ClearShaderCache(m_uber_vs_cache);
378   ClearShaderCache(m_uber_ps_cache);
379 
380   m_screen_quad_vertex_shader.reset();
381   m_texture_copy_vertex_shader.reset();
382   m_efb_copy_vertex_shader.reset();
383   m_texcoord_geometry_shader.reset();
384   m_color_geometry_shader.reset();
385   m_texture_copy_pixel_shader.reset();
386   m_color_pixel_shader.reset();
387 
388   m_efb_copy_to_vram_pipelines.clear();
389   m_efb_copy_to_ram_pipelines.clear();
390   m_copy_rgba8_pipeline.reset();
391   m_rgba8_stereo_copy_pipeline.reset();
392   for (auto& pipeline : m_palette_conversion_pipelines)
393     pipeline.reset();
394   m_texture_reinterpret_pipelines.clear();
395   m_texture_decoding_shaders.clear();
396 
397   SETSTAT(g_stats.num_pixel_shaders_created, 0);
398   SETSTAT(g_stats.num_pixel_shaders_alive, 0);
399   SETSTAT(g_stats.num_vertex_shaders_created, 0);
400   SETSTAT(g_stats.num_vertex_shaders_alive, 0);
401 }
402 
CompileMissingPipelines()403 void ShaderCache::CompileMissingPipelines()
404 {
405   // Queue all uids with a null pipeline for compilation.
406   for (auto& it : m_gx_pipeline_cache)
407   {
408     if (!it.second.first)
409       QueuePipelineCompile(it.first, COMPILE_PRIORITY_SHADERCACHE_PIPELINE);
410   }
411   for (auto& it : m_gx_uber_pipeline_cache)
412   {
413     if (!it.second.first)
414       QueueUberPipelineCompile(it.first, COMPILE_PRIORITY_UBERSHADER_PIPELINE);
415   }
416 }
417 
CompileVertexShader(const VertexShaderUid & uid) const418 std::unique_ptr<AbstractShader> ShaderCache::CompileVertexShader(const VertexShaderUid& uid) const
419 {
420   const ShaderCode source_code =
421       GenerateVertexShaderCode(m_api_type, m_host_config, uid.GetUidData());
422   return g_renderer->CreateShaderFromSource(ShaderStage::Vertex, source_code.GetBuffer());
423 }
424 
425 std::unique_ptr<AbstractShader>
CompileVertexUberShader(const UberShader::VertexShaderUid & uid) const426 ShaderCache::CompileVertexUberShader(const UberShader::VertexShaderUid& uid) const
427 {
428   const ShaderCode source_code =
429       UberShader::GenVertexShader(m_api_type, m_host_config, uid.GetUidData());
430   return g_renderer->CreateShaderFromSource(ShaderStage::Vertex, source_code.GetBuffer());
431 }
432 
CompilePixelShader(const PixelShaderUid & uid) const433 std::unique_ptr<AbstractShader> ShaderCache::CompilePixelShader(const PixelShaderUid& uid) const
434 {
435   const ShaderCode source_code =
436       GeneratePixelShaderCode(m_api_type, m_host_config, uid.GetUidData());
437   return g_renderer->CreateShaderFromSource(ShaderStage::Pixel, source_code.GetBuffer());
438 }
439 
440 std::unique_ptr<AbstractShader>
CompilePixelUberShader(const UberShader::PixelShaderUid & uid) const441 ShaderCache::CompilePixelUberShader(const UberShader::PixelShaderUid& uid) const
442 {
443   const ShaderCode source_code =
444       UberShader::GenPixelShader(m_api_type, m_host_config, uid.GetUidData());
445   return g_renderer->CreateShaderFromSource(ShaderStage::Pixel, source_code.GetBuffer());
446 }
447 
InsertVertexShader(const VertexShaderUid & uid,std::unique_ptr<AbstractShader> shader)448 const AbstractShader* ShaderCache::InsertVertexShader(const VertexShaderUid& uid,
449                                                       std::unique_ptr<AbstractShader> shader)
450 {
451   auto& entry = m_vs_cache.shader_map[uid];
452   entry.pending = false;
453 
454   if (shader && !entry.shader)
455   {
456     if (g_ActiveConfig.bShaderCache && g_ActiveConfig.backend_info.bSupportsShaderBinaries)
457     {
458       auto binary = shader->GetBinary();
459       if (!binary.empty())
460         m_vs_cache.disk_cache.Append(uid, binary.data(), static_cast<u32>(binary.size()));
461     }
462     INCSTAT(g_stats.num_vertex_shaders_created);
463     INCSTAT(g_stats.num_vertex_shaders_alive);
464     entry.shader = std::move(shader);
465   }
466 
467   return entry.shader.get();
468 }
469 
InsertVertexUberShader(const UberShader::VertexShaderUid & uid,std::unique_ptr<AbstractShader> shader)470 const AbstractShader* ShaderCache::InsertVertexUberShader(const UberShader::VertexShaderUid& uid,
471                                                           std::unique_ptr<AbstractShader> shader)
472 {
473   auto& entry = m_uber_vs_cache.shader_map[uid];
474   entry.pending = false;
475 
476   if (shader && !entry.shader)
477   {
478     if (g_ActiveConfig.bShaderCache && g_ActiveConfig.backend_info.bSupportsShaderBinaries)
479     {
480       auto binary = shader->GetBinary();
481       if (!binary.empty())
482         m_uber_vs_cache.disk_cache.Append(uid, binary.data(), static_cast<u32>(binary.size()));
483     }
484     INCSTAT(g_stats.num_vertex_shaders_created);
485     INCSTAT(g_stats.num_vertex_shaders_alive);
486     entry.shader = std::move(shader);
487   }
488 
489   return entry.shader.get();
490 }
491 
InsertPixelShader(const PixelShaderUid & uid,std::unique_ptr<AbstractShader> shader)492 const AbstractShader* ShaderCache::InsertPixelShader(const PixelShaderUid& uid,
493                                                      std::unique_ptr<AbstractShader> shader)
494 {
495   auto& entry = m_ps_cache.shader_map[uid];
496   entry.pending = false;
497 
498   if (shader && !entry.shader)
499   {
500     if (g_ActiveConfig.bShaderCache && g_ActiveConfig.backend_info.bSupportsShaderBinaries)
501     {
502       auto binary = shader->GetBinary();
503       if (!binary.empty())
504         m_ps_cache.disk_cache.Append(uid, binary.data(), static_cast<u32>(binary.size()));
505     }
506     INCSTAT(g_stats.num_pixel_shaders_created);
507     INCSTAT(g_stats.num_pixel_shaders_alive);
508     entry.shader = std::move(shader);
509   }
510 
511   return entry.shader.get();
512 }
513 
InsertPixelUberShader(const UberShader::PixelShaderUid & uid,std::unique_ptr<AbstractShader> shader)514 const AbstractShader* ShaderCache::InsertPixelUberShader(const UberShader::PixelShaderUid& uid,
515                                                          std::unique_ptr<AbstractShader> shader)
516 {
517   auto& entry = m_uber_ps_cache.shader_map[uid];
518   entry.pending = false;
519 
520   if (shader && !entry.shader)
521   {
522     if (g_ActiveConfig.bShaderCache && g_ActiveConfig.backend_info.bSupportsShaderBinaries)
523     {
524       auto binary = shader->GetBinary();
525       if (!binary.empty())
526         m_uber_ps_cache.disk_cache.Append(uid, binary.data(), static_cast<u32>(binary.size()));
527     }
528     INCSTAT(g_stats.num_pixel_shaders_created);
529     INCSTAT(g_stats.num_pixel_shaders_alive);
530     entry.shader = std::move(shader);
531   }
532 
533   return entry.shader.get();
534 }
535 
CreateGeometryShader(const GeometryShaderUid & uid)536 const AbstractShader* ShaderCache::CreateGeometryShader(const GeometryShaderUid& uid)
537 {
538   const ShaderCode source_code =
539       GenerateGeometryShaderCode(m_api_type, m_host_config, uid.GetUidData());
540   std::unique_ptr<AbstractShader> shader =
541       g_renderer->CreateShaderFromSource(ShaderStage::Geometry, source_code.GetBuffer());
542 
543   auto& entry = m_gs_cache.shader_map[uid];
544   entry.pending = false;
545 
546   if (shader && !entry.shader)
547   {
548     if (g_ActiveConfig.bShaderCache && g_ActiveConfig.backend_info.bSupportsShaderBinaries)
549     {
550       auto binary = shader->GetBinary();
551       if (!binary.empty())
552         m_gs_cache.disk_cache.Append(uid, binary.data(), static_cast<u32>(binary.size()));
553     }
554     entry.shader = std::move(shader);
555   }
556 
557   return entry.shader.get();
558 }
559 
NeedsGeometryShader(const GeometryShaderUid & uid) const560 bool ShaderCache::NeedsGeometryShader(const GeometryShaderUid& uid) const
561 {
562   return m_host_config.backend_geometry_shaders && !uid.GetUidData()->IsPassthrough();
563 }
564 
UseGeometryShaderForEFBCopies() const565 bool ShaderCache::UseGeometryShaderForEFBCopies() const
566 {
567   return m_host_config.backend_geometry_shaders && m_host_config.stereo;
568 }
569 
GetGXPipelineConfig(const NativeVertexFormat * vertex_format,const AbstractShader * vertex_shader,const AbstractShader * geometry_shader,const AbstractShader * pixel_shader,const RasterizationState & rasterization_state,const DepthState & depth_state,const BlendingState & blending_state)570 AbstractPipelineConfig ShaderCache::GetGXPipelineConfig(
571     const NativeVertexFormat* vertex_format, const AbstractShader* vertex_shader,
572     const AbstractShader* geometry_shader, const AbstractShader* pixel_shader,
573     const RasterizationState& rasterization_state, const DepthState& depth_state,
574     const BlendingState& blending_state)
575 {
576   AbstractPipelineConfig config = {};
577   config.usage = AbstractPipelineUsage::GX;
578   config.vertex_format = vertex_format;
579   config.vertex_shader = vertex_shader;
580   config.geometry_shader = geometry_shader;
581   config.pixel_shader = pixel_shader;
582   config.rasterization_state = rasterization_state;
583   config.depth_state = depth_state;
584   config.blending_state = blending_state;
585   config.framebuffer_state = g_framebuffer_manager->GetEFBFramebufferState();
586 
587   if (config.blending_state.logicopenable && !g_ActiveConfig.backend_info.bSupportsLogicOp)
588   {
589     WARN_LOG(VIDEO, "Approximating logic op with blending, this will produce incorrect rendering.");
590     config.blending_state.ApproximateLogicOpWithBlending();
591   }
592 
593   return config;
594 }
595 
GetGXPipelineConfig(const GXPipelineUid & config)596 std::optional<AbstractPipelineConfig> ShaderCache::GetGXPipelineConfig(const GXPipelineUid& config)
597 {
598   const AbstractShader* vs;
599   auto vs_iter = m_vs_cache.shader_map.find(config.vs_uid);
600   if (vs_iter != m_vs_cache.shader_map.end() && !vs_iter->second.pending)
601     vs = vs_iter->second.shader.get();
602   else
603     vs = InsertVertexShader(config.vs_uid, CompileVertexShader(config.vs_uid));
604 
605   PixelShaderUid ps_uid = config.ps_uid;
606   ClearUnusedPixelShaderUidBits(m_api_type, m_host_config, &ps_uid);
607 
608   const AbstractShader* ps;
609   auto ps_iter = m_ps_cache.shader_map.find(ps_uid);
610   if (ps_iter != m_ps_cache.shader_map.end() && !ps_iter->second.pending)
611     ps = ps_iter->second.shader.get();
612   else
613     ps = InsertPixelShader(ps_uid, CompilePixelShader(ps_uid));
614 
615   if (!vs || !ps)
616     return {};
617 
618   const AbstractShader* gs = nullptr;
619   if (NeedsGeometryShader(config.gs_uid))
620   {
621     auto gs_iter = m_gs_cache.shader_map.find(config.gs_uid);
622     if (gs_iter != m_gs_cache.shader_map.end() && !gs_iter->second.pending)
623       gs = gs_iter->second.shader.get();
624     else
625       gs = CreateGeometryShader(config.gs_uid);
626     if (!gs)
627       return {};
628   }
629 
630   return GetGXPipelineConfig(config.vertex_format, vs, gs, ps, config.rasterization_state,
631                              config.depth_state, config.blending_state);
632 }
633 
634 std::optional<AbstractPipelineConfig>
GetGXPipelineConfig(const GXUberPipelineUid & config)635 ShaderCache::GetGXPipelineConfig(const GXUberPipelineUid& config)
636 {
637   const AbstractShader* vs;
638   auto vs_iter = m_uber_vs_cache.shader_map.find(config.vs_uid);
639   if (vs_iter != m_uber_vs_cache.shader_map.end() && !vs_iter->second.pending)
640     vs = vs_iter->second.shader.get();
641   else
642     vs = InsertVertexUberShader(config.vs_uid, CompileVertexUberShader(config.vs_uid));
643 
644   UberShader::PixelShaderUid ps_uid = config.ps_uid;
645   UberShader::ClearUnusedPixelShaderUidBits(m_api_type, m_host_config, &ps_uid);
646 
647   const AbstractShader* ps;
648   auto ps_iter = m_uber_ps_cache.shader_map.find(ps_uid);
649   if (ps_iter != m_uber_ps_cache.shader_map.end() && !ps_iter->second.pending)
650     ps = ps_iter->second.shader.get();
651   else
652     ps = InsertPixelUberShader(ps_uid, CompilePixelUberShader(ps_uid));
653 
654   if (!vs || !ps)
655     return {};
656 
657   const AbstractShader* gs = nullptr;
658   if (NeedsGeometryShader(config.gs_uid))
659   {
660     auto gs_iter = m_gs_cache.shader_map.find(config.gs_uid);
661     if (gs_iter != m_gs_cache.shader_map.end() && !gs_iter->second.pending)
662       gs = gs_iter->second.shader.get();
663     else
664       gs = CreateGeometryShader(config.gs_uid);
665     if (!gs)
666       return {};
667   }
668 
669   return GetGXPipelineConfig(config.vertex_format, vs, gs, ps, config.rasterization_state,
670                              config.depth_state, config.blending_state);
671 }
672 
InsertGXPipeline(const GXPipelineUid & config,std::unique_ptr<AbstractPipeline> pipeline)673 const AbstractPipeline* ShaderCache::InsertGXPipeline(const GXPipelineUid& config,
674                                                       std::unique_ptr<AbstractPipeline> pipeline)
675 {
676   auto& entry = m_gx_pipeline_cache[config];
677   entry.second = false;
678   if (!entry.first && pipeline)
679   {
680     entry.first = std::move(pipeline);
681 
682     if (g_ActiveConfig.bShaderCache)
683     {
684       auto cache_data = entry.first->GetCacheData();
685       if (!cache_data.empty())
686       {
687         SerializedGXPipelineUid disk_uid;
688         SerializePipelineUid(config, disk_uid);
689         m_gx_pipeline_disk_cache.Append(disk_uid, cache_data.data(),
690                                         static_cast<u32>(cache_data.size()));
691       }
692     }
693   }
694 
695   return entry.first.get();
696 }
697 
698 const AbstractPipeline*
InsertGXUberPipeline(const GXUberPipelineUid & config,std::unique_ptr<AbstractPipeline> pipeline)699 ShaderCache::InsertGXUberPipeline(const GXUberPipelineUid& config,
700                                   std::unique_ptr<AbstractPipeline> pipeline)
701 {
702   auto& entry = m_gx_uber_pipeline_cache[config];
703   entry.second = false;
704   if (!entry.first && pipeline)
705   {
706     entry.first = std::move(pipeline);
707 
708     if (g_ActiveConfig.bShaderCache)
709     {
710       auto cache_data = entry.first->GetCacheData();
711       if (!cache_data.empty())
712       {
713         SerializedGXUberPipelineUid disk_uid;
714         SerializePipelineUid(config, disk_uid);
715         m_gx_uber_pipeline_disk_cache.Append(disk_uid, cache_data.data(),
716                                              static_cast<u32>(cache_data.size()));
717       }
718     }
719   }
720 
721   return entry.first.get();
722 }
723 
LoadPipelineUIDCache()724 void ShaderCache::LoadPipelineUIDCache()
725 {
726   constexpr u32 CACHE_FILE_MAGIC = 0x44495550;  // PUID
727   constexpr size_t CACHE_HEADER_SIZE = sizeof(u32) + sizeof(u32);
728   std::string filename =
729       File::GetUserPath(D_CACHE_IDX) + SConfig::GetInstance().GetGameID() + ".uidcache";
730   if (m_gx_pipeline_uid_cache_file.Open(filename, "rb+"))
731   {
732     // If an existing case exists, validate the version before reading entries.
733     u32 existing_magic;
734     u32 existing_version;
735     bool uid_file_valid = false;
736     if (m_gx_pipeline_uid_cache_file.ReadBytes(&existing_magic, sizeof(existing_magic)) &&
737         m_gx_pipeline_uid_cache_file.ReadBytes(&existing_version, sizeof(existing_version)) &&
738         existing_magic == CACHE_FILE_MAGIC && existing_version == GX_PIPELINE_UID_VERSION)
739     {
740       // Ensure the expected size matches the actual size of the file. If it doesn't, it means
741       // the cache file may be corrupted, and we should not proceed with loading potentially
742       // garbage or invalid UIDs.
743       const u64 file_size = m_gx_pipeline_uid_cache_file.GetSize();
744       const size_t uid_count =
745           static_cast<size_t>(file_size - CACHE_HEADER_SIZE) / sizeof(SerializedGXPipelineUid);
746       const size_t expected_size = uid_count * sizeof(SerializedGXPipelineUid) + CACHE_HEADER_SIZE;
747       uid_file_valid = file_size == expected_size;
748       if (uid_file_valid)
749       {
750         for (size_t i = 0; i < uid_count; i++)
751         {
752           SerializedGXPipelineUid serialized_uid;
753           if (m_gx_pipeline_uid_cache_file.ReadBytes(&serialized_uid, sizeof(serialized_uid)))
754           {
755             // This just adds the pipeline to the map, it is compiled later.
756             AddSerializedGXPipelineUID(serialized_uid);
757           }
758           else
759           {
760             uid_file_valid = false;
761             break;
762           }
763         }
764       }
765 
766       // We open the file for reading and writing, so we must seek to the end before writing.
767       if (uid_file_valid)
768         uid_file_valid = m_gx_pipeline_uid_cache_file.Seek(expected_size, SEEK_SET);
769     }
770 
771     // If the file is invalid, close it. We re-open and truncate it below.
772     if (!uid_file_valid)
773       m_gx_pipeline_uid_cache_file.Close();
774   }
775 
776   // If the file is not open, it means it was either corrupted or didn't exist.
777   if (!m_gx_pipeline_uid_cache_file.IsOpen())
778   {
779     if (m_gx_pipeline_uid_cache_file.Open(filename, "wb"))
780     {
781       // Write the version identifier.
782       m_gx_pipeline_uid_cache_file.WriteBytes(&CACHE_FILE_MAGIC, sizeof(GX_PIPELINE_UID_VERSION));
783       m_gx_pipeline_uid_cache_file.WriteBytes(&GX_PIPELINE_UID_VERSION,
784                                               sizeof(GX_PIPELINE_UID_VERSION));
785 
786       // Write any current UIDs out to the file.
787       // This way, if we load a UID cache where the data was incomplete (e.g. Dolphin crashed),
788       // we don't lose the existing UIDs which were previously at the beginning.
789       for (const auto& it : m_gx_pipeline_cache)
790         AppendGXPipelineUID(it.first);
791     }
792   }
793 
794   INFO_LOG(VIDEO, "Read %u pipeline UIDs from %s",
795            static_cast<unsigned>(m_gx_pipeline_cache.size()), filename.c_str());
796 }
797 
ClosePipelineUIDCache()798 void ShaderCache::ClosePipelineUIDCache()
799 {
800   // This is left as a method in case we need to append extra data to the file in the future.
801   m_gx_pipeline_uid_cache_file.Close();
802 }
803 
AddSerializedGXPipelineUID(const SerializedGXPipelineUid & uid)804 void ShaderCache::AddSerializedGXPipelineUID(const SerializedGXPipelineUid& uid)
805 {
806   GXPipelineUid real_uid;
807   UnserializePipelineUid(uid, real_uid);
808 
809   auto iter = m_gx_pipeline_cache.find(real_uid);
810   if (iter != m_gx_pipeline_cache.end())
811     return;
812 
813   // Flag it as empty with a null pipeline object, for later compilation.
814   auto& entry = m_gx_pipeline_cache[real_uid];
815   entry.second = false;
816 }
817 
AppendGXPipelineUID(const GXPipelineUid & config)818 void ShaderCache::AppendGXPipelineUID(const GXPipelineUid& config)
819 {
820   if (!m_gx_pipeline_uid_cache_file.IsOpen())
821     return;
822 
823   SerializedGXPipelineUid disk_uid;
824   SerializePipelineUid(config, disk_uid);
825   if (!m_gx_pipeline_uid_cache_file.WriteBytes(&disk_uid, sizeof(disk_uid)))
826   {
827     WARN_LOG(VIDEO, "Writing pipeline UID to cache failed, closing file.");
828     m_gx_pipeline_uid_cache_file.Close();
829   }
830 }
831 
QueueVertexShaderCompile(const VertexShaderUid & uid,u32 priority)832 void ShaderCache::QueueVertexShaderCompile(const VertexShaderUid& uid, u32 priority)
833 {
834   class VertexShaderWorkItem final : public AsyncShaderCompiler::WorkItem
835   {
836   public:
837     VertexShaderWorkItem(ShaderCache* shader_cache_, const VertexShaderUid& uid_)
838         : shader_cache(shader_cache_), uid(uid_)
839     {
840     }
841 
842     bool Compile() override
843     {
844       shader = shader_cache->CompileVertexShader(uid);
845       return true;
846     }
847 
848     void Retrieve() override { shader_cache->InsertVertexShader(uid, std::move(shader)); }
849 
850   private:
851     ShaderCache* shader_cache;
852     std::unique_ptr<AbstractShader> shader;
853     VertexShaderUid uid;
854   };
855 
856   m_vs_cache.shader_map[uid].pending = true;
857   auto wi = m_async_shader_compiler->CreateWorkItem<VertexShaderWorkItem>(this, uid);
858   m_async_shader_compiler->QueueWorkItem(std::move(wi), priority);
859 }
860 
QueueVertexUberShaderCompile(const UberShader::VertexShaderUid & uid,u32 priority)861 void ShaderCache::QueueVertexUberShaderCompile(const UberShader::VertexShaderUid& uid, u32 priority)
862 {
863   class VertexUberShaderWorkItem final : public AsyncShaderCompiler::WorkItem
864   {
865   public:
866     VertexUberShaderWorkItem(ShaderCache* shader_cache_, const UberShader::VertexShaderUid& uid_)
867         : shader_cache(shader_cache_), uid(uid_)
868     {
869     }
870 
871     bool Compile() override
872     {
873       shader = shader_cache->CompileVertexUberShader(uid);
874       return true;
875     }
876 
877     void Retrieve() override { shader_cache->InsertVertexUberShader(uid, std::move(shader)); }
878 
879   private:
880     ShaderCache* shader_cache;
881     std::unique_ptr<AbstractShader> shader;
882     UberShader::VertexShaderUid uid;
883   };
884 
885   m_uber_vs_cache.shader_map[uid].pending = true;
886   auto wi = m_async_shader_compiler->CreateWorkItem<VertexUberShaderWorkItem>(this, uid);
887   m_async_shader_compiler->QueueWorkItem(std::move(wi), priority);
888 }
889 
QueuePixelShaderCompile(const PixelShaderUid & uid,u32 priority)890 void ShaderCache::QueuePixelShaderCompile(const PixelShaderUid& uid, u32 priority)
891 {
892   class PixelShaderWorkItem final : public AsyncShaderCompiler::WorkItem
893   {
894   public:
895     PixelShaderWorkItem(ShaderCache* shader_cache_, const PixelShaderUid& uid_)
896         : shader_cache(shader_cache_), uid(uid_)
897     {
898     }
899 
900     bool Compile() override
901     {
902       shader = shader_cache->CompilePixelShader(uid);
903       return true;
904     }
905 
906     void Retrieve() override { shader_cache->InsertPixelShader(uid, std::move(shader)); }
907 
908   private:
909     ShaderCache* shader_cache;
910     std::unique_ptr<AbstractShader> shader;
911     PixelShaderUid uid;
912   };
913 
914   m_ps_cache.shader_map[uid].pending = true;
915   auto wi = m_async_shader_compiler->CreateWorkItem<PixelShaderWorkItem>(this, uid);
916   m_async_shader_compiler->QueueWorkItem(std::move(wi), priority);
917 }
918 
QueuePixelUberShaderCompile(const UberShader::PixelShaderUid & uid,u32 priority)919 void ShaderCache::QueuePixelUberShaderCompile(const UberShader::PixelShaderUid& uid, u32 priority)
920 {
921   class PixelUberShaderWorkItem final : public AsyncShaderCompiler::WorkItem
922   {
923   public:
924     PixelUberShaderWorkItem(ShaderCache* shader_cache_, const UberShader::PixelShaderUid& uid_)
925         : shader_cache(shader_cache_), uid(uid_)
926     {
927     }
928 
929     bool Compile() override
930     {
931       shader = shader_cache->CompilePixelUberShader(uid);
932       return true;
933     }
934 
935     void Retrieve() override { shader_cache->InsertPixelUberShader(uid, std::move(shader)); }
936 
937   private:
938     ShaderCache* shader_cache;
939     std::unique_ptr<AbstractShader> shader;
940     UberShader::PixelShaderUid uid;
941   };
942 
943   m_uber_ps_cache.shader_map[uid].pending = true;
944   auto wi = m_async_shader_compiler->CreateWorkItem<PixelUberShaderWorkItem>(this, uid);
945   m_async_shader_compiler->QueueWorkItem(std::move(wi), priority);
946 }
947 
QueuePipelineCompile(const GXPipelineUid & uid,u32 priority)948 void ShaderCache::QueuePipelineCompile(const GXPipelineUid& uid, u32 priority)
949 {
950   class PipelineWorkItem final : public AsyncShaderCompiler::WorkItem
951   {
952   public:
953     PipelineWorkItem(ShaderCache* shader_cache_, const GXPipelineUid& uid_, u32 priority_)
954         : shader_cache(shader_cache_), uid(uid_), priority(priority_)
955     {
956       // Check if all the stages required for this pipeline have been compiled.
957       // If not, this work item becomes a no-op, and re-queues the pipeline for the next frame.
958       if (SetStagesReady())
959         config = shader_cache->GetGXPipelineConfig(uid);
960     }
961 
962     bool SetStagesReady()
963     {
964       stages_ready = true;
965 
966       auto vs_it = shader_cache->m_vs_cache.shader_map.find(uid.vs_uid);
967       stages_ready &= vs_it != shader_cache->m_vs_cache.shader_map.end() && !vs_it->second.pending;
968       if (vs_it == shader_cache->m_vs_cache.shader_map.end())
969         shader_cache->QueueVertexShaderCompile(uid.vs_uid, priority);
970 
971       PixelShaderUid ps_uid = uid.ps_uid;
972       ClearUnusedPixelShaderUidBits(shader_cache->m_api_type, shader_cache->m_host_config, &ps_uid);
973 
974       auto ps_it = shader_cache->m_ps_cache.shader_map.find(ps_uid);
975       stages_ready &= ps_it != shader_cache->m_ps_cache.shader_map.end() && !ps_it->second.pending;
976       if (ps_it == shader_cache->m_ps_cache.shader_map.end())
977         shader_cache->QueuePixelShaderCompile(ps_uid, priority);
978 
979       return stages_ready;
980     }
981 
982     bool Compile() override
983     {
984       if (config)
985         pipeline = g_renderer->CreatePipeline(*config);
986       return true;
987     }
988 
989     void Retrieve() override
990     {
991       if (stages_ready)
992       {
993         shader_cache->InsertGXPipeline(uid, std::move(pipeline));
994       }
995       else
996       {
997         // Re-queue for next frame.
998         auto wi = shader_cache->m_async_shader_compiler->CreateWorkItem<PipelineWorkItem>(
999             shader_cache, uid, priority);
1000         shader_cache->m_async_shader_compiler->QueueWorkItem(std::move(wi), priority);
1001       }
1002     }
1003 
1004   private:
1005     ShaderCache* shader_cache;
1006     std::unique_ptr<AbstractPipeline> pipeline;
1007     GXPipelineUid uid;
1008     u32 priority;
1009     std::optional<AbstractPipelineConfig> config;
1010     bool stages_ready;
1011   };
1012 
1013   auto wi = m_async_shader_compiler->CreateWorkItem<PipelineWorkItem>(this, uid, priority);
1014   m_async_shader_compiler->QueueWorkItem(std::move(wi), priority);
1015   m_gx_pipeline_cache[uid].second = true;
1016 }
1017 
QueueUberPipelineCompile(const GXUberPipelineUid & uid,u32 priority)1018 void ShaderCache::QueueUberPipelineCompile(const GXUberPipelineUid& uid, u32 priority)
1019 {
1020   class UberPipelineWorkItem final : public AsyncShaderCompiler::WorkItem
1021   {
1022   public:
1023     UberPipelineWorkItem(ShaderCache* shader_cache_, const GXUberPipelineUid& uid_, u32 priority_)
1024         : shader_cache(shader_cache_), uid(uid_), priority(priority_)
1025     {
1026       // Check if all the stages required for this UberPipeline have been compiled.
1027       // If not, this work item becomes a no-op, and re-queues the UberPipeline for the next frame.
1028       if (SetStagesReady())
1029         config = shader_cache->GetGXPipelineConfig(uid);
1030     }
1031 
1032     bool SetStagesReady()
1033     {
1034       stages_ready = true;
1035 
1036       auto vs_it = shader_cache->m_uber_vs_cache.shader_map.find(uid.vs_uid);
1037       stages_ready &=
1038           vs_it != shader_cache->m_uber_vs_cache.shader_map.end() && !vs_it->second.pending;
1039       if (vs_it == shader_cache->m_uber_vs_cache.shader_map.end())
1040         shader_cache->QueueVertexUberShaderCompile(uid.vs_uid, priority);
1041 
1042       UberShader::PixelShaderUid ps_uid = uid.ps_uid;
1043       UberShader::ClearUnusedPixelShaderUidBits(shader_cache->m_api_type,
1044                                                 shader_cache->m_host_config, &ps_uid);
1045 
1046       auto ps_it = shader_cache->m_uber_ps_cache.shader_map.find(ps_uid);
1047       stages_ready &=
1048           ps_it != shader_cache->m_uber_ps_cache.shader_map.end() && !ps_it->second.pending;
1049       if (ps_it == shader_cache->m_uber_ps_cache.shader_map.end())
1050         shader_cache->QueuePixelUberShaderCompile(ps_uid, priority);
1051 
1052       return stages_ready;
1053     }
1054 
1055     bool Compile() override
1056     {
1057       if (config)
1058         UberPipeline = g_renderer->CreatePipeline(*config);
1059       return true;
1060     }
1061 
1062     void Retrieve() override
1063     {
1064       if (stages_ready)
1065       {
1066         shader_cache->InsertGXUberPipeline(uid, std::move(UberPipeline));
1067       }
1068       else
1069       {
1070         // Re-queue for next frame.
1071         auto wi = shader_cache->m_async_shader_compiler->CreateWorkItem<UberPipelineWorkItem>(
1072             shader_cache, uid, priority);
1073         shader_cache->m_async_shader_compiler->QueueWorkItem(std::move(wi), priority);
1074       }
1075     }
1076 
1077   private:
1078     ShaderCache* shader_cache;
1079     std::unique_ptr<AbstractPipeline> UberPipeline;
1080     GXUberPipelineUid uid;
1081     u32 priority;
1082     std::optional<AbstractPipelineConfig> config;
1083     bool stages_ready;
1084   };
1085 
1086   auto wi = m_async_shader_compiler->CreateWorkItem<UberPipelineWorkItem>(this, uid, priority);
1087   m_async_shader_compiler->QueueWorkItem(std::move(wi), priority);
1088   m_gx_uber_pipeline_cache[uid].second = true;
1089 }
1090 
QueueUberShaderPipelines()1091 void ShaderCache::QueueUberShaderPipelines()
1092 {
1093   // Create a dummy vertex format with no attributes.
1094   // All attributes will be enabled in GetUberVertexFormat.
1095   PortableVertexDeclaration dummy_vertex_decl = {};
1096   dummy_vertex_decl.position.components = 4;
1097   dummy_vertex_decl.position.type = VAR_FLOAT;
1098   dummy_vertex_decl.position.enable = true;
1099   dummy_vertex_decl.stride = sizeof(float) * 4;
1100   NativeVertexFormat* dummy_vertex_format =
1101       VertexLoaderManager::GetUberVertexFormat(dummy_vertex_decl);
1102   auto QueueDummyPipeline = [&](const UberShader::VertexShaderUid& vs_uid,
1103                                 const GeometryShaderUid& gs_uid,
1104                                 const UberShader::PixelShaderUid& ps_uid) {
1105     GXUberPipelineUid config;
1106     config.vertex_format = dummy_vertex_format;
1107     config.vs_uid = vs_uid;
1108     config.gs_uid = gs_uid;
1109     config.ps_uid = ps_uid;
1110     config.rasterization_state = RenderState::GetCullBackFaceRasterizationState(
1111         static_cast<PrimitiveType>(gs_uid.GetUidData()->primitive_type));
1112     config.depth_state = RenderState::GetNoDepthTestingDepthState();
1113     config.blending_state = RenderState::GetNoBlendingBlendState();
1114     if (ps_uid.GetUidData()->uint_output)
1115     {
1116       // uint_output is only ever enabled when logic ops are enabled.
1117       config.blending_state.logicopenable = true;
1118       config.blending_state.logicmode = BlendMode::AND;
1119     }
1120 
1121     auto iter = m_gx_uber_pipeline_cache.find(config);
1122     if (iter != m_gx_uber_pipeline_cache.end())
1123       return;
1124 
1125     auto& entry = m_gx_uber_pipeline_cache[config];
1126     entry.second = false;
1127   };
1128 
1129   // Populate the pipeline configs with empty entries, these will be compiled afterwards.
1130   UberShader::EnumerateVertexShaderUids([&](const UberShader::VertexShaderUid& vuid) {
1131     UberShader::EnumeratePixelShaderUids([&](const UberShader::PixelShaderUid& puid) {
1132       // UIDs must have compatible texgens, a mismatching combination will never be queried.
1133       if (vuid.GetUidData()->num_texgens != puid.GetUidData()->num_texgens)
1134         return;
1135 
1136       UberShader::PixelShaderUid cleared_puid = puid;
1137       UberShader::ClearUnusedPixelShaderUidBits(m_api_type, m_host_config, &cleared_puid);
1138       EnumerateGeometryShaderUids([&](const GeometryShaderUid& guid) {
1139         if (guid.GetUidData()->numTexGens != vuid.GetUidData()->num_texgens ||
1140             (!guid.GetUidData()->IsPassthrough() && !m_host_config.backend_geometry_shaders))
1141         {
1142           return;
1143         }
1144         QueueDummyPipeline(vuid, guid, cleared_puid);
1145       });
1146     });
1147   });
1148 }
1149 
1150 const AbstractPipeline*
GetEFBCopyToVRAMPipeline(const TextureConversionShaderGen::TCShaderUid & uid)1151 ShaderCache::GetEFBCopyToVRAMPipeline(const TextureConversionShaderGen::TCShaderUid& uid)
1152 {
1153   auto iter = m_efb_copy_to_vram_pipelines.find(uid);
1154   if (iter != m_efb_copy_to_vram_pipelines.end())
1155     return iter->second.get();
1156 
1157   auto shader_code = TextureConversionShaderGen::GeneratePixelShader(m_api_type, uid.GetUidData());
1158   auto shader = g_renderer->CreateShaderFromSource(ShaderStage::Pixel, shader_code.GetBuffer());
1159   if (!shader)
1160   {
1161     m_efb_copy_to_vram_pipelines.emplace(uid, nullptr);
1162     return nullptr;
1163   }
1164 
1165   AbstractPipelineConfig config = {};
1166   config.vertex_format = nullptr;
1167   config.vertex_shader = m_efb_copy_vertex_shader.get();
1168   config.geometry_shader =
1169       UseGeometryShaderForEFBCopies() ? m_texcoord_geometry_shader.get() : nullptr;
1170   config.pixel_shader = shader.get();
1171   config.rasterization_state = RenderState::GetNoCullRasterizationState(PrimitiveType::Triangles);
1172   config.depth_state = RenderState::GetNoDepthTestingDepthState();
1173   config.blending_state = RenderState::GetNoBlendingBlendState();
1174   config.framebuffer_state = RenderState::GetRGBA8FramebufferState();
1175   config.usage = AbstractPipelineUsage::Utility;
1176   auto iiter = m_efb_copy_to_vram_pipelines.emplace(uid, g_renderer->CreatePipeline(config));
1177   return iiter.first->second.get();
1178 }
1179 
GetEFBCopyToRAMPipeline(const EFBCopyParams & uid)1180 const AbstractPipeline* ShaderCache::GetEFBCopyToRAMPipeline(const EFBCopyParams& uid)
1181 {
1182   auto iter = m_efb_copy_to_ram_pipelines.find(uid);
1183   if (iter != m_efb_copy_to_ram_pipelines.end())
1184     return iter->second.get();
1185 
1186   const std::string shader_code =
1187       TextureConversionShaderTiled::GenerateEncodingShader(uid, m_api_type);
1188   const auto shader = g_renderer->CreateShaderFromSource(ShaderStage::Pixel, shader_code);
1189   if (!shader)
1190   {
1191     m_efb_copy_to_ram_pipelines.emplace(uid, nullptr);
1192     return nullptr;
1193   }
1194 
1195   AbstractPipelineConfig config = {};
1196   config.vertex_shader = m_screen_quad_vertex_shader.get();
1197   config.pixel_shader = shader.get();
1198   config.rasterization_state = RenderState::GetNoCullRasterizationState(PrimitiveType::Triangles);
1199   config.depth_state = RenderState::GetNoDepthTestingDepthState();
1200   config.blending_state = RenderState::GetNoBlendingBlendState();
1201   config.framebuffer_state = RenderState::GetColorFramebufferState(AbstractTextureFormat::BGRA8);
1202   config.usage = AbstractPipelineUsage::Utility;
1203   auto iiter = m_efb_copy_to_ram_pipelines.emplace(uid, g_renderer->CreatePipeline(config));
1204   return iiter.first->second.get();
1205 }
1206 
CompileSharedPipelines()1207 bool ShaderCache::CompileSharedPipelines()
1208 {
1209   m_screen_quad_vertex_shader = g_renderer->CreateShaderFromSource(
1210       ShaderStage::Vertex, FramebufferShaderGen::GenerateScreenQuadVertexShader());
1211   m_texture_copy_vertex_shader = g_renderer->CreateShaderFromSource(
1212       ShaderStage::Vertex, FramebufferShaderGen::GenerateTextureCopyVertexShader());
1213   m_efb_copy_vertex_shader = g_renderer->CreateShaderFromSource(
1214       ShaderStage::Vertex,
1215       TextureConversionShaderGen::GenerateVertexShader(m_api_type).GetBuffer());
1216   if (!m_screen_quad_vertex_shader || !m_texture_copy_vertex_shader || !m_efb_copy_vertex_shader)
1217     return false;
1218 
1219   if (UseGeometryShaderForEFBCopies())
1220   {
1221     m_texcoord_geometry_shader = g_renderer->CreateShaderFromSource(
1222         ShaderStage::Geometry, FramebufferShaderGen::GeneratePassthroughGeometryShader(1, 0));
1223     m_color_geometry_shader = g_renderer->CreateShaderFromSource(
1224         ShaderStage::Geometry, FramebufferShaderGen::GeneratePassthroughGeometryShader(0, 1));
1225     if (!m_texcoord_geometry_shader || !m_color_geometry_shader)
1226       return false;
1227   }
1228 
1229   m_texture_copy_pixel_shader = g_renderer->CreateShaderFromSource(
1230       ShaderStage::Pixel, FramebufferShaderGen::GenerateTextureCopyPixelShader());
1231   m_color_pixel_shader = g_renderer->CreateShaderFromSource(
1232       ShaderStage::Pixel, FramebufferShaderGen::GenerateColorPixelShader());
1233   if (!m_texture_copy_pixel_shader || !m_color_pixel_shader)
1234     return false;
1235 
1236   AbstractPipelineConfig config;
1237   config.vertex_format = nullptr;
1238   config.vertex_shader = m_texture_copy_vertex_shader.get();
1239   config.geometry_shader = nullptr;
1240   config.pixel_shader = m_texture_copy_pixel_shader.get();
1241   config.rasterization_state = RenderState::GetNoCullRasterizationState(PrimitiveType::Triangles);
1242   config.depth_state = RenderState::GetNoDepthTestingDepthState();
1243   config.blending_state = RenderState::GetNoBlendingBlendState();
1244   config.framebuffer_state = RenderState::GetRGBA8FramebufferState();
1245   config.usage = AbstractPipelineUsage::Utility;
1246   m_copy_rgba8_pipeline = g_renderer->CreatePipeline(config);
1247   if (!m_copy_rgba8_pipeline)
1248     return false;
1249 
1250   if (UseGeometryShaderForEFBCopies())
1251   {
1252     config.geometry_shader = m_texcoord_geometry_shader.get();
1253     m_rgba8_stereo_copy_pipeline = g_renderer->CreatePipeline(config);
1254     if (!m_rgba8_stereo_copy_pipeline)
1255       return false;
1256   }
1257 
1258   if (m_host_config.backend_palette_conversion)
1259   {
1260     config.vertex_shader = m_screen_quad_vertex_shader.get();
1261     config.geometry_shader = nullptr;
1262 
1263     for (size_t i = 0; i < NUM_PALETTE_CONVERSION_SHADERS; i++)
1264     {
1265       auto shader = g_renderer->CreateShaderFromSource(
1266           ShaderStage::Pixel, TextureConversionShaderTiled::GeneratePaletteConversionShader(
1267                                   static_cast<TLUTFormat>(i), m_api_type));
1268       if (!shader)
1269         return false;
1270 
1271       config.pixel_shader = shader.get();
1272       m_palette_conversion_pipelines[i] = g_renderer->CreatePipeline(config);
1273       if (!m_palette_conversion_pipelines[i])
1274         return false;
1275     }
1276   }
1277 
1278   return true;
1279 }
1280 
GetPaletteConversionPipeline(TLUTFormat format)1281 const AbstractPipeline* ShaderCache::GetPaletteConversionPipeline(TLUTFormat format)
1282 {
1283   ASSERT(static_cast<size_t>(format) < NUM_PALETTE_CONVERSION_SHADERS);
1284   return m_palette_conversion_pipelines[static_cast<size_t>(format)].get();
1285 }
1286 
GetTextureReinterpretPipeline(TextureFormat from_format,TextureFormat to_format)1287 const AbstractPipeline* ShaderCache::GetTextureReinterpretPipeline(TextureFormat from_format,
1288                                                                    TextureFormat to_format)
1289 {
1290   const auto key = std::make_pair(from_format, to_format);
1291   auto iter = m_texture_reinterpret_pipelines.find(key);
1292   if (iter != m_texture_reinterpret_pipelines.end())
1293     return iter->second.get();
1294 
1295   std::string shader_source =
1296       FramebufferShaderGen::GenerateTextureReinterpretShader(from_format, to_format);
1297   if (shader_source.empty())
1298   {
1299     m_texture_reinterpret_pipelines.emplace(key, nullptr);
1300     return nullptr;
1301   }
1302 
1303   std::unique_ptr<AbstractShader> shader =
1304       g_renderer->CreateShaderFromSource(ShaderStage::Pixel, shader_source);
1305   if (!shader)
1306   {
1307     m_texture_reinterpret_pipelines.emplace(key, nullptr);
1308     return nullptr;
1309   }
1310 
1311   AbstractPipelineConfig config;
1312   config.vertex_format = nullptr;
1313   config.vertex_shader = m_screen_quad_vertex_shader.get();
1314   config.geometry_shader = nullptr;
1315   config.pixel_shader = shader.get();
1316   config.rasterization_state = RenderState::GetNoCullRasterizationState(PrimitiveType::Triangles);
1317   config.depth_state = RenderState::GetNoDepthTestingDepthState();
1318   config.blending_state = RenderState::GetNoBlendingBlendState();
1319   config.framebuffer_state = RenderState::GetRGBA8FramebufferState();
1320   config.usage = AbstractPipelineUsage::Utility;
1321   auto iiter = m_texture_reinterpret_pipelines.emplace(key, g_renderer->CreatePipeline(config));
1322   return iiter.first->second.get();
1323 }
1324 
GetTextureDecodingShader(TextureFormat format,TLUTFormat palette_format)1325 const AbstractShader* ShaderCache::GetTextureDecodingShader(TextureFormat format,
1326                                                             TLUTFormat palette_format)
1327 {
1328   const auto key = std::make_pair(static_cast<u32>(format), static_cast<u32>(palette_format));
1329   auto iter = m_texture_decoding_shaders.find(key);
1330   if (iter != m_texture_decoding_shaders.end())
1331     return iter->second.get();
1332 
1333   std::string shader_source =
1334       TextureConversionShaderTiled::GenerateDecodingShader(format, palette_format, APIType::OpenGL);
1335   if (shader_source.empty())
1336   {
1337     m_texture_decoding_shaders.emplace(key, nullptr);
1338     return nullptr;
1339   }
1340 
1341   std::unique_ptr<AbstractShader> shader =
1342       g_renderer->CreateShaderFromSource(ShaderStage::Compute, shader_source);
1343   if (!shader)
1344   {
1345     m_texture_decoding_shaders.emplace(key, nullptr);
1346     return nullptr;
1347   }
1348 
1349   auto iiter = m_texture_decoding_shaders.emplace(key, std::move(shader));
1350   return iiter.first->second.get();
1351 }
1352 }  // namespace VideoCommon
1353