From cfd6ed0e98ddadc9f45a8c954be50069b9fabf24 Mon Sep 17 00:00:00 2001 From: baldurk Date: Mon, 6 Sep 2021 14:58:46 +0100 Subject: [PATCH] Hash any unhashed incoming shaders on D3D12 * This is possible when capturing a program that uses experimental feature to allow unhashed shaders. We don't replay this so it would fail. We could enable the feature, but this is just as easy and means it works even when ""development mode"" isn't enabled. --- renderdoc/driver/d3d12/d3d12_common.h | 10 +++++++ renderdoc/driver/d3d12/d3d12_device_wrap.cpp | 26 +++++++++++++++++++ renderdoc/driver/d3d12/d3d12_device_wrap2.cpp | 11 ++++++++ .../driver/shaders/dxbc/dxbc_container.cpp | 4 +-- .../driver/shaders/dxbc/dxbc_container.h | 2 +- 5 files changed, 50 insertions(+), 3 deletions(-) diff --git a/renderdoc/driver/d3d12/d3d12_common.h b/renderdoc/driver/d3d12/d3d12_common.h index 699809d9d..788281338 100644 --- a/renderdoc/driver/d3d12/d3d12_common.h +++ b/renderdoc/driver/d3d12/d3d12_common.h @@ -528,6 +528,16 @@ public: } } + size_t GetStageCount() { return 6; } + D3D12_SHADER_BYTECODE &GetStage(size_t i) + { + D3D12_SHADER_BYTECODE *stages[] = { + &m_GraphicsStreamData.VS, &m_GraphicsStreamData.HS, &m_GraphicsStreamData.DS, + &m_GraphicsStreamData.GS, &m_GraphicsStreamData.PS, &m_ComputeStreamData.CS, + }; + return *stages[i]; + } + private: struct { diff --git a/renderdoc/driver/d3d12/d3d12_device_wrap.cpp b/renderdoc/driver/d3d12/d3d12_device_wrap.cpp index c7b34310e..1fcb4b616 100644 --- a/renderdoc/driver/d3d12/d3d12_device_wrap.cpp +++ b/renderdoc/driver/d3d12/d3d12_device_wrap.cpp @@ -432,6 +432,25 @@ bool WrappedID3D12Device::Serialise_CreateGraphicsPipelineState( D3D12_GRAPHICS_PIPELINE_STATE_DESC unwrappedDesc = Descriptor; unwrappedDesc.pRootSignature = Unwrap(unwrappedDesc.pRootSignature); + { + D3D12_SHADER_BYTECODE *shaders[] = { + &Descriptor.VS, &Descriptor.HS, &Descriptor.DS, &Descriptor.GS, &Descriptor.PS, + }; + + for(size_t i = 0; i < ARRAY_COUNT(shaders); i++) + { + if(shaders[i]->BytecodeLength == 0 || shaders[i]->pShaderBytecode == NULL) + continue; + + // add any missing hashes ourselves. This probably comes from a capture with experimental + // enabled so it can load unhashed, but we want to be more proactive + if(!DXBC::DXBCContainer::IsHashedContainer(shaders[i]->pShaderBytecode, + shaders[i]->BytecodeLength)) + DXBC::DXBCContainer::HashContainer((void *)shaders[i]->pShaderBytecode, + shaders[i]->BytecodeLength); + } + } + ID3D12PipelineState *ret = NULL; HRESULT hr = m_pDevice->CreateGraphicsPipelineState(&unwrappedDesc, guid, (void **)&ret); @@ -712,6 +731,13 @@ bool WrappedID3D12Device::Serialise_CreateComputePipelineState( D3D12_COMPUTE_PIPELINE_STATE_DESC unwrappedDesc = Descriptor; unwrappedDesc.pRootSignature = Unwrap(unwrappedDesc.pRootSignature); + // add any missing hashes ourselves. This probably comes from a capture with experimental + // enabled so it can load unhashed, but we want to be more proactive + if(!DXBC::DXBCContainer::IsHashedContainer(Descriptor.CS.pShaderBytecode, + Descriptor.CS.BytecodeLength)) + DXBC::DXBCContainer::HashContainer((void *)Descriptor.CS.pShaderBytecode, + Descriptor.CS.BytecodeLength); + ID3D12PipelineState *ret = NULL; HRESULT hr = m_pDevice->CreateComputePipelineState(&unwrappedDesc, guid, (void **)&ret); diff --git a/renderdoc/driver/d3d12/d3d12_device_wrap2.cpp b/renderdoc/driver/d3d12/d3d12_device_wrap2.cpp index 6e5147d78..00ccb7565 100644 --- a/renderdoc/driver/d3d12/d3d12_device_wrap2.cpp +++ b/renderdoc/driver/d3d12/d3d12_device_wrap2.cpp @@ -55,6 +55,17 @@ bool WrappedID3D12Device::Serialise_CreatePipelineState(SerialiserType &ser, ID3D12PipelineState *ret = NULL; HRESULT hr = E_NOINTERFACE; + for(size_t i = 0; i < unwrappedDesc.GetStageCount(); i++) + { + D3D12_SHADER_BYTECODE &sh = unwrappedDesc.GetStage(i); + + if(sh.BytecodeLength == 0 || sh.pShaderBytecode == NULL) + continue; + + if(!DXBC::DXBCContainer::IsHashedContainer(sh.pShaderBytecode, sh.BytecodeLength)) + DXBC::DXBCContainer::HashContainer((void *)sh.pShaderBytecode, sh.BytecodeLength); + } + if(m_pDevice2) hr = m_pDevice2->CreatePipelineState(unwrappedDesc.AsDescStream(), guid, (void **)&ret); else diff --git a/renderdoc/driver/shaders/dxbc/dxbc_container.cpp b/renderdoc/driver/shaders/dxbc/dxbc_container.cpp index 10034a42a..be512d22b 100644 --- a/renderdoc/driver/shaders/dxbc/dxbc_container.cpp +++ b/renderdoc/driver/shaders/dxbc/dxbc_container.cpp @@ -754,12 +754,12 @@ void DXBCContainer::GetHash(uint32_t hash[4], const void *ByteCode, size_t Bytec } } -bool DXBCContainer::IsHashedContainer(void *ByteCode, size_t BytecodeLength) +bool DXBCContainer::IsHashedContainer(const void *ByteCode, size_t BytecodeLength) { if(BytecodeLength < sizeof(FileHeader)) return false; - FileHeader *header = (FileHeader *)ByteCode; + const FileHeader *header = (const FileHeader *)ByteCode; if(header->fourcc != FOURCC_DXBC) return false; diff --git a/renderdoc/driver/shaders/dxbc/dxbc_container.h b/renderdoc/driver/shaders/dxbc/dxbc_container.h index f694fea36..7005661b5 100644 --- a/renderdoc/driver/shaders/dxbc/dxbc_container.h +++ b/renderdoc/driver/shaders/dxbc/dxbc_container.h @@ -170,7 +170,7 @@ public: const DXIL::Program *GetDXILByteCode() { return m_DXILByteCode; } static void GetHash(uint32_t hash[4], const void *ByteCode, size_t BytecodeLength); - static bool IsHashedContainer(void *ByteCode, size_t BytecodeLength); + static bool IsHashedContainer(const void *ByteCode, size_t BytecodeLength); static bool HashContainer(void *ByteCode, size_t BytecodeLength); static bool UsesExtensionUAV(uint32_t slot, uint32_t space, const void *ByteCode,