Implement unstripped SPIR-V shader blob loading from magic value tags

This commit is contained in:
baldurk
2022-02-09 18:01:30 +00:00
parent b094c45d42
commit f7aec1a5f6
5 changed files with 131 additions and 1 deletions
@@ -370,6 +370,7 @@ void Processor::Parse(const rdcarray<uint32_t> &spirvWords)
if(packedVersion > VersionPacked)
{
RDCERR("Unsupported SPIR-V version: %08x", packedVersion);
m_SPIRV.clear();
return;
}
@@ -521,7 +521,7 @@ public:
const rdcarray<EntryPoint> &GetEntries() { return entries; }
const rdcarray<Variable> &GetGlobals() { return globals; }
Id GetIDType(Id id) { return idTypes[id]; }
rdcarray<uint32_t> GetSPIRV() const { return m_SPIRV; }
const rdcarray<uint32_t> &GetSPIRV() const { return m_SPIRV; }
protected:
virtual void Parse(const rdcarray<uint32_t> &spirvWords);
+126
View File
@@ -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<rdcstr>, 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<rdcstr> &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<byte> 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>((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,
+2
View File
@@ -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
@@ -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)));
}