Generate baked per-pipeline static descriptor access on D3D12

This commit is contained in:
baldurk
2024-03-07 16:58:43 +00:00
parent 50091dcffc
commit 55f0cd0561
3 changed files with 234 additions and 9 deletions
+51 -1
View File
@@ -2429,7 +2429,57 @@ rdcarray<SamplerDescriptor> D3D12Replay::GetSamplerDescriptors(ResourceId descri
rdcarray<DescriptorAccess> 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<WrappedID3D12PipelineState>(rs.pipe);
rdcarray<DescriptorAccess> ret;
if(pipe)
{
pipe->ProcessDescriptorAccess();
ret = pipe->staticDescriptorAccess;
WrappedID3D12DescriptorHeap *resourceHeap = NULL;
WrappedID3D12DescriptorHeap *samplerHeap = NULL;
for(ResourceId id : rs.heaps)
{
WrappedID3D12DescriptorHeap *heap =
(WrappedID3D12DescriptorHeap *)rm->GetCurrentAs<ID3D12DescriptorHeap>(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)
+170
View File
@@ -661,6 +661,176 @@ void WrappedID3D12PipelineState::ShaderEntry::BuildReflection()
m_Details->resourceId = GetResourceID();
}
rdcpair<uint32_t, uint32_t> 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 &param = 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();
+13 -8
View File
@@ -634,6 +634,9 @@ public:
D3D12_EXPANDED_PIPELINE_STATE_STREAM_DESC *graphics = NULL;
D3D12_EXPANDED_PIPELINE_STATE_STREAM_DESC *compute = NULL;
rdcarray<DescriptorAccess> 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