message: 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.
diff: @@ -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);
  +
  + // 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<uint32_t>(*blob);
  + m_ShaderCacheDirty = true;
  + }
  + }
  - if(!err.empty() || m_BuiltinShaderBlobs[i][baseType][textureType] == VK_NULL_HANDLE)
  + 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(
  