Add thread safety to VkShaderCache

This commit is contained in:
dpjudas 2025-04-19 09:30:17 +02:00
commit 4f1316b3fd
5 changed files with 76 additions and 42 deletions

View file

@ -644,12 +644,12 @@ FString VkShaderManager::GetVersionBlock()
FString VkShaderManager::LoadPublicShaderLump(const char* lumpname)
{
return fb->GetShaderCache()->GetPublicFile(lumpname).Code;
return fb->GetShaderCache()->GetPublicFileText(lumpname);
}
FString VkShaderManager::LoadPrivateShaderLump(const char* lumpname)
{
return fb->GetShaderCache()->GetPrivateFile(lumpname).Code;
return fb->GetShaderCache()->GetPrivateFileText(lumpname);
}
VkPPShader* VkShaderManager::GetVkShader(PPShader* shader)

View file

@ -26,42 +26,24 @@ VkShaderCache::~VkShaderCache()
Save();
}
FString VkShaderCache::GetPublicFileText(const FString& lumpname)
{
std::unique_lock lock(Mutex);
return GetPublicFile(lumpname).Code;
}
FString VkShaderCache::GetPrivateFileText(const FString& lumpname)
{
std::unique_lock lock(Mutex);
return GetPrivateFile(lumpname).Code;
}
std::vector<uint32_t> VkShaderCache::Compile(ShaderType type, const TArrayView<VkShaderSource>& sources, const std::function<FString(FString)>& includeFilter)
{
// Is this something we already compiled before?
FString checksum = CalcSha1(type, sources);
auto it = CodeCache.find(checksum);
if (it != CodeCache.end())
{
// OK we found a match. Did any of the include files change?
try
{
VkCachedCompile& cacheinfo = it->second;
bool foundChanges = false;
for (const VkCachedInclude& includeinfo : cacheinfo.Includes)
{
const VkCachedShaderLump& lumpinfo = includeinfo.PrivateLump ? GetPrivateFile(includeinfo.LumpName) : GetPublicFile(includeinfo.LumpName);
if (lumpinfo.Checksum != includeinfo.Checksum)
{
foundChanges = true;
break;
}
}
if (!foundChanges)
{
cacheinfo.LastUsed = LaunchTime;
return cacheinfo.Code;
}
}
catch (...)
{
// If GetPrivateFile or GetPublicFile is unable to find the file anymore it must be out of date.
}
}
FString key = CalcSha1(type, sources);
std::vector<uint32_t> code = GetFromCache(key);
if (!code.empty())
return code;
// No match or out of date
// Compile it and store the dependencies:
@ -77,8 +59,50 @@ std::vector<uint32_t> VkShaderCache::Compile(ShaderType type, const TArrayView<V
compiler.AddSource(source.Name, source.Code);
cachedCompile.Code = compiler.Compile(fb->GetDevice());
cachedCompile.LastUsed = LaunchTime;
return AddToCache(key, std::move(cachedCompile));
}
auto& c = CodeCache[checksum];
std::vector<uint32_t> VkShaderCache::GetFromCache(const FString& key)
{
std::unique_lock lock(Mutex);
auto it = CodeCache.find(key);
if (it == CodeCache.end())
return {};
VkCachedCompile& cacheinfo = it->second;
try
{
// Did any of the include files change?
bool foundChanges = false;
for (const VkCachedInclude& includeinfo : cacheinfo.Includes)
{
const VkCachedShaderLump& lumpinfo = includeinfo.PrivateLump ? GetPrivateFile(includeinfo.LumpName) : GetPublicFile(includeinfo.LumpName);
if (lumpinfo.Checksum != includeinfo.Checksum)
{
foundChanges = true;
break;
}
}
if (foundChanges)
return {};
cacheinfo.LastUsed = LaunchTime;
return cacheinfo.Code;
}
catch (...)
{
// If GetPrivateFile or GetPublicFile is unable to find the file anymore it must be out of date.
return {};
}
}
std::vector<uint32_t> VkShaderCache::AddToCache(const FString& key, VkCachedCompile cachedCompile)
{
std::unique_lock lock(Mutex);
auto& c = CodeCache[key];
c = std::move(cachedCompile);
return c.Code;
}
@ -88,6 +112,8 @@ ShaderIncludeResult VkShaderCache::OnInclude(VkCachedCompile& cachedCompile, FSt
if (depth > 8)
I_Error("Too much include recursion!");
std::unique_lock lock(Mutex);
const VkCachedShaderLump& file = system ? GetPrivateFile(headerName) : GetPublicFile(headerName);
VkCachedInclude cacheinfo;

View file

@ -6,6 +6,7 @@
#include <vector>
#include <map>
#include <functional>
#include <mutex>
#include <zvulkan/vulkanbuilders.h>
class VulkanRenderDevice;
@ -50,18 +51,24 @@ public:
std::vector<uint32_t> Compile(ShaderType type, const TArrayView<VkShaderSource>& sources, const std::function<FString(FString)>& includeFilter = {});
const VkCachedShaderLump& GetPublicFile(const FString& lumpname);
const VkCachedShaderLump& GetPrivateFile(const FString& lumpname);
FString GetPublicFileText(const FString& lumpname);
FString GetPrivateFileText(const FString& lumpname);
private:
void Load();
void Save();
std::vector<uint32_t> GetFromCache(const FString& key);
std::vector<uint32_t> AddToCache(const FString& key, VkCachedCompile cachedCompile);
FString CalcSha1(ShaderType type, const TArrayView<VkShaderSource>& sources);
FString CalcSha1(const FString& str);
ShaderIncludeResult OnInclude(VkCachedCompile& cachedCompile, FString headerName, FString includerName, size_t depth, bool system, const std::function<FString(FString)>& includeFilter);
const VkCachedShaderLump& GetPublicFile(const FString& lumpname);
const VkCachedShaderLump& GetPrivateFile(const FString& lumpname);
static FString LoadPublicShaderLump(const char* lumpname);
static FString LoadPrivateShaderLump(const char* lumpname);
@ -70,6 +77,7 @@ private:
VulkanRenderDevice* fb = nullptr;
std::mutex Mutex;
std::map<FString, VkCachedShaderLump> PublicFiles;
std::map<FString, VkCachedShaderLump> PrivateFiles;
std::map<FString, VkCachedCompile> CodeCache;

View file

@ -645,12 +645,12 @@ void VkLevelMesh::CreateViewerObjects()
FString VkLevelMesh::LoadPrivateShaderLump(const char* lumpname)
{
return fb->GetShaderCache()->GetPrivateFile(lumpname).Code;
return fb->GetShaderCache()->GetPrivateFileText(lumpname);
}
FString VkLevelMesh::LoadPublicShaderLump(const char* lumpname)
{
return fb->GetShaderCache()->GetPublicFile(lumpname).Code;
return fb->GetShaderCache()->GetPublicFileText(lumpname);
}
/////////////////////////////////////////////////////////////////////////////

View file

@ -586,12 +586,12 @@ int VkLightmapper::GetRaytracePipelineIndex()
FString VkLightmapper::LoadPrivateShaderLump(const char* lumpname)
{
return fb->GetShaderCache()->GetPrivateFile(lumpname).Code;
return fb->GetShaderCache()->GetPrivateFileText(lumpname);
}
FString VkLightmapper::LoadPublicShaderLump(const char* lumpname)
{
return fb->GetShaderCache()->GetPublicFile(lumpname).Code;
return fb->GetShaderCache()->GetPublicFileText(lumpname);
}
void VkLightmapper::CreateRaytracePipeline()