Fix D3D12 descriptor set staging for shader tables

This commit is contained in:
2026-04-12 11:49:12 +08:00
parent 7ee28a7969
commit 347d08463b
4 changed files with 81 additions and 2 deletions

View File

@@ -348,10 +348,12 @@ void D3D12CommandList::SetGraphicsDescriptorSets(
}
D3D12DescriptorHeap* heap = d3d12Set->GetHeap();
if (heap == nullptr || !heap->IsShaderVisible()) {
if (heap == nullptr) {
continue;
}
// Descriptor sets are staged in CPU-visible heaps and copied into this
// command list's shader-visible heaps immediately before binding.
if (heap->GetType() == DescriptorHeapType::CBV_SRV_UAV) {
const bool hasSrvTable = d3d12Layout->UsesSetLayouts()
? d3d12Layout->HasShaderResourceTable(setIndex)
@@ -581,10 +583,12 @@ void D3D12CommandList::SetComputeDescriptorSets(
}
D3D12DescriptorHeap* heap = d3d12Set->GetHeap();
if (heap == nullptr || !heap->IsShaderVisible()) {
if (heap == nullptr) {
continue;
}
// Descriptor sets are staged in CPU-visible heaps and copied into this
// command list's shader-visible heaps immediately before binding.
if (heap->GetType() == DescriptorHeapType::CBV_SRV_UAV) {
const bool hasSrvTable = d3d12Layout->UsesSetLayouts()
? d3d12Layout->HasShaderResourceTable(setIndex)

View File

@@ -77,6 +77,9 @@ D3D12_CPU_DESCRIPTOR_HANDLE D3D12DescriptorHeap::GetCPUDescriptorHandleForHeapSt
}
D3D12_GPU_DESCRIPTOR_HANDLE D3D12DescriptorHeap::GetGPUDescriptorHandleForHeapStart() const {
if (!m_shaderVisible || m_descriptorHeap == nullptr) {
return D3D12_GPU_DESCRIPTOR_HANDLE{0};
}
return m_descriptorHeap->GetGPUDescriptorHandleForHeapStart();
}
@@ -89,6 +92,10 @@ CPUDescriptorHandle D3D12DescriptorHeap::GetCPUDescriptorHandle(uint32_t index)
}
GPUDescriptorHandle D3D12DescriptorHeap::GetGPUDescriptorHandle(uint32_t index) {
if (!m_shaderVisible || m_descriptorHeap == nullptr) {
return GPUDescriptorHandle{0};
}
D3D12_GPU_DESCRIPTOR_HANDLE handle = m_descriptorHeap->GetGPUDescriptorHandleForHeapStart();
handle.ptr += index * m_descriptorSize;
GPUDescriptorHandle result;

View File

@@ -51,6 +51,10 @@ bool HasShaderPayload(const ShaderCompileDesc& desc) {
return !desc.source.empty() || !desc.fileName.empty() || !desc.compiledBinary.empty();
}
bool UsesTransientShaderVisibleDescriptorHeap(DescriptorHeapType type) {
return type == DescriptorHeapType::CBV_SRV_UAV || type == DescriptorHeapType::Sampler;
}
bool ShouldTraceVolumetricShaderCompile(const ShaderCompileDesc& desc) {
const std::string fileName = NarrowAscii(desc.fileName);
if (fileName.find("volumetric") != std::string::npos) {
@@ -1279,6 +1283,11 @@ RHIDescriptorPool* D3D12Device::CreateDescriptorPool(const DescriptorPoolDesc& d
auto* pool = new D3D12DescriptorHeap();
DescriptorPoolDesc poolDesc = desc;
poolDesc.device = m_device.Get();
if (UsesTransientShaderVisibleDescriptorHeap(poolDesc.type)) {
// Descriptor sets are staged in CPU-visible heaps and copied into the
// command list's transient shader-visible heaps before each bind.
poolDesc.shaderVisible = false;
}
if (pool->Initialize(poolDesc)) {
return pool;
}

View File

@@ -1,5 +1,6 @@
#include "fixtures/D3D12TestFixture.h"
#include "XCEngine/RHI/D3D12/D3D12DescriptorHeap.h"
#include "XCEngine/RHI/D3D12/D3D12DescriptorSet.h"
#include "XCEngine/RHI/D3D12/D3D12PipelineLayout.h"
#include "XCEngine/RHI/RHIDescriptorPool.h"
@@ -54,6 +55,64 @@ TEST_F(D3D12TestFixture, DescriptorSet_MixedBindings_AssignDescriptorIndicesByTy
delete pool;
}
TEST_F(D3D12TestFixture, DescriptorSet_TableBindingsUseCpuVisibleStagingHeaps) {
DescriptorPoolDesc texturePoolDesc = {};
texturePoolDesc.type = DescriptorHeapType::CBV_SRV_UAV;
texturePoolDesc.descriptorCount = 2;
texturePoolDesc.shaderVisible = true;
RHIDescriptorPool* texturePool = GetDevice()->CreateDescriptorPool(texturePoolDesc);
ASSERT_NE(texturePool, nullptr);
DescriptorSetLayoutBinding textureBinding = {};
textureBinding.binding = 0;
textureBinding.type = static_cast<uint32_t>(DescriptorType::SRV);
textureBinding.count = 1;
DescriptorSetLayoutDesc textureLayoutDesc = {};
textureLayoutDesc.bindings = &textureBinding;
textureLayoutDesc.bindingCount = 1;
RHIDescriptorSet* textureSet = texturePool->AllocateSet(textureLayoutDesc);
ASSERT_NE(textureSet, nullptr);
auto* textureD3D12Set = static_cast<D3D12DescriptorSet*>(textureSet);
ASSERT_NE(textureD3D12Set->GetHeap(), nullptr);
EXPECT_FALSE(textureD3D12Set->GetHeap()->IsShaderVisible());
DescriptorPoolDesc samplerPoolDesc = {};
samplerPoolDesc.type = DescriptorHeapType::Sampler;
samplerPoolDesc.descriptorCount = 1;
samplerPoolDesc.shaderVisible = true;
RHIDescriptorPool* samplerPool = GetDevice()->CreateDescriptorPool(samplerPoolDesc);
ASSERT_NE(samplerPool, nullptr);
DescriptorSetLayoutBinding samplerBinding = {};
samplerBinding.binding = 0;
samplerBinding.type = static_cast<uint32_t>(DescriptorType::Sampler);
samplerBinding.count = 1;
DescriptorSetLayoutDesc samplerLayoutDesc = {};
samplerLayoutDesc.bindings = &samplerBinding;
samplerLayoutDesc.bindingCount = 1;
RHIDescriptorSet* samplerSet = samplerPool->AllocateSet(samplerLayoutDesc);
ASSERT_NE(samplerSet, nullptr);
auto* samplerD3D12Set = static_cast<D3D12DescriptorSet*>(samplerSet);
ASSERT_NE(samplerD3D12Set->GetHeap(), nullptr);
EXPECT_FALSE(samplerD3D12Set->GetHeap()->IsShaderVisible());
textureSet->Shutdown();
delete textureSet;
texturePool->Shutdown();
delete texturePool;
samplerSet->Shutdown();
delete samplerSet;
samplerPool->Shutdown();
delete samplerPool;
}
TEST_F(D3D12TestFixture, DescriptorSet_MultipleConstantBuffersUploadIndependently) {
DescriptorPoolDesc poolDesc = {};
poolDesc.type = DescriptorHeapType::CBV_SRV_UAV;