From 4f1316b3fd768fd37368427d12d2ed34cd50305d Mon Sep 17 00:00:00 2001 From: dpjudas Date: Sat, 19 Apr 2025 09:30:17 +0200 Subject: [PATCH] Add thread safety to VkShaderCache --- .../rendering/vulkan/shaders/vk_shader.cpp | 4 +- .../vulkan/shaders/vk_shadercache.cpp | 96 ++++++++++++------- .../rendering/vulkan/shaders/vk_shadercache.h | 12 ++- src/common/rendering/vulkan/vk_levelmesh.cpp | 4 +- .../rendering/vulkan/vk_lightmapper.cpp | 4 +- 5 files changed, 77 insertions(+), 43 deletions(-) diff --git a/src/common/rendering/vulkan/shaders/vk_shader.cpp b/src/common/rendering/vulkan/shaders/vk_shader.cpp index 40b56f12f..a77ffa1a3 100644 --- a/src/common/rendering/vulkan/shaders/vk_shader.cpp +++ b/src/common/rendering/vulkan/shaders/vk_shader.cpp @@ -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) diff --git a/src/common/rendering/vulkan/shaders/vk_shadercache.cpp b/src/common/rendering/vulkan/shaders/vk_shadercache.cpp index f28c49c87..361a2135a 100644 --- a/src/common/rendering/vulkan/shaders/vk_shadercache.cpp +++ b/src/common/rendering/vulkan/shaders/vk_shadercache.cpp @@ -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 VkShaderCache::Compile(ShaderType type, const TArrayView& sources, const std::function& 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 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 VkShaderCache::Compile(ShaderType type, const TArrayViewGetDevice()); cachedCompile.LastUsed = LaunchTime; + return AddToCache(key, std::move(cachedCompile)); +} - auto& c = CodeCache[checksum]; +std::vector 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 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; diff --git a/src/common/rendering/vulkan/shaders/vk_shadercache.h b/src/common/rendering/vulkan/shaders/vk_shadercache.h index f5e4b9a56..c038e4a46 100644 --- a/src/common/rendering/vulkan/shaders/vk_shadercache.h +++ b/src/common/rendering/vulkan/shaders/vk_shadercache.h @@ -6,6 +6,7 @@ #include #include #include +#include #include class VulkanRenderDevice; @@ -50,18 +51,24 @@ public: std::vector Compile(ShaderType type, const TArrayView& sources, const std::function& 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 GetFromCache(const FString& key); + std::vector AddToCache(const FString& key, VkCachedCompile cachedCompile); + FString CalcSha1(ShaderType type, const TArrayView& sources); FString CalcSha1(const FString& str); ShaderIncludeResult OnInclude(VkCachedCompile& cachedCompile, FString headerName, FString includerName, size_t depth, bool system, const std::function& 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 PublicFiles; std::map PrivateFiles; std::map CodeCache; diff --git a/src/common/rendering/vulkan/vk_levelmesh.cpp b/src/common/rendering/vulkan/vk_levelmesh.cpp index d1fce2bfa..9be513a4d 100644 --- a/src/common/rendering/vulkan/vk_levelmesh.cpp +++ b/src/common/rendering/vulkan/vk_levelmesh.cpp @@ -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); } ///////////////////////////////////////////////////////////////////////////// diff --git a/src/common/rendering/vulkan/vk_lightmapper.cpp b/src/common/rendering/vulkan/vk_lightmapper.cpp index eff1c1dcf..f14a5d647 100644 --- a/src/common/rendering/vulkan/vk_lightmapper.cpp +++ b/src/common/rendering/vulkan/vk_lightmapper.cpp @@ -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()