diff --git a/renderdoc/driver/shaders/spirv/spirv_processor.cpp b/renderdoc/driver/shaders/spirv/spirv_processor.cpp index 347b9e23f..3e7625b39 100644 --- a/renderdoc/driver/shaders/spirv/spirv_processor.cpp +++ b/renderdoc/driver/shaders/spirv/spirv_processor.cpp @@ -370,6 +370,7 @@ void Processor::Parse(const rdcarray &spirvWords) if(packedVersion > VersionPacked) { RDCERR("Unsupported SPIR-V version: %08x", packedVersion); + m_SPIRV.clear(); return; } diff --git a/renderdoc/driver/shaders/spirv/spirv_processor.h b/renderdoc/driver/shaders/spirv/spirv_processor.h index 18f48f87d..4e9a83508 100644 --- a/renderdoc/driver/shaders/spirv/spirv_processor.h +++ b/renderdoc/driver/shaders/spirv/spirv_processor.h @@ -521,7 +521,7 @@ public: const rdcarray &GetEntries() { return entries; } const rdcarray &GetGlobals() { return globals; } Id GetIDType(Id id) { return idTypes[id]; } - rdcarray GetSPIRV() const { return m_SPIRV; } + const rdcarray &GetSPIRV() const { return m_SPIRV; } protected: virtual void Parse(const rdcarray &spirvWords); diff --git a/renderdoc/driver/vulkan/vk_info.cpp b/renderdoc/driver/vulkan/vk_info.cpp index c8f93c81e..d111e3fd9 100644 --- a/renderdoc/driver/vulkan/vk_info.cpp +++ b/renderdoc/driver/vulkan/vk_info.cpp @@ -23,6 +23,11 @@ ******************************************************************************/ #include "vk_info.h" +#include "core/settings.h" +#include "lz4/lz4.h" + +// for compatibility we use the same DXBC name since it's now configured by the UI +RDOC_EXTERN_CONFIG(rdcarray, DXBC_Debug_SearchDirPaths); VkDynamicState ConvertDynamicState(VulkanDynamicStateIndex idx) { @@ -1378,6 +1383,127 @@ void VulkanCreationInfo::ShaderModule::Init(VulkanResourceManager *resourceMan, } } +void VulkanCreationInfo::ShaderModule::Reinit() +{ + bool lz4 = false; + + rdcstr originalPath = unstrippedPath; + + if(!strncmp(originalPath.c_str(), "lz4#", 4)) + { + originalPath = originalPath.substr(4); + lz4 = true; + } + // could support more if we're willing to compile in the decompressor + + FILE *originalShaderFile = NULL; + + const rdcarray &searchPaths = DXBC_Debug_SearchDirPaths(); + + size_t numSearchPaths = searchPaths.size(); + + rdcstr foundPath; + + // keep searching until we've exhausted all possible path options, or we've found a file that + // opens + while(originalShaderFile == NULL && !originalPath.empty()) + { + // while we haven't found a file, keep trying through the search paths. For i==0 + // check the path on its own, in case it's an absolute path. + for(size_t i = 0; originalShaderFile == NULL && i <= numSearchPaths; i++) + { + if(i == 0) + { + originalShaderFile = FileIO::fopen(originalPath, FileIO::ReadBinary); + foundPath = originalPath; + continue; + } + else + { + const rdcstr &searchPath = searchPaths[i - 1]; + foundPath = searchPath + "/" + originalPath; + originalShaderFile = FileIO::fopen(foundPath, FileIO::ReadBinary); + } + } + + if(originalShaderFile == NULL) + { + // follow D3D's search behaviour for consistency: when presented with a + // relative path containing subfolders like foo/bar/blah.pdb then we should first try to + // append it to all search paths as-is, then strip off the top-level subdirectory to get + // bar/blah.pdb and try that in all search directories, and keep going. So if we got here + // and didn't open a file, try to strip off the the top directory and continue. + int32_t offs = originalPath.find_first_of("\\/"); + + // if we couldn't find a directory separator there's nothing to do, stop looking + if(offs == -1) + break; + + // otherwise strip up to there and keep going + originalPath.erase(0, offs + 1); + } + } + + if(originalShaderFile == NULL) + return; + + FileIO::fseek64(originalShaderFile, 0L, SEEK_END); + uint64_t originalShaderSize = FileIO::ftell64(originalShaderFile); + FileIO::fseek64(originalShaderFile, 0, SEEK_SET); + + { + bytebuf debugBytecode; + + debugBytecode.resize((size_t)originalShaderSize); + FileIO::fread(&debugBytecode[0], sizeof(byte), (size_t)originalShaderSize, originalShaderFile); + + if(lz4) + { + rdcarray decompressed; + + // first try decompressing to 1MB flat + decompressed.resize(100 * 1024); + + int ret = LZ4_decompress_safe((const char *)&debugBytecode[0], (char *)&decompressed[0], + (int)debugBytecode.size(), (int)decompressed.size()); + + if(ret < 0) + { + // if it failed, either source is corrupt or we didn't allocate enough space. + // Just allocate 255x compressed size since it can't need any more than that. + decompressed.resize(255 * debugBytecode.size()); + + ret = LZ4_decompress_safe((const char *)&debugBytecode[0], (char *)&decompressed[0], + (int)debugBytecode.size(), (int)decompressed.size()); + + if(ret < 0) + { + RDCERR("Failed to decompress LZ4 data from %s", foundPath.c_str()); + return; + } + } + + RDCASSERT(ret > 0, ret); + + // we resize and memcpy instead of just doing .swap() because that would + // transfer over the over-large pessimistic capacity needed for decompression + debugBytecode.resize(ret); + memcpy(&debugBytecode[0], &decompressed[0], debugBytecode.size()); + } + + rdcspv::Reflector reflTest; + reflTest.Parse(rdcarray((uint32_t *)(debugBytecode.data()), + debugBytecode.size() / sizeof(uint32_t))); + + if(!reflTest.GetSPIRV().empty()) + { + spirv = reflTest; + } + } + + FileIO::fclose(originalShaderFile); +} + void VulkanCreationInfo::ShaderModuleReflection::Init(VulkanResourceManager *resourceMan, ResourceId id, const rdcspv::Reflector &spv, const rdcstr &entry, diff --git a/renderdoc/driver/vulkan/vk_info.h b/renderdoc/driver/vulkan/vk_info.h index 18e336d89..0ac35d4fd 100644 --- a/renderdoc/driver/vulkan/vk_info.h +++ b/renderdoc/driver/vulkan/vk_info.h @@ -638,6 +638,8 @@ struct VulkanCreationInfo void Init(VulkanResourceManager *resourceMan, VulkanCreationInfo &info, const VkShaderModuleCreateInfo *pCreateInfo); + void Reinit(); + ShaderModuleReflection &GetReflection(ShaderStage stage, const rdcstr &entry, ResourceId pipe) { // look for one from this pipeline specifically, if it was specialised diff --git a/renderdoc/driver/vulkan/wrappers/vk_misc_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_misc_funcs.cpp index ac582d0ca..5bececfd9 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_misc_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_misc_funcs.cpp @@ -2092,6 +2092,7 @@ bool WrappedVulkan::Serialise_SetShaderDebugPath(SerialiserType &ser, VkShaderMo if(IsReplayingAndReading()) { m_CreationInfo.m_ShaderModule[GetResID(ShaderObject)].unstrippedPath = DebugPath; + m_CreationInfo.m_ShaderModule[GetResID(ShaderObject)].Reinit(); AddResourceCurChunk(GetResourceManager()->GetOriginalID(GetResID(ShaderObject))); }