fix(rhi): honor firstSet in set-aware d3d12 bindings
This commit is contained in:
@@ -17,6 +17,13 @@ class D3D12Device;
|
||||
|
||||
class D3D12PipelineLayout : public RHIPipelineLayout {
|
||||
public:
|
||||
struct SetRootParameterMapping {
|
||||
std::unordered_map<uint32_t, uint32_t> constantBufferRootIndices;
|
||||
uint32_t shaderResourceTableRootIndex = UINT32_MAX;
|
||||
uint32_t unorderedAccessTableRootIndex = UINT32_MAX;
|
||||
uint32_t samplerTableRootIndex = UINT32_MAX;
|
||||
};
|
||||
|
||||
D3D12PipelineLayout();
|
||||
~D3D12PipelineLayout() override;
|
||||
|
||||
@@ -27,6 +34,9 @@ public:
|
||||
void* GetNativeHandle() override { return m_rootSignature.Get(); }
|
||||
ID3D12RootSignature* GetRootSignature() const { return m_rootSignature.Get(); }
|
||||
|
||||
bool UsesSetLayouts() const { return m_desc.setLayoutCount > 0 && m_desc.setLayouts != nullptr; }
|
||||
uint32_t GetSetLayoutCount() const { return m_desc.setLayoutCount; }
|
||||
|
||||
bool HasConstantBufferBinding(uint32_t binding) const;
|
||||
uint32_t GetConstantBufferRootParameterIndex(uint32_t binding) const;
|
||||
bool HasShaderResourceTable() const;
|
||||
@@ -35,10 +45,21 @@ public:
|
||||
uint32_t GetUnorderedAccessTableRootParameterIndex() const;
|
||||
bool HasSamplerTable() const;
|
||||
uint32_t GetSamplerTableRootParameterIndex() const;
|
||||
|
||||
bool HasConstantBufferBinding(uint32_t setIndex, uint32_t binding) const;
|
||||
uint32_t GetConstantBufferRootParameterIndex(uint32_t setIndex, uint32_t binding) const;
|
||||
bool HasShaderResourceTable(uint32_t setIndex) const;
|
||||
uint32_t GetShaderResourceTableRootParameterIndex(uint32_t setIndex) const;
|
||||
bool HasUnorderedAccessTable(uint32_t setIndex) const;
|
||||
uint32_t GetUnorderedAccessTableRootParameterIndex(uint32_t setIndex) const;
|
||||
bool HasSamplerTable(uint32_t setIndex) const;
|
||||
uint32_t GetSamplerTableRootParameterIndex(uint32_t setIndex) const;
|
||||
const RHIPipelineLayoutDesc& GetDesc() const { return m_desc; }
|
||||
|
||||
private:
|
||||
bool InitializeInternal(D3D12Device* device, const RHIPipelineLayoutDesc& desc);
|
||||
bool InitializeSetAwareRootSignature();
|
||||
bool InitializeFlatRootSignature();
|
||||
|
||||
ComPtr<ID3D12RootSignature> m_rootSignature;
|
||||
D3D12Device* m_device;
|
||||
@@ -47,6 +68,7 @@ private:
|
||||
uint32_t m_shaderResourceTableRootIndex = UINT32_MAX;
|
||||
uint32_t m_unorderedAccessTableRootIndex = UINT32_MAX;
|
||||
uint32_t m_samplerTableRootIndex = UINT32_MAX;
|
||||
std::vector<SetRootParameterMapping> m_setRootParameterMappings;
|
||||
std::vector<DescriptorSetLayoutDesc> m_setLayouts;
|
||||
std::vector<std::vector<DescriptorSetLayoutBinding>> m_setLayoutBindings;
|
||||
std::vector<D3D12_ROOT_PARAMETER> m_rootParameters;
|
||||
|
||||
@@ -197,15 +197,23 @@ void D3D12CommandList::SetGraphicsDescriptorSets(
|
||||
continue;
|
||||
}
|
||||
|
||||
const uint32_t setIndex = firstSet + i;
|
||||
D3D12DescriptorSet* d3d12Set = static_cast<D3D12DescriptorSet*>(descriptorSets[i]);
|
||||
const DescriptorSetLayoutBinding* bindings = d3d12Set->GetBindings();
|
||||
for (uint32_t bindingIndex = 0; bindingIndex < d3d12Set->GetBindingCount(); ++bindingIndex) {
|
||||
const DescriptorSetLayoutBinding& binding = bindings[bindingIndex];
|
||||
const bool hasBinding = d3d12Layout->UsesSetLayouts()
|
||||
? d3d12Layout->HasConstantBufferBinding(setIndex, binding.binding)
|
||||
: d3d12Layout->HasConstantBufferBinding(binding.binding);
|
||||
const uint32_t rootParameterIndex = d3d12Layout->UsesSetLayouts()
|
||||
? d3d12Layout->GetConstantBufferRootParameterIndex(setIndex, binding.binding)
|
||||
: d3d12Layout->GetConstantBufferRootParameterIndex(binding.binding);
|
||||
|
||||
if (static_cast<DescriptorType>(binding.type) == DescriptorType::CBV &&
|
||||
d3d12Layout->HasConstantBufferBinding(binding.binding) &&
|
||||
hasBinding &&
|
||||
d3d12Set->UploadConstantBuffer(binding.binding)) {
|
||||
SetGraphicsRootConstantBufferView(
|
||||
d3d12Layout->GetConstantBufferRootParameterIndex(binding.binding),
|
||||
rootParameterIndex,
|
||||
d3d12Set->GetConstantBufferGPUAddress(binding.binding));
|
||||
}
|
||||
}
|
||||
@@ -216,28 +224,49 @@ void D3D12CommandList::SetGraphicsDescriptorSets(
|
||||
}
|
||||
|
||||
if (heap->GetType() == DescriptorHeapType::CBV_SRV_UAV) {
|
||||
if (d3d12Set->HasBindingType(DescriptorType::SRV) && d3d12Layout->HasShaderResourceTable()) {
|
||||
const bool hasSrvTable = d3d12Layout->UsesSetLayouts()
|
||||
? d3d12Layout->HasShaderResourceTable(setIndex)
|
||||
: d3d12Layout->HasShaderResourceTable();
|
||||
const bool hasUavTable = d3d12Layout->UsesSetLayouts()
|
||||
? d3d12Layout->HasUnorderedAccessTable(setIndex)
|
||||
: d3d12Layout->HasUnorderedAccessTable();
|
||||
|
||||
if (d3d12Set->HasBindingType(DescriptorType::SRV) && hasSrvTable) {
|
||||
const uint32_t srvBinding = d3d12Set->GetFirstBindingOfType(DescriptorType::SRV);
|
||||
const D3D12_GPU_DESCRIPTOR_HANDLE gpuHandle = d3d12Set->GetGPUHandleForBinding(srvBinding);
|
||||
if (gpuHandle.ptr != 0) {
|
||||
SetGraphicsRootDescriptorTable(d3d12Layout->GetShaderResourceTableRootParameterIndex(), gpuHandle);
|
||||
SetGraphicsRootDescriptorTable(
|
||||
d3d12Layout->UsesSetLayouts()
|
||||
? d3d12Layout->GetShaderResourceTableRootParameterIndex(setIndex)
|
||||
: d3d12Layout->GetShaderResourceTableRootParameterIndex(),
|
||||
gpuHandle);
|
||||
}
|
||||
}
|
||||
|
||||
if (d3d12Set->HasBindingType(DescriptorType::UAV) && d3d12Layout->HasUnorderedAccessTable()) {
|
||||
if (d3d12Set->HasBindingType(DescriptorType::UAV) && hasUavTable) {
|
||||
const uint32_t uavBinding = d3d12Set->GetFirstBindingOfType(DescriptorType::UAV);
|
||||
const D3D12_GPU_DESCRIPTOR_HANDLE gpuHandle = d3d12Set->GetGPUHandleForBinding(uavBinding);
|
||||
if (gpuHandle.ptr != 0) {
|
||||
SetGraphicsRootDescriptorTable(d3d12Layout->GetUnorderedAccessTableRootParameterIndex(), gpuHandle);
|
||||
SetGraphicsRootDescriptorTable(
|
||||
d3d12Layout->UsesSetLayouts()
|
||||
? d3d12Layout->GetUnorderedAccessTableRootParameterIndex(setIndex)
|
||||
: d3d12Layout->GetUnorderedAccessTableRootParameterIndex(),
|
||||
gpuHandle);
|
||||
}
|
||||
}
|
||||
} else if (heap->GetType() == DescriptorHeapType::Sampler &&
|
||||
HasSamplerBindings(d3d12Set) &&
|
||||
d3d12Layout->HasSamplerTable()) {
|
||||
(d3d12Layout->UsesSetLayouts()
|
||||
? d3d12Layout->HasSamplerTable(setIndex)
|
||||
: d3d12Layout->HasSamplerTable())) {
|
||||
const uint32_t samplerBinding = d3d12Set->GetFirstBindingOfType(DescriptorType::Sampler);
|
||||
const D3D12_GPU_DESCRIPTOR_HANDLE gpuHandle = d3d12Set->GetGPUHandleForBinding(samplerBinding);
|
||||
if (gpuHandle.ptr != 0) {
|
||||
SetGraphicsRootDescriptorTable(d3d12Layout->GetSamplerTableRootParameterIndex(), gpuHandle);
|
||||
SetGraphicsRootDescriptorTable(
|
||||
d3d12Layout->UsesSetLayouts()
|
||||
? d3d12Layout->GetSamplerTableRootParameterIndex(setIndex)
|
||||
: d3d12Layout->GetSamplerTableRootParameterIndex(),
|
||||
gpuHandle);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -285,15 +314,23 @@ void D3D12CommandList::SetComputeDescriptorSets(
|
||||
continue;
|
||||
}
|
||||
|
||||
const uint32_t setIndex = firstSet + i;
|
||||
D3D12DescriptorSet* d3d12Set = static_cast<D3D12DescriptorSet*>(descriptorSets[i]);
|
||||
const DescriptorSetLayoutBinding* bindings = d3d12Set->GetBindings();
|
||||
for (uint32_t bindingIndex = 0; bindingIndex < d3d12Set->GetBindingCount(); ++bindingIndex) {
|
||||
const DescriptorSetLayoutBinding& binding = bindings[bindingIndex];
|
||||
const bool hasBinding = d3d12Layout->UsesSetLayouts()
|
||||
? d3d12Layout->HasConstantBufferBinding(setIndex, binding.binding)
|
||||
: d3d12Layout->HasConstantBufferBinding(binding.binding);
|
||||
const uint32_t rootParameterIndex = d3d12Layout->UsesSetLayouts()
|
||||
? d3d12Layout->GetConstantBufferRootParameterIndex(setIndex, binding.binding)
|
||||
: d3d12Layout->GetConstantBufferRootParameterIndex(binding.binding);
|
||||
|
||||
if (static_cast<DescriptorType>(binding.type) == DescriptorType::CBV &&
|
||||
d3d12Layout->HasConstantBufferBinding(binding.binding) &&
|
||||
hasBinding &&
|
||||
d3d12Set->UploadConstantBuffer(binding.binding)) {
|
||||
m_commandList->SetComputeRootConstantBufferView(
|
||||
d3d12Layout->GetConstantBufferRootParameterIndex(binding.binding),
|
||||
rootParameterIndex,
|
||||
d3d12Set->GetConstantBufferGPUAddress(binding.binding));
|
||||
}
|
||||
}
|
||||
@@ -304,33 +341,48 @@ void D3D12CommandList::SetComputeDescriptorSets(
|
||||
}
|
||||
|
||||
if (heap->GetType() == DescriptorHeapType::CBV_SRV_UAV) {
|
||||
if (d3d12Set->HasBindingType(DescriptorType::SRV) && d3d12Layout->HasShaderResourceTable()) {
|
||||
const bool hasSrvTable = d3d12Layout->UsesSetLayouts()
|
||||
? d3d12Layout->HasShaderResourceTable(setIndex)
|
||||
: d3d12Layout->HasShaderResourceTable();
|
||||
const bool hasUavTable = d3d12Layout->UsesSetLayouts()
|
||||
? d3d12Layout->HasUnorderedAccessTable(setIndex)
|
||||
: d3d12Layout->HasUnorderedAccessTable();
|
||||
|
||||
if (d3d12Set->HasBindingType(DescriptorType::SRV) && hasSrvTable) {
|
||||
const uint32_t srvBinding = d3d12Set->GetFirstBindingOfType(DescriptorType::SRV);
|
||||
const D3D12_GPU_DESCRIPTOR_HANDLE gpuHandle = d3d12Set->GetGPUHandleForBinding(srvBinding);
|
||||
if (gpuHandle.ptr != 0) {
|
||||
m_commandList->SetComputeRootDescriptorTable(
|
||||
d3d12Layout->GetShaderResourceTableRootParameterIndex(),
|
||||
d3d12Layout->UsesSetLayouts()
|
||||
? d3d12Layout->GetShaderResourceTableRootParameterIndex(setIndex)
|
||||
: d3d12Layout->GetShaderResourceTableRootParameterIndex(),
|
||||
gpuHandle);
|
||||
}
|
||||
}
|
||||
|
||||
if (d3d12Set->HasBindingType(DescriptorType::UAV) && d3d12Layout->HasUnorderedAccessTable()) {
|
||||
if (d3d12Set->HasBindingType(DescriptorType::UAV) && hasUavTable) {
|
||||
const uint32_t uavBinding = d3d12Set->GetFirstBindingOfType(DescriptorType::UAV);
|
||||
const D3D12_GPU_DESCRIPTOR_HANDLE gpuHandle = d3d12Set->GetGPUHandleForBinding(uavBinding);
|
||||
if (gpuHandle.ptr != 0) {
|
||||
m_commandList->SetComputeRootDescriptorTable(
|
||||
d3d12Layout->GetUnorderedAccessTableRootParameterIndex(),
|
||||
d3d12Layout->UsesSetLayouts()
|
||||
? d3d12Layout->GetUnorderedAccessTableRootParameterIndex(setIndex)
|
||||
: d3d12Layout->GetUnorderedAccessTableRootParameterIndex(),
|
||||
gpuHandle);
|
||||
}
|
||||
}
|
||||
} else if (heap->GetType() == DescriptorHeapType::Sampler &&
|
||||
HasSamplerBindings(d3d12Set) &&
|
||||
d3d12Layout->HasSamplerTable()) {
|
||||
(d3d12Layout->UsesSetLayouts()
|
||||
? d3d12Layout->HasSamplerTable(setIndex)
|
||||
: d3d12Layout->HasSamplerTable())) {
|
||||
const uint32_t samplerBinding = d3d12Set->GetFirstBindingOfType(DescriptorType::Sampler);
|
||||
const D3D12_GPU_DESCRIPTOR_HANDLE gpuHandle = d3d12Set->GetGPUHandleForBinding(samplerBinding);
|
||||
if (gpuHandle.ptr != 0) {
|
||||
m_commandList->SetComputeRootDescriptorTable(
|
||||
d3d12Layout->GetSamplerTableRootParameterIndex(),
|
||||
d3d12Layout->UsesSetLayouts()
|
||||
? d3d12Layout->GetSamplerTableRootParameterIndex(setIndex)
|
||||
: d3d12Layout->GetSamplerTableRootParameterIndex(),
|
||||
gpuHandle);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#include "XCEngine/RHI/D3D12/D3D12PipelineLayout.h"
|
||||
#include "XCEngine/RHI/D3D12/D3D12Device.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace XCEngine {
|
||||
namespace RHI {
|
||||
|
||||
@@ -28,6 +30,52 @@ void AccumulateDescriptorCounts(const DescriptorSetLayoutDesc& setLayout, RHIPip
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t CountBindingEntriesOfType(const DescriptorSetLayoutDesc& setLayout, DescriptorType type) {
|
||||
uint32_t count = 0;
|
||||
for (uint32_t bindingIndex = 0; bindingIndex < setLayout.bindingCount; ++bindingIndex) {
|
||||
if (static_cast<DescriptorType>(setLayout.bindings[bindingIndex].type) == type) {
|
||||
++count;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
uint32_t SumDescriptorCountOfType(const DescriptorSetLayoutDesc& setLayout, DescriptorType type) {
|
||||
uint32_t count = 0;
|
||||
for (uint32_t bindingIndex = 0; bindingIndex < setLayout.bindingCount; ++bindingIndex) {
|
||||
const DescriptorSetLayoutBinding& binding = setLayout.bindings[bindingIndex];
|
||||
if (static_cast<DescriptorType>(binding.type) == type) {
|
||||
count += binding.count > 0 ? binding.count : 1u;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
std::vector<const DescriptorSetLayoutBinding*> GatherBindingsOfTypeSorted(
|
||||
const DescriptorSetLayoutDesc& setLayout,
|
||||
DescriptorType type) {
|
||||
std::vector<const DescriptorSetLayoutBinding*> bindings;
|
||||
bindings.reserve(setLayout.bindingCount);
|
||||
|
||||
for (uint32_t bindingIndex = 0; bindingIndex < setLayout.bindingCount; ++bindingIndex) {
|
||||
const DescriptorSetLayoutBinding& binding = setLayout.bindings[bindingIndex];
|
||||
if (static_cast<DescriptorType>(binding.type) == type) {
|
||||
bindings.push_back(&binding);
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(
|
||||
bindings.begin(),
|
||||
bindings.end(),
|
||||
[](const DescriptorSetLayoutBinding* left, const DescriptorSetLayoutBinding* right) {
|
||||
return left->binding < right->binding;
|
||||
});
|
||||
|
||||
return bindings;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
D3D12PipelineLayout::D3D12PipelineLayout()
|
||||
@@ -88,7 +136,315 @@ bool D3D12PipelineLayout::InitializeInternal(D3D12Device* device, const RHIPipel
|
||||
m_shaderResourceTableRootIndex = UINT32_MAX;
|
||||
m_unorderedAccessTableRootIndex = UINT32_MAX;
|
||||
m_samplerTableRootIndex = UINT32_MAX;
|
||||
m_setRootParameterMappings.clear();
|
||||
|
||||
if (UsesSetLayouts()) {
|
||||
if (!InitializeSetAwareRootSignature()) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!InitializeFlatRootSignature()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
D3D12_ROOT_SIGNATURE_DESC rootSigDesc = D3D12RootSignature::CreateDesc(
|
||||
m_rootParameters.empty() ? nullptr : m_rootParameters.data(),
|
||||
static_cast<uint32_t>(m_rootParameters.size()),
|
||||
nullptr, 0,
|
||||
D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT);
|
||||
|
||||
ID3D12Device* d3d12Device = device->GetDevice();
|
||||
if (!d3d12Device) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ID3DBlob* signature = nullptr;
|
||||
ID3DBlob* error = nullptr;
|
||||
|
||||
HRESULT hr = D3D12SerializeRootSignature(&rootSigDesc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, &error);
|
||||
if (FAILED(hr)) {
|
||||
if (error) {
|
||||
error->Release();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
hr = d3d12Device->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(&m_rootSignature));
|
||||
signature->Release();
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void D3D12PipelineLayout::Shutdown() {
|
||||
m_rootSignature.Reset();
|
||||
m_desc = {};
|
||||
m_rootParameters.clear();
|
||||
m_descriptorRanges.clear();
|
||||
m_constantBufferRootIndices.clear();
|
||||
m_shaderResourceTableRootIndex = UINT32_MAX;
|
||||
m_unorderedAccessTableRootIndex = UINT32_MAX;
|
||||
m_samplerTableRootIndex = UINT32_MAX;
|
||||
m_setRootParameterMappings.clear();
|
||||
m_setLayouts.clear();
|
||||
m_setLayoutBindings.clear();
|
||||
m_device = nullptr;
|
||||
}
|
||||
|
||||
bool D3D12PipelineLayout::HasConstantBufferBinding(uint32_t binding) const {
|
||||
if (UsesSetLayouts()) {
|
||||
return HasConstantBufferBinding(0, binding);
|
||||
}
|
||||
|
||||
return m_constantBufferRootIndices.find(binding) != m_constantBufferRootIndices.end();
|
||||
}
|
||||
|
||||
uint32_t D3D12PipelineLayout::GetConstantBufferRootParameterIndex(uint32_t binding) const {
|
||||
if (UsesSetLayouts()) {
|
||||
return GetConstantBufferRootParameterIndex(0, binding);
|
||||
}
|
||||
|
||||
auto it = m_constantBufferRootIndices.find(binding);
|
||||
if (it != m_constantBufferRootIndices.end()) {
|
||||
return it->second;
|
||||
}
|
||||
return UINT32_MAX;
|
||||
}
|
||||
|
||||
bool D3D12PipelineLayout::HasShaderResourceTable() const {
|
||||
if (UsesSetLayouts()) {
|
||||
return HasShaderResourceTable(0);
|
||||
}
|
||||
|
||||
return m_shaderResourceTableRootIndex != UINT32_MAX;
|
||||
}
|
||||
|
||||
uint32_t D3D12PipelineLayout::GetShaderResourceTableRootParameterIndex() const {
|
||||
if (UsesSetLayouts()) {
|
||||
return GetShaderResourceTableRootParameterIndex(0);
|
||||
}
|
||||
|
||||
return m_shaderResourceTableRootIndex;
|
||||
}
|
||||
|
||||
bool D3D12PipelineLayout::HasUnorderedAccessTable() const {
|
||||
if (UsesSetLayouts()) {
|
||||
return HasUnorderedAccessTable(0);
|
||||
}
|
||||
|
||||
return m_unorderedAccessTableRootIndex != UINT32_MAX;
|
||||
}
|
||||
|
||||
uint32_t D3D12PipelineLayout::GetUnorderedAccessTableRootParameterIndex() const {
|
||||
if (UsesSetLayouts()) {
|
||||
return GetUnorderedAccessTableRootParameterIndex(0);
|
||||
}
|
||||
|
||||
return m_unorderedAccessTableRootIndex;
|
||||
}
|
||||
|
||||
bool D3D12PipelineLayout::HasSamplerTable() const {
|
||||
if (UsesSetLayouts()) {
|
||||
return HasSamplerTable(0);
|
||||
}
|
||||
|
||||
return m_samplerTableRootIndex != UINT32_MAX;
|
||||
}
|
||||
|
||||
uint32_t D3D12PipelineLayout::GetSamplerTableRootParameterIndex() const {
|
||||
if (UsesSetLayouts()) {
|
||||
return GetSamplerTableRootParameterIndex(0);
|
||||
}
|
||||
|
||||
return m_samplerTableRootIndex;
|
||||
}
|
||||
|
||||
bool D3D12PipelineLayout::HasConstantBufferBinding(uint32_t setIndex, uint32_t binding) const {
|
||||
if (!UsesSetLayouts()) {
|
||||
return setIndex == 0 && HasConstantBufferBinding(binding);
|
||||
}
|
||||
|
||||
if (setIndex >= m_setRootParameterMappings.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return m_setRootParameterMappings[setIndex].constantBufferRootIndices.find(binding) !=
|
||||
m_setRootParameterMappings[setIndex].constantBufferRootIndices.end();
|
||||
}
|
||||
|
||||
uint32_t D3D12PipelineLayout::GetConstantBufferRootParameterIndex(uint32_t setIndex, uint32_t binding) const {
|
||||
if (!UsesSetLayouts()) {
|
||||
return setIndex == 0 ? GetConstantBufferRootParameterIndex(binding) : UINT32_MAX;
|
||||
}
|
||||
|
||||
if (setIndex >= m_setRootParameterMappings.size()) {
|
||||
return UINT32_MAX;
|
||||
}
|
||||
|
||||
const auto& rootIndices = m_setRootParameterMappings[setIndex].constantBufferRootIndices;
|
||||
auto it = rootIndices.find(binding);
|
||||
if (it != rootIndices.end()) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
return UINT32_MAX;
|
||||
}
|
||||
|
||||
bool D3D12PipelineLayout::HasShaderResourceTable(uint32_t setIndex) const {
|
||||
if (!UsesSetLayouts()) {
|
||||
return setIndex == 0 && HasShaderResourceTable();
|
||||
}
|
||||
|
||||
return setIndex < m_setRootParameterMappings.size() &&
|
||||
m_setRootParameterMappings[setIndex].shaderResourceTableRootIndex != UINT32_MAX;
|
||||
}
|
||||
|
||||
uint32_t D3D12PipelineLayout::GetShaderResourceTableRootParameterIndex(uint32_t setIndex) const {
|
||||
if (!UsesSetLayouts()) {
|
||||
return setIndex == 0 ? GetShaderResourceTableRootParameterIndex() : UINT32_MAX;
|
||||
}
|
||||
|
||||
return setIndex < m_setRootParameterMappings.size()
|
||||
? m_setRootParameterMappings[setIndex].shaderResourceTableRootIndex
|
||||
: UINT32_MAX;
|
||||
}
|
||||
|
||||
bool D3D12PipelineLayout::HasUnorderedAccessTable(uint32_t setIndex) const {
|
||||
if (!UsesSetLayouts()) {
|
||||
return setIndex == 0 && HasUnorderedAccessTable();
|
||||
}
|
||||
|
||||
return setIndex < m_setRootParameterMappings.size() &&
|
||||
m_setRootParameterMappings[setIndex].unorderedAccessTableRootIndex != UINT32_MAX;
|
||||
}
|
||||
|
||||
uint32_t D3D12PipelineLayout::GetUnorderedAccessTableRootParameterIndex(uint32_t setIndex) const {
|
||||
if (!UsesSetLayouts()) {
|
||||
return setIndex == 0 ? GetUnorderedAccessTableRootParameterIndex() : UINT32_MAX;
|
||||
}
|
||||
|
||||
return setIndex < m_setRootParameterMappings.size()
|
||||
? m_setRootParameterMappings[setIndex].unorderedAccessTableRootIndex
|
||||
: UINT32_MAX;
|
||||
}
|
||||
|
||||
bool D3D12PipelineLayout::HasSamplerTable(uint32_t setIndex) const {
|
||||
if (!UsesSetLayouts()) {
|
||||
return setIndex == 0 && HasSamplerTable();
|
||||
}
|
||||
|
||||
return setIndex < m_setRootParameterMappings.size() &&
|
||||
m_setRootParameterMappings[setIndex].samplerTableRootIndex != UINT32_MAX;
|
||||
}
|
||||
|
||||
uint32_t D3D12PipelineLayout::GetSamplerTableRootParameterIndex(uint32_t setIndex) const {
|
||||
if (!UsesSetLayouts()) {
|
||||
return setIndex == 0 ? GetSamplerTableRootParameterIndex() : UINT32_MAX;
|
||||
}
|
||||
|
||||
return setIndex < m_setRootParameterMappings.size()
|
||||
? m_setRootParameterMappings[setIndex].samplerTableRootIndex
|
||||
: UINT32_MAX;
|
||||
}
|
||||
|
||||
bool D3D12PipelineLayout::InitializeSetAwareRootSignature() {
|
||||
const uint32_t setCount = m_desc.setLayoutCount;
|
||||
m_setRootParameterMappings.assign(setCount, SetRootParameterMapping{});
|
||||
|
||||
uint32_t rootParameterCount = 0;
|
||||
uint32_t descriptorRangeCount = 0;
|
||||
for (uint32_t setIndex = 0; setIndex < setCount; ++setIndex) {
|
||||
const DescriptorSetLayoutDesc& setLayout = m_desc.setLayouts[setIndex];
|
||||
rootParameterCount += CountBindingEntriesOfType(setLayout, DescriptorType::CBV);
|
||||
rootParameterCount += SumDescriptorCountOfType(setLayout, DescriptorType::SRV) > 0 ? 1u : 0u;
|
||||
rootParameterCount += SumDescriptorCountOfType(setLayout, DescriptorType::UAV) > 0 ? 1u : 0u;
|
||||
rootParameterCount += SumDescriptorCountOfType(setLayout, DescriptorType::Sampler) > 0 ? 1u : 0u;
|
||||
|
||||
descriptorRangeCount += CountBindingEntriesOfType(setLayout, DescriptorType::SRV);
|
||||
descriptorRangeCount += CountBindingEntriesOfType(setLayout, DescriptorType::UAV);
|
||||
descriptorRangeCount += CountBindingEntriesOfType(setLayout, DescriptorType::Sampler);
|
||||
}
|
||||
|
||||
m_rootParameters.reserve(rootParameterCount);
|
||||
m_descriptorRanges.reserve(descriptorRangeCount);
|
||||
|
||||
uint32_t rootIndex = 0;
|
||||
uint32_t nextCBVRegister = 0;
|
||||
uint32_t nextSRVRegister = 0;
|
||||
uint32_t nextUAVRegister = 0;
|
||||
uint32_t nextSamplerRegister = 0;
|
||||
|
||||
for (uint32_t setIndex = 0; setIndex < setCount; ++setIndex) {
|
||||
const DescriptorSetLayoutDesc& setLayout = m_desc.setLayouts[setIndex];
|
||||
SetRootParameterMapping& setMapping = m_setRootParameterMappings[setIndex];
|
||||
|
||||
const auto cbvBindings = GatherBindingsOfTypeSorted(setLayout, DescriptorType::CBV);
|
||||
for (const DescriptorSetLayoutBinding* binding : cbvBindings) {
|
||||
m_rootParameters.push_back(D3D12RootSignature::CreateCBV(nextCBVRegister, ShaderVisibility::All, 0));
|
||||
setMapping.constantBufferRootIndices[binding->binding] = rootIndex++;
|
||||
nextCBVRegister += binding->count > 0 ? binding->count : 1u;
|
||||
}
|
||||
|
||||
const auto appendDescriptorTable =
|
||||
[this, &rootIndex](
|
||||
const DescriptorSetLayoutDesc& layout,
|
||||
DescriptorType type,
|
||||
D3D12_DESCRIPTOR_RANGE_TYPE rangeType,
|
||||
uint32_t& nextRegister,
|
||||
uint32_t& rootParameterIndex) {
|
||||
const auto bindings = GatherBindingsOfTypeSorted(layout, type);
|
||||
if (bindings.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const size_t rangeStart = m_descriptorRanges.size();
|
||||
for (const DescriptorSetLayoutBinding* binding : bindings) {
|
||||
const uint32_t descriptorCount = binding->count > 0 ? binding->count : 1u;
|
||||
m_descriptorRanges.push_back(
|
||||
D3D12RootSignature::CreateDescriptorRange(
|
||||
rangeType,
|
||||
nextRegister,
|
||||
descriptorCount,
|
||||
0));
|
||||
nextRegister += descriptorCount;
|
||||
}
|
||||
|
||||
m_rootParameters.push_back(
|
||||
D3D12RootSignature::CreateDescriptorTable(
|
||||
static_cast<uint32_t>(bindings.size()),
|
||||
m_descriptorRanges.data() + rangeStart,
|
||||
ShaderVisibility::All));
|
||||
rootParameterIndex = rootIndex++;
|
||||
};
|
||||
|
||||
appendDescriptorTable(
|
||||
setLayout,
|
||||
DescriptorType::SRV,
|
||||
D3D12_DESCRIPTOR_RANGE_TYPE_SRV,
|
||||
nextSRVRegister,
|
||||
setMapping.shaderResourceTableRootIndex);
|
||||
appendDescriptorTable(
|
||||
setLayout,
|
||||
DescriptorType::UAV,
|
||||
D3D12_DESCRIPTOR_RANGE_TYPE_UAV,
|
||||
nextUAVRegister,
|
||||
setMapping.unorderedAccessTableRootIndex);
|
||||
appendDescriptorTable(
|
||||
setLayout,
|
||||
DescriptorType::Sampler,
|
||||
D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER,
|
||||
nextSamplerRegister,
|
||||
setMapping.samplerTableRootIndex);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool D3D12PipelineLayout::InitializeFlatRootSignature() {
|
||||
const RHIPipelineLayoutDesc& normalizedDesc = m_desc;
|
||||
|
||||
const uint32_t rootParameterCount =
|
||||
@@ -143,87 +499,8 @@ bool D3D12PipelineLayout::InitializeInternal(D3D12Device* device, const RHIPipel
|
||||
rootIndex++;
|
||||
}
|
||||
|
||||
D3D12_ROOT_SIGNATURE_DESC rootSigDesc = D3D12RootSignature::CreateDesc(
|
||||
m_rootParameters.empty() ? nullptr : m_rootParameters.data(),
|
||||
static_cast<uint32_t>(m_rootParameters.size()),
|
||||
nullptr, 0,
|
||||
D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT);
|
||||
|
||||
ID3D12Device* d3d12Device = device->GetDevice();
|
||||
if (!d3d12Device) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ID3DBlob* signature = nullptr;
|
||||
ID3DBlob* error = nullptr;
|
||||
|
||||
HRESULT hr = D3D12SerializeRootSignature(&rootSigDesc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, &error);
|
||||
if (FAILED(hr)) {
|
||||
if (error) {
|
||||
error->Release();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
hr = d3d12Device->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(&m_rootSignature));
|
||||
signature->Release();
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void D3D12PipelineLayout::Shutdown() {
|
||||
m_rootSignature.Reset();
|
||||
m_desc = {};
|
||||
m_rootParameters.clear();
|
||||
m_descriptorRanges.clear();
|
||||
m_constantBufferRootIndices.clear();
|
||||
m_shaderResourceTableRootIndex = UINT32_MAX;
|
||||
m_unorderedAccessTableRootIndex = UINT32_MAX;
|
||||
m_samplerTableRootIndex = UINT32_MAX;
|
||||
m_setLayouts.clear();
|
||||
m_setLayoutBindings.clear();
|
||||
m_device = nullptr;
|
||||
}
|
||||
|
||||
bool D3D12PipelineLayout::HasConstantBufferBinding(uint32_t binding) const {
|
||||
return m_constantBufferRootIndices.find(binding) != m_constantBufferRootIndices.end();
|
||||
}
|
||||
|
||||
uint32_t D3D12PipelineLayout::GetConstantBufferRootParameterIndex(uint32_t binding) const {
|
||||
auto it = m_constantBufferRootIndices.find(binding);
|
||||
if (it != m_constantBufferRootIndices.end()) {
|
||||
return it->second;
|
||||
}
|
||||
return UINT32_MAX;
|
||||
}
|
||||
|
||||
bool D3D12PipelineLayout::HasShaderResourceTable() const {
|
||||
return m_shaderResourceTableRootIndex != UINT32_MAX;
|
||||
}
|
||||
|
||||
uint32_t D3D12PipelineLayout::GetShaderResourceTableRootParameterIndex() const {
|
||||
return m_shaderResourceTableRootIndex;
|
||||
}
|
||||
|
||||
bool D3D12PipelineLayout::HasUnorderedAccessTable() const {
|
||||
return m_unorderedAccessTableRootIndex != UINT32_MAX;
|
||||
}
|
||||
|
||||
uint32_t D3D12PipelineLayout::GetUnorderedAccessTableRootParameterIndex() const {
|
||||
return m_unorderedAccessTableRootIndex;
|
||||
}
|
||||
|
||||
bool D3D12PipelineLayout::HasSamplerTable() const {
|
||||
return m_samplerTableRootIndex != UINT32_MAX;
|
||||
}
|
||||
|
||||
uint32_t D3D12PipelineLayout::GetSamplerTableRootParameterIndex() const {
|
||||
return m_samplerTableRootIndex;
|
||||
}
|
||||
|
||||
} // namespace RHI
|
||||
} // namespace XCEngine
|
||||
|
||||
@@ -44,6 +44,8 @@ struct MatrixBufferData {
|
||||
constexpr float kSphereRadius = 1.0f;
|
||||
constexpr int kSphereSegments = 32;
|
||||
constexpr float kPi = 3.14159265358979323846f;
|
||||
constexpr uint32_t kSphereDescriptorFirstSet = 1;
|
||||
constexpr uint32_t kSphereDescriptorSetCount = 4;
|
||||
|
||||
std::filesystem::path GetExecutableDirectory() {
|
||||
char exePath[MAX_PATH] = {};
|
||||
@@ -452,10 +454,15 @@ void SphereTest::InitializeSphereResources() {
|
||||
ASSERT_NE(mSamplerSet, nullptr);
|
||||
mSamplerSet->UpdateSampler(0, mSampler);
|
||||
|
||||
DescriptorSetLayoutDesc setLayouts[kSphereDescriptorSetCount] = {};
|
||||
// Reserve set0 so the integration test exercises non-zero firstSet binding.
|
||||
setLayouts[1] = constantLayoutDesc;
|
||||
setLayouts[2] = textureLayoutDesc;
|
||||
setLayouts[3] = samplerLayoutDesc;
|
||||
|
||||
RHIPipelineLayoutDesc pipelineLayoutDesc = {};
|
||||
pipelineLayoutDesc.constantBufferCount = 1;
|
||||
pipelineLayoutDesc.textureCount = 1;
|
||||
pipelineLayoutDesc.samplerCount = 1;
|
||||
pipelineLayoutDesc.setLayouts = setLayouts;
|
||||
pipelineLayoutDesc.setLayoutCount = kSphereDescriptorSetCount;
|
||||
mPipelineLayout = GetDevice()->CreatePipelineLayout(pipelineLayoutDesc);
|
||||
ASSERT_NE(mPipelineLayout, nullptr);
|
||||
|
||||
@@ -584,7 +591,7 @@ void SphereTest::RenderFrame() {
|
||||
|
||||
cmdList->SetPipelineState(mPipelineState);
|
||||
RHIDescriptorSet* descriptorSets[] = { mConstantSet, mTextureSet, mSamplerSet };
|
||||
cmdList->SetGraphicsDescriptorSets(0, 3, descriptorSets, mPipelineLayout);
|
||||
cmdList->SetGraphicsDescriptorSets(kSphereDescriptorFirstSet, 3, descriptorSets, mPipelineLayout);
|
||||
cmdList->SetPrimitiveTopology(PrimitiveTopology::TriangleList);
|
||||
|
||||
RHIResourceView* vertexBuffers[] = { mVertexBufferView };
|
||||
|
||||
@@ -283,10 +283,12 @@ TEST_P(RHITestFixture, PipelineLayout_D3D12InfersBindingClassesFromSetLayouts) {
|
||||
ASSERT_NE(layout, nullptr);
|
||||
|
||||
auto* d3d12Layout = static_cast<D3D12PipelineLayout*>(layout);
|
||||
EXPECT_TRUE(d3d12Layout->HasConstantBufferBinding(0));
|
||||
EXPECT_TRUE(d3d12Layout->HasShaderResourceTable());
|
||||
EXPECT_TRUE(d3d12Layout->HasUnorderedAccessTable());
|
||||
EXPECT_TRUE(d3d12Layout->HasSamplerTable());
|
||||
EXPECT_TRUE(d3d12Layout->UsesSetLayouts());
|
||||
EXPECT_EQ(d3d12Layout->GetSetLayoutCount(), 4u);
|
||||
EXPECT_TRUE(d3d12Layout->HasConstantBufferBinding(0, 0));
|
||||
EXPECT_TRUE(d3d12Layout->HasShaderResourceTable(1));
|
||||
EXPECT_TRUE(d3d12Layout->HasUnorderedAccessTable(2));
|
||||
EXPECT_TRUE(d3d12Layout->HasSamplerTable(3));
|
||||
EXPECT_EQ(d3d12Layout->GetDesc().constantBufferCount, 1u);
|
||||
EXPECT_EQ(d3d12Layout->GetDesc().textureCount, 1u);
|
||||
EXPECT_EQ(d3d12Layout->GetDesc().uavCount, 1u);
|
||||
@@ -295,3 +297,68 @@ TEST_P(RHITestFixture, PipelineLayout_D3D12InfersBindingClassesFromSetLayouts) {
|
||||
layout->Shutdown();
|
||||
delete layout;
|
||||
}
|
||||
|
||||
TEST_P(RHITestFixture, PipelineLayout_D3D12SeparatesOverlappingBindingsAcrossSetSlots) {
|
||||
if (GetBackendType() != RHIType::D3D12) {
|
||||
GTEST_SKIP() << "D3D12-specific root parameter verification";
|
||||
}
|
||||
|
||||
DescriptorSetLayoutBinding set0Bindings[2] = {};
|
||||
set0Bindings[0].binding = 0;
|
||||
set0Bindings[0].type = static_cast<uint32_t>(DescriptorType::CBV);
|
||||
set0Bindings[0].count = 1;
|
||||
set0Bindings[1].binding = 0;
|
||||
set0Bindings[1].type = static_cast<uint32_t>(DescriptorType::SRV);
|
||||
set0Bindings[1].count = 1;
|
||||
|
||||
DescriptorSetLayoutBinding set1Bindings[2] = {};
|
||||
set1Bindings[0].binding = 0;
|
||||
set1Bindings[0].type = static_cast<uint32_t>(DescriptorType::CBV);
|
||||
set1Bindings[0].count = 1;
|
||||
set1Bindings[1].binding = 0;
|
||||
set1Bindings[1].type = static_cast<uint32_t>(DescriptorType::SRV);
|
||||
set1Bindings[1].count = 1;
|
||||
|
||||
DescriptorSetLayoutBinding set2Bindings[1] = {};
|
||||
set2Bindings[0].binding = 0;
|
||||
set2Bindings[0].type = static_cast<uint32_t>(DescriptorType::Sampler);
|
||||
set2Bindings[0].count = 1;
|
||||
|
||||
DescriptorSetLayoutDesc setLayouts[3] = {};
|
||||
setLayouts[0].bindings = set0Bindings;
|
||||
setLayouts[0].bindingCount = 2;
|
||||
setLayouts[1].bindings = set1Bindings;
|
||||
setLayouts[1].bindingCount = 2;
|
||||
setLayouts[2].bindings = set2Bindings;
|
||||
setLayouts[2].bindingCount = 1;
|
||||
|
||||
RHIPipelineLayoutDesc desc = {};
|
||||
desc.setLayouts = setLayouts;
|
||||
desc.setLayoutCount = 3;
|
||||
|
||||
RHIPipelineLayout* layout = GetDevice()->CreatePipelineLayout(desc);
|
||||
ASSERT_NE(layout, nullptr);
|
||||
|
||||
auto* d3d12Layout = static_cast<D3D12PipelineLayout*>(layout);
|
||||
EXPECT_TRUE(d3d12Layout->UsesSetLayouts());
|
||||
EXPECT_TRUE(d3d12Layout->HasConstantBufferBinding(0, 0));
|
||||
EXPECT_TRUE(d3d12Layout->HasConstantBufferBinding(1, 0));
|
||||
EXPECT_FALSE(d3d12Layout->HasConstantBufferBinding(2, 0));
|
||||
EXPECT_NE(
|
||||
d3d12Layout->GetConstantBufferRootParameterIndex(0, 0),
|
||||
d3d12Layout->GetConstantBufferRootParameterIndex(1, 0));
|
||||
|
||||
EXPECT_TRUE(d3d12Layout->HasShaderResourceTable(0));
|
||||
EXPECT_TRUE(d3d12Layout->HasShaderResourceTable(1));
|
||||
EXPECT_FALSE(d3d12Layout->HasShaderResourceTable(2));
|
||||
EXPECT_NE(
|
||||
d3d12Layout->GetShaderResourceTableRootParameterIndex(0),
|
||||
d3d12Layout->GetShaderResourceTableRootParameterIndex(1));
|
||||
|
||||
EXPECT_FALSE(d3d12Layout->HasSamplerTable(0));
|
||||
EXPECT_FALSE(d3d12Layout->HasSamplerTable(1));
|
||||
EXPECT_TRUE(d3d12Layout->HasSamplerTable(2));
|
||||
|
||||
layout->Shutdown();
|
||||
delete layout;
|
||||
}
|
||||
|
||||
@@ -174,6 +174,7 @@ tests/RHI/integration/
|
||||
- `sphere_opengl.ppm`
|
||||
5. 两个后端都必须与同一张 `GT.ppm` 做比对。
|
||||
6. 新测试如果暴露抽象层缺口,应先补 RHI,再补测试。
|
||||
7. 至少保留一个场景覆盖 `firstSet != 0` 的描述符绑定路径,当前由 `sphere` 负责验证。
|
||||
|
||||
### 6.3 命名
|
||||
|
||||
|
||||
Reference in New Issue
Block a user