From 54db5aaf3bcfe3066761d5f819210c30d115c408 Mon Sep 17 00:00:00 2001 From: baldurk Date: Fri, 4 Sep 2020 16:53:38 +0100 Subject: [PATCH] Store entries in vulkan shader cache for GLSL generation inputs * GenerateGLSLShader is reasonably expensive because it uses glslang to preprocess the shaders. If we can cache the input hash and look up the cache with that hash then we can skip it entirely. --- renderdoc/driver/vulkan/vk_shader_cache.cpp | 42 ++++++++++++++++----- 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/renderdoc/driver/vulkan/vk_shader_cache.cpp b/renderdoc/driver/vulkan/vk_shader_cache.cpp index 19af5b38a..b5bfb61f6 100644 --- a/renderdoc/driver/vulkan/vk_shader_cache.cpp +++ b/renderdoc/driver/vulkan/vk_shader_cache.cpp @@ -239,7 +239,6 @@ VulkanShaderCache::VulkanShaderCache(WrappedVulkan *driver) if(driverVersion.RunningOnMetal()) globalDefines += "#define METAL_BACKEND\n"; - rdcstr src; rdcspv::CompilationSettings compileSettings; compileSettings.lang = rdcspv::InputLanguage::VulkanGLSL; @@ -267,6 +266,8 @@ VulkanShaderCache::VulkanShaderCache(WrappedVulkan *driver) if(config.flags & BuiltinShaderFlags::TextureTypeParameterised) textureTypeCount = (size_t)BuiltinShaderTextureType::Count; + compileSettings.stage = config.stage; + // for shaders that aren't parameterised these loops will be a no-op that only iterates once, // and fills in [First][First] entry. for(size_t baseType = (size_t)BuiltinShaderBaseType::First; baseType < baseTypeCount; baseType++) @@ -279,14 +280,37 @@ VulkanShaderCache::VulkanShaderCache(WrappedVulkan *driver) defines += rdcstr("#define SHADER_RESTYPE ") + ToStr(textureType) + "\n"; defines += rdcstr("#define SHADER_BASETYPE ") + ToStr(baseType) + "\n"; - src = GenerateGLSLShader(GetDynamicEmbeddedResource(config.resource), ShaderType::Vulkan, - 430, defines); + SPIRVBlob &blob = m_BuiltinShaderBlobs[i][baseType][textureType]; + rdcstr source = GetDynamicEmbeddedResource(config.resource); - compileSettings.stage = config.stage; - rdcstr err = - GetSPIRVBlob(compileSettings, src, m_BuiltinShaderBlobs[i][baseType][textureType]); + uint32_t inputHash = strhash(source.c_str()); + inputHash = strhash(defines.c_str(), inputHash); - if(!err.empty() || m_BuiltinShaderBlobs[i][baseType][textureType] == VK_NULL_HANDLE) + // bump this version if anything inside GenerateGLSLShader changes. This is used to + // determine if we can skip the call to GenerateGLSLShader (which calls out to glslang). + // Otherwise we'll use the cached SPIR-V generated by the previous call using the same + // source & defines. + inputHash = strhash("inputHashVersion1", inputHash); + + rdcstr err; + + if(m_ShaderCache.find(inputHash) != m_ShaderCache.end()) + blob = m_ShaderCache[inputHash]; + + if(blob == NULL) + { + err = GetSPIRVBlob(compileSettings, + GenerateGLSLShader(source, ShaderType::Vulkan, 430, defines), blob); + + // if we missed the inputHash, make a copy there too. + if(m_CacheShaders) + { + m_ShaderCache[inputHash] = new rdcarray(*blob); + m_ShaderCacheDirty = true; + } + } + + if(!err.empty() || blob == VK_NULL_HANDLE) { RDCERR("Error compiling builtin %u (baseType %zu textureType %zu): %s", (uint32_t)i, baseType, textureType, err.c_str()); @@ -297,8 +321,8 @@ VulkanShaderCache::VulkanShaderCache(WrappedVulkan *driver) VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, NULL, 0, - m_BuiltinShaderBlobs[i][baseType][textureType]->size() * sizeof(uint32_t), - m_BuiltinShaderBlobs[i][baseType][textureType]->data(), + blob->size() * sizeof(uint32_t), + blob->data(), }; VkResult vkr = driver->vkCreateShaderModule(