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.
This commit is contained in:
baldurk
2021-09-06 14:58:46 +01:00
parent 587c411833
commit cfd6ed0e98
5 changed files with 50 additions and 3 deletions
+10
View File
@@ -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
{
@@ -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);
@@ -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
@@ -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;
@@ -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,