308 lines
11 KiB
C++
308 lines
11 KiB
C++
#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"
|
|
#include "XCEngine/RHI/RHIEnums.h"
|
|
#include "XCEngine/RHI/RHIPipelineLayout.h"
|
|
|
|
using namespace XCEngine::RHI;
|
|
|
|
TEST_F(D3D12TestFixture, DescriptorSet_MixedBindings_AssignDescriptorIndicesByType) {
|
|
DescriptorPoolDesc poolDesc = {};
|
|
poolDesc.type = DescriptorHeapType::CBV_SRV_UAV;
|
|
poolDesc.descriptorCount = 4;
|
|
poolDesc.shaderVisible = true;
|
|
|
|
RHIDescriptorPool* pool = GetDevice()->CreateDescriptorPool(poolDesc);
|
|
ASSERT_NE(pool, nullptr);
|
|
|
|
DescriptorSetLayoutBinding bindings[3] = {};
|
|
bindings[0].binding = 2;
|
|
bindings[0].type = static_cast<uint32_t>(DescriptorType::UAV);
|
|
bindings[0].count = 1;
|
|
bindings[1].binding = 0;
|
|
bindings[1].type = static_cast<uint32_t>(DescriptorType::CBV);
|
|
bindings[1].count = 1;
|
|
bindings[2].binding = 1;
|
|
bindings[2].type = static_cast<uint32_t>(DescriptorType::SRV);
|
|
bindings[2].count = 1;
|
|
|
|
DescriptorSetLayoutDesc layoutDesc = {};
|
|
layoutDesc.bindings = bindings;
|
|
layoutDesc.bindingCount = 3;
|
|
|
|
RHIDescriptorSet* firstSet = pool->AllocateSet(layoutDesc);
|
|
RHIDescriptorSet* secondSet = pool->AllocateSet(layoutDesc);
|
|
ASSERT_NE(firstSet, nullptr);
|
|
ASSERT_NE(secondSet, nullptr);
|
|
|
|
auto* firstD3D12Set = static_cast<D3D12DescriptorSet*>(firstSet);
|
|
auto* secondD3D12Set = static_cast<D3D12DescriptorSet*>(secondSet);
|
|
EXPECT_EQ(firstD3D12Set->GetCount(), 2u);
|
|
EXPECT_EQ(firstD3D12Set->GetDescriptorIndexForBinding(1), 0u);
|
|
EXPECT_EQ(firstD3D12Set->GetDescriptorIndexForBinding(2), 1u);
|
|
EXPECT_EQ(firstD3D12Set->GetDescriptorIndexForBinding(0), UINT32_MAX);
|
|
EXPECT_EQ(firstD3D12Set->GetOffset(), 0u);
|
|
EXPECT_EQ(secondD3D12Set->GetOffset(), 2u);
|
|
|
|
firstSet->Shutdown();
|
|
delete firstSet;
|
|
secondSet->Shutdown();
|
|
delete secondSet;
|
|
pool->Shutdown();
|
|
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;
|
|
poolDesc.descriptorCount = 1;
|
|
poolDesc.shaderVisible = false;
|
|
|
|
RHIDescriptorPool* pool = GetDevice()->CreateDescriptorPool(poolDesc);
|
|
ASSERT_NE(pool, nullptr);
|
|
|
|
DescriptorSetLayoutBinding bindings[2] = {};
|
|
bindings[0].binding = 0;
|
|
bindings[0].type = static_cast<uint32_t>(DescriptorType::CBV);
|
|
bindings[0].count = 1;
|
|
bindings[1].binding = 1;
|
|
bindings[1].type = static_cast<uint32_t>(DescriptorType::CBV);
|
|
bindings[1].count = 1;
|
|
|
|
DescriptorSetLayoutDesc layoutDesc = {};
|
|
layoutDesc.bindings = bindings;
|
|
layoutDesc.bindingCount = 2;
|
|
|
|
RHIDescriptorSet* set = pool->AllocateSet(layoutDesc);
|
|
ASSERT_NE(set, nullptr);
|
|
|
|
auto* d3d12Set = static_cast<D3D12DescriptorSet*>(set);
|
|
const float firstData[16] = { 1.0f, 0.0f, 0.0f, 0.0f };
|
|
const float secondData[16] = { 2.0f, 0.0f, 0.0f, 0.0f };
|
|
d3d12Set->WriteConstant(0, firstData, sizeof(firstData));
|
|
d3d12Set->WriteConstant(1, secondData, sizeof(secondData));
|
|
|
|
ASSERT_TRUE(d3d12Set->UploadConstantBuffer(0));
|
|
ASSERT_TRUE(d3d12Set->UploadConstantBuffer(1));
|
|
|
|
const D3D12_GPU_VIRTUAL_ADDRESS firstAddress = d3d12Set->GetConstantBufferGPUAddress(0);
|
|
const D3D12_GPU_VIRTUAL_ADDRESS secondAddress = d3d12Set->GetConstantBufferGPUAddress(1);
|
|
EXPECT_NE(firstAddress, 0u);
|
|
EXPECT_NE(secondAddress, 0u);
|
|
EXPECT_NE(firstAddress, secondAddress);
|
|
|
|
set->Shutdown();
|
|
delete set;
|
|
pool->Shutdown();
|
|
delete pool;
|
|
}
|
|
|
|
TEST_F(D3D12TestFixture, PipelineLayout_TracksDistinctBindingClasses) {
|
|
RHIPipelineLayoutDesc desc = {};
|
|
desc.constantBufferCount = 2;
|
|
desc.textureCount = 1;
|
|
desc.uavCount = 1;
|
|
desc.samplerCount = 1;
|
|
|
|
RHIPipelineLayout* layout = GetDevice()->CreatePipelineLayout(desc);
|
|
ASSERT_NE(layout, nullptr);
|
|
|
|
auto* d3d12Layout = static_cast<D3D12PipelineLayout*>(layout);
|
|
EXPECT_TRUE(d3d12Layout->HasConstantBufferBinding(0));
|
|
EXPECT_TRUE(d3d12Layout->HasConstantBufferBinding(1));
|
|
EXPECT_FALSE(d3d12Layout->HasConstantBufferBinding(2));
|
|
|
|
EXPECT_TRUE(d3d12Layout->HasShaderResourceTable());
|
|
EXPECT_TRUE(d3d12Layout->HasUnorderedAccessTable());
|
|
EXPECT_TRUE(d3d12Layout->HasSamplerTable());
|
|
|
|
EXPECT_NE(
|
|
d3d12Layout->GetConstantBufferRootParameterIndex(0),
|
|
d3d12Layout->GetConstantBufferRootParameterIndex(1));
|
|
EXPECT_NE(
|
|
d3d12Layout->GetShaderResourceTableRootParameterIndex(),
|
|
d3d12Layout->GetUnorderedAccessTableRootParameterIndex());
|
|
EXPECT_NE(
|
|
d3d12Layout->GetUnorderedAccessTableRootParameterIndex(),
|
|
d3d12Layout->GetSamplerTableRootParameterIndex());
|
|
|
|
layout->Shutdown();
|
|
delete layout;
|
|
}
|
|
|
|
TEST_F(D3D12TestFixture, PipelineLayout_InfersBindingClassesFromSetLayouts) {
|
|
DescriptorSetLayoutBinding set0Bindings[1] = {};
|
|
set0Bindings[0].binding = 0;
|
|
set0Bindings[0].type = static_cast<uint32_t>(DescriptorType::CBV);
|
|
set0Bindings[0].count = 1;
|
|
|
|
DescriptorSetLayoutBinding set1Bindings[1] = {};
|
|
set1Bindings[0].binding = 0;
|
|
set1Bindings[0].type = static_cast<uint32_t>(DescriptorType::SRV);
|
|
set1Bindings[0].count = 1;
|
|
|
|
DescriptorSetLayoutBinding set2Bindings[1] = {};
|
|
set2Bindings[0].binding = 0;
|
|
set2Bindings[0].type = static_cast<uint32_t>(DescriptorType::UAV);
|
|
set2Bindings[0].count = 1;
|
|
|
|
DescriptorSetLayoutBinding set3Bindings[1] = {};
|
|
set3Bindings[0].binding = 0;
|
|
set3Bindings[0].type = static_cast<uint32_t>(DescriptorType::Sampler);
|
|
set3Bindings[0].count = 1;
|
|
|
|
DescriptorSetLayoutDesc setLayouts[4] = {};
|
|
setLayouts[0].bindings = set0Bindings;
|
|
setLayouts[0].bindingCount = 1;
|
|
setLayouts[1].bindings = set1Bindings;
|
|
setLayouts[1].bindingCount = 1;
|
|
setLayouts[2].bindings = set2Bindings;
|
|
setLayouts[2].bindingCount = 1;
|
|
setLayouts[3].bindings = set3Bindings;
|
|
setLayouts[3].bindingCount = 1;
|
|
|
|
RHIPipelineLayoutDesc desc = {};
|
|
desc.setLayouts = setLayouts;
|
|
desc.setLayoutCount = 4;
|
|
|
|
RHIPipelineLayout* layout = GetDevice()->CreatePipelineLayout(desc);
|
|
ASSERT_NE(layout, nullptr);
|
|
|
|
auto* d3d12Layout = static_cast<D3D12PipelineLayout*>(layout);
|
|
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);
|
|
EXPECT_EQ(d3d12Layout->GetDesc().samplerCount, 1u);
|
|
|
|
layout->Shutdown();
|
|
delete layout;
|
|
}
|
|
|
|
TEST_F(D3D12TestFixture, PipelineLayout_SeparatesOverlappingBindingsAcrossSetSlots) {
|
|
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;
|
|
}
|