From 55f0cd05613fd93e667af9c3761eaa2b3add5eec Mon Sep 17 00:00:00 2001 From: baldurk Date: Thu, 7 Mar 2024 16:58:43 +0000 Subject: [PATCH] Generate baked per-pipeline static descriptor access on D3D12 --- renderdoc/driver/d3d12/d3d12_replay.cpp | 52 ++++++- renderdoc/driver/d3d12/d3d12_resources.cpp | 170 +++++++++++++++++++++ renderdoc/driver/d3d12/d3d12_resources.h | 21 ++- 3 files changed, 234 insertions(+), 9 deletions(-) diff --git a/renderdoc/driver/d3d12/d3d12_replay.cpp b/renderdoc/driver/d3d12/d3d12_replay.cpp index f10387cd4..18e3a5e65 100644 --- a/renderdoc/driver/d3d12/d3d12_replay.cpp +++ b/renderdoc/driver/d3d12/d3d12_replay.cpp @@ -2429,7 +2429,57 @@ rdcarray D3D12Replay::GetSamplerDescriptors(ResourceId descri rdcarray D3D12Replay::GetDescriptorAccess() { - return {}; + const D3D12RenderState &rs = m_pDevice->GetQueue()->GetCommandData()->m_RenderState; + + D3D12ResourceManager *rm = m_pDevice->GetResourceManager(); + + WrappedID3D12PipelineState *pipe = NULL; + + if(rs.pipe != ResourceId()) + pipe = rm->GetCurrentAs(rs.pipe); + + rdcarray ret; + + if(pipe) + { + pipe->ProcessDescriptorAccess(); + + ret = pipe->staticDescriptorAccess; + + WrappedID3D12DescriptorHeap *resourceHeap = NULL; + WrappedID3D12DescriptorHeap *samplerHeap = NULL; + for(ResourceId id : rs.heaps) + { + WrappedID3D12DescriptorHeap *heap = + (WrappedID3D12DescriptorHeap *)rm->GetCurrentAs(id); + D3D12_DESCRIPTOR_HEAP_DESC desc = heap->GetDesc(); + if(desc.Type == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV) + resourceHeap = heap; + else + samplerHeap = heap; + } + + for(DescriptorAccess &access : ret) + { + if(access.type == DescriptorType::Sampler) + access.descriptorStore = + samplerHeap ? rm->GetOriginalID(samplerHeap->GetResourceID()) : ResourceId(); + else + access.descriptorStore = + resourceHeap ? rm->GetOriginalID(resourceHeap->GetResourceID()) : ResourceId(); + + uint32_t rootIndex = (uint32_t)access.byteSize; + access.byteSize = 1; + + // apply the per-parameter offset into the heap here + if(pipe->IsGraphics()) + access.byteOffset += (uint32_t)rs.graphics.sigelems[rootIndex].offset; + else + access.byteOffset += (uint32_t)rs.compute.sigelems[rootIndex].offset; + } + } + + return ret; } void D3D12Replay::RenderHighlightBox(float w, float h, float scale) diff --git a/renderdoc/driver/d3d12/d3d12_resources.cpp b/renderdoc/driver/d3d12/d3d12_resources.cpp index 7fe435aa8..e646b58f2 100644 --- a/renderdoc/driver/d3d12/d3d12_resources.cpp +++ b/renderdoc/driver/d3d12/d3d12_resources.cpp @@ -661,6 +661,176 @@ void WrappedID3D12PipelineState::ShaderEntry::BuildReflection() m_Details->resourceId = GetResourceID(); } +rdcpair FindMatchingRootParameter(const D3D12RootSignature *sig, + D3D12_SHADER_VISIBILITY visibility, + D3D12_DESCRIPTOR_RANGE_TYPE rangeType, + uint32_t space, uint32_t bind) +{ + // search the root signature to find the matching entry and figure out the offset from the root binding + for(uint32_t root = 0; root < sig->Parameters.size(); root++) + { + const D3D12RootSignatureParameter ¶m = sig->Parameters[root]; + + if(param.ShaderVisibility != visibility && param.ShaderVisibility != D3D12_SHADER_VISIBILITY_ALL) + continue; + + uint32_t descOffset = 0; + for(const D3D12_DESCRIPTOR_RANGE1 &range : param.ranges) + { + uint32_t rangeOffset = range.OffsetInDescriptorsFromTableStart; + if(range.OffsetInDescriptorsFromTableStart == D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND) + rangeOffset = descOffset; + + if(range.RangeType == rangeType && range.RegisterSpace == space && + range.BaseShaderRegister <= bind && + (range.NumDescriptors == ~0U || bind < range.BaseShaderRegister + range.NumDescriptors)) + { + return {root, rangeOffset + (bind - range.BaseShaderRegister)}; + } + + descOffset = rangeOffset + range.NumDescriptors; + } + } + + return {~0U, 0}; +} + +void WrappedID3D12PipelineState::ProcessDescriptorAccess() +{ + if(m_AccessProcessed) + return; + m_AccessProcessed = true; + + const D3D12RootSignature *sig = NULL; + if(graphics) + sig = &((WrappedID3D12RootSignature *)graphics->pRootSignature)->sig; + else if(compute) + sig = &((WrappedID3D12RootSignature *)compute->pRootSignature)->sig; + + for(ShaderEntry *shad : {VS(), HS(), DS(), GS(), PS(), AS(), MS(), CS()}) + { + if(!shad) + continue; + + const ShaderReflection &refl = shad->GetDetails(); + const ShaderBindpointMapping &mapping = shad->GetMapping(); + + D3D12_SHADER_VISIBILITY visibility; + switch(refl.stage) + { + case ShaderStage::Vertex: visibility = D3D12_SHADER_VISIBILITY_VERTEX; break; + case ShaderStage::Hull: visibility = D3D12_SHADER_VISIBILITY_HULL; break; + case ShaderStage::Domain: visibility = D3D12_SHADER_VISIBILITY_DOMAIN; break; + case ShaderStage::Geometry: visibility = D3D12_SHADER_VISIBILITY_GEOMETRY; break; + case ShaderStage::Pixel: visibility = D3D12_SHADER_VISIBILITY_PIXEL; break; + case ShaderStage::Amplification: visibility = D3D12_SHADER_VISIBILITY_AMPLIFICATION; break; + case ShaderStage::Mesh: visibility = D3D12_SHADER_VISIBILITY_MESH; break; + default: visibility = D3D12_SHADER_VISIBILITY_ALL; break; + } + + DescriptorAccess access; + access.stage = refl.stage; + + // we will store the root signature element in byteSize to be decoded into descriptorStore later + access.byteSize = 0; + + staticDescriptorAccess.reserve(staticDescriptorAccess.size() + mapping.constantBlocks.size() + + mapping.samplers.size() + mapping.readOnlyResources.size() + + mapping.readWriteResources.size()); + + RDCASSERT(mapping.constantBlocks.size() < 0xffff, mapping.constantBlocks.size()); + for(uint16_t i = 0; i < mapping.constantBlocks.size(); i++) + { + const Bindpoint &bind = mapping.constantBlocks[i]; + + // arrayed descriptors will be handled with bindless feedback + if(bind.arraySize > 1) + continue; + + access.staticallyUnused = !bind.used; + access.type = DescriptorType::ConstantBuffer; + access.index = i; + rdctie(access.byteSize, access.byteOffset) = + FindMatchingRootParameter(sig, visibility, D3D12_DESCRIPTOR_RANGE_TYPE_CBV, + (uint32_t)bind.bindset, (uint32_t)bind.bind); + + if(access.byteSize != ~0U) + staticDescriptorAccess.push_back(access); + } + + RDCASSERT(mapping.samplers.size() < 0xffff, mapping.samplers.size()); + for(uint16_t i = 0; i < mapping.samplers.size(); i++) + { + const Bindpoint &bind = mapping.samplers[i]; + + // arrayed descriptors will be handled with bindless feedback + if(bind.arraySize > 1) + continue; + + access.staticallyUnused = !bind.used; + access.type = DescriptorType::Sampler; + access.index = i; + rdctie(access.byteSize, access.byteOffset) = + FindMatchingRootParameter(sig, visibility, D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, + (uint32_t)bind.bindset, (uint32_t)bind.bind); + + if(access.byteSize != ~0U) + staticDescriptorAccess.push_back(access); + } + + RDCASSERT(mapping.readOnlyResources.size() < 0xffff, mapping.readOnlyResources.size()); + for(uint16_t i = 0; i < mapping.readOnlyResources.size(); i++) + { + const Bindpoint &bind = mapping.readOnlyResources[i]; + + // arrayed descriptors will be handled with bindless feedback + if(bind.arraySize > 1) + continue; + + access.staticallyUnused = !bind.used; + access.type = DescriptorType::Image; + if(!refl.readOnlyResources[i].isTexture) + access.type = (refl.readOnlyResources[i].variableType.baseType == VarType::UByte || + !refl.readOnlyResources[i].variableType.members.empty()) + ? DescriptorType::Buffer + : DescriptorType::TypedBuffer; + access.index = i; + rdctie(access.byteSize, access.byteOffset) = + FindMatchingRootParameter(sig, visibility, D3D12_DESCRIPTOR_RANGE_TYPE_SRV, + (uint32_t)bind.bindset, (uint32_t)bind.bind); + + if(access.byteSize != ~0U) + staticDescriptorAccess.push_back(access); + } + + RDCASSERT(mapping.readWriteResources.size() < 0xffff, mapping.readWriteResources.size()); + for(uint16_t i = 0; i < mapping.readWriteResources.size(); i++) + { + const Bindpoint &bind = mapping.readWriteResources[i]; + + // arrayed descriptors will be handled with bindless feedback + if(bind.arraySize > 1) + continue; + + access.staticallyUnused = !bind.used; + access.type = DescriptorType::ReadWriteImage; + if(!refl.readWriteResources[i].isTexture) + access.type = (refl.readWriteResources[i].variableType.baseType == VarType::UByte || + !refl.readWriteResources[i].variableType.members.empty()) + ? DescriptorType::ReadWriteBuffer + : DescriptorType::ReadWriteTypedBuffer; + + access.index = i; + rdctie(access.byteSize, access.byteOffset) = + FindMatchingRootParameter(sig, visibility, D3D12_DESCRIPTOR_RANGE_TYPE_UAV, + (uint32_t)bind.bindset, (uint32_t)bind.bind); + + if(access.byteSize != ~0U) + staticDescriptorAccess.push_back(access); + } + } +} + UINT GetPlaneForSubresource(ID3D12Resource *res, int Subresource) { D3D12_RESOURCE_DESC desc = res->GetDesc(); diff --git a/renderdoc/driver/d3d12/d3d12_resources.h b/renderdoc/driver/d3d12/d3d12_resources.h index 74f01e5d6..8844fc8bb 100644 --- a/renderdoc/driver/d3d12/d3d12_resources.h +++ b/renderdoc/driver/d3d12/d3d12_resources.h @@ -634,6 +634,9 @@ public: D3D12_EXPANDED_PIPELINE_STATE_STREAM_DESC *graphics = NULL; D3D12_EXPANDED_PIPELINE_STATE_STREAM_DESC *compute = NULL; + rdcarray staticDescriptorAccess; + bool m_AccessProcessed = false; + void Fill(D3D12_EXPANDED_PIPELINE_STATE_STREAM_DESC &desc) { if(graphics) @@ -861,14 +864,14 @@ public: TypeEnum = Resource_PipelineState, }; - ShaderEntry *VS() { return (ShaderEntry *)graphics->VS.pShaderBytecode; } - ShaderEntry *HS() { return (ShaderEntry *)graphics->HS.pShaderBytecode; } - ShaderEntry *DS() { return (ShaderEntry *)graphics->DS.pShaderBytecode; } - ShaderEntry *GS() { return (ShaderEntry *)graphics->GS.pShaderBytecode; } - ShaderEntry *PS() { return (ShaderEntry *)graphics->PS.pShaderBytecode; } - ShaderEntry *AS() { return (ShaderEntry *)graphics->AS.pShaderBytecode; } - ShaderEntry *MS() { return (ShaderEntry *)graphics->MS.pShaderBytecode; } - ShaderEntry *CS() { return (ShaderEntry *)compute->CS.pShaderBytecode; } + ShaderEntry *VS() { return graphics ? (ShaderEntry *)graphics->VS.pShaderBytecode : NULL; } + ShaderEntry *HS() { return graphics ? (ShaderEntry *)graphics->HS.pShaderBytecode : NULL; } + ShaderEntry *DS() { return graphics ? (ShaderEntry *)graphics->DS.pShaderBytecode : NULL; } + ShaderEntry *GS() { return graphics ? (ShaderEntry *)graphics->GS.pShaderBytecode : NULL; } + ShaderEntry *PS() { return graphics ? (ShaderEntry *)graphics->PS.pShaderBytecode : NULL; } + ShaderEntry *AS() { return graphics ? (ShaderEntry *)graphics->AS.pShaderBytecode : NULL; } + ShaderEntry *MS() { return graphics ? (ShaderEntry *)graphics->MS.pShaderBytecode : NULL; } + ShaderEntry *CS() { return compute ? (ShaderEntry *)compute->CS.pShaderBytecode : NULL; } WrappedID3D12PipelineState(ID3D12PipelineState *real, WrappedID3D12Device *device) : WrappedDeviceChild12(real, device) { @@ -908,6 +911,8 @@ public: } } + void ProcessDescriptorAccess(); + ////////////////////////////// // implement ID3D12PipelineState