#include "fixtures/RHITestFixture.h" #include "XCEngine/RHI/D3D12/D3D12DescriptorSet.h" #include "XCEngine/RHI/RHIDescriptorPool.h" #include "XCEngine/RHI/RHIDescriptorSet.h" #include "XCEngine/RHI/RHIBuffer.h" #include "XCEngine/RHI/RHISampler.h" #include "XCEngine/RHI/RHIResourceView.h" #include "XCEngine/RHI/RHITexture.h" using namespace XCEngine::RHI; TEST_P(RHITestFixture, DescriptorSet_Allocate_Basic) { DescriptorPoolDesc poolDesc = {}; poolDesc.type = DescriptorHeapType::CBV_SRV_UAV; poolDesc.descriptorCount = 10; poolDesc.shaderVisible = true; RHIDescriptorPool* pool = GetDevice()->CreateDescriptorPool(poolDesc); if (pool == nullptr) { return; } DescriptorSetLayoutDesc layoutDesc = {}; layoutDesc.bindings = nullptr; layoutDesc.bindingCount = 0; RHIDescriptorSet* set = pool->AllocateSet(layoutDesc); if (set != nullptr) { EXPECT_GE(set->GetBindingCount(), 0u); set->Shutdown(); delete set; } pool->Shutdown(); delete pool; } TEST_P(RHITestFixture, DescriptorSet_Update_ResourceView) { DescriptorPoolDesc poolDesc = {}; poolDesc.type = DescriptorHeapType::CBV_SRV_UAV; poolDesc.descriptorCount = 10; poolDesc.shaderVisible = true; RHIDescriptorPool* pool = GetDevice()->CreateDescriptorPool(poolDesc); if (pool == nullptr) { return; } TextureDesc texDesc = {}; texDesc.width = 256; texDesc.height = 256; texDesc.format = static_cast(Format::R8G8B8A8_UNorm); texDesc.textureType = static_cast(TextureType::Texture2D); texDesc.sampleCount = 1; RHITexture* texture = GetDevice()->CreateTexture(texDesc); if (texture == nullptr) { pool->Shutdown(); delete pool; return; } RHIResourceView* srv = GetDevice()->CreateShaderResourceView(texture, {}); if (srv == nullptr) { texture->Shutdown(); delete texture; pool->Shutdown(); delete pool; return; } DescriptorSetLayoutDesc layoutDesc = {}; layoutDesc.bindingCount = 1; DescriptorSetLayoutBinding binding = {}; binding.binding = 0; binding.type = static_cast(DescriptorType::SRV); binding.count = 1; layoutDesc.bindings = &binding; RHIDescriptorSet* set = pool->AllocateSet(layoutDesc); if (set != nullptr) { set->Update(0, srv); set->Shutdown(); delete set; } srv->Shutdown(); delete srv; texture->Shutdown(); delete texture; pool->Shutdown(); delete pool; } TEST_P(RHITestFixture, DescriptorSet_UpdateSampler) { DescriptorPoolDesc poolDesc = {}; poolDesc.type = DescriptorHeapType::Sampler; poolDesc.descriptorCount = 10; poolDesc.shaderVisible = true; RHIDescriptorPool* pool = GetDevice()->CreateDescriptorPool(poolDesc); if (pool == nullptr) { return; } SamplerDesc samplerDesc = {}; samplerDesc.filter = static_cast(FilterMode::Linear); samplerDesc.addressU = static_cast(TextureAddressMode::Wrap); samplerDesc.addressV = static_cast(TextureAddressMode::Wrap); samplerDesc.addressW = static_cast(TextureAddressMode::Wrap); RHISampler* sampler = GetDevice()->CreateSampler(samplerDesc); if (sampler == nullptr) { pool->Shutdown(); delete pool; return; } DescriptorSetLayoutDesc layoutDesc = {}; layoutDesc.bindingCount = 1; DescriptorSetLayoutBinding binding = {}; binding.binding = 0; binding.type = static_cast(DescriptorType::Sampler); binding.count = 1; layoutDesc.bindings = &binding; RHIDescriptorSet* set = pool->AllocateSet(layoutDesc); if (set != nullptr) { set->UpdateSampler(0, sampler); set->Shutdown(); delete set; } sampler->Shutdown(); delete sampler; pool->Shutdown(); delete pool; } TEST_P(RHITestFixture, DescriptorSet_WriteConstant) { DescriptorPoolDesc poolDesc = {}; poolDesc.type = DescriptorHeapType::CBV_SRV_UAV; poolDesc.descriptorCount = 10; poolDesc.shaderVisible = false; RHIDescriptorPool* pool = GetDevice()->CreateDescriptorPool(poolDesc); if (pool == nullptr) { return; } DescriptorSetLayoutDesc layoutDesc = {}; layoutDesc.bindingCount = 1; DescriptorSetLayoutBinding binding = {}; binding.binding = 0; binding.type = static_cast(DescriptorType::CBV); binding.count = 1; layoutDesc.bindings = &binding; RHIDescriptorSet* set = pool->AllocateSet(layoutDesc); if (set != nullptr) { float testData[16] = { 1.0f, 2.0f, 3.0f, 4.0f }; set->WriteConstant(0, testData, sizeof(testData)); void* constantData = set->GetConstantBufferData(); EXPECT_NE(constantData, nullptr); size_t constantSize = set->GetConstantBufferSize(); EXPECT_GE(constantSize, sizeof(testData)); set->Shutdown(); delete set; } pool->Shutdown(); delete pool; } TEST_P(RHITestFixture, DescriptorSet_WriteConstant_PartialUpdate) { DescriptorPoolDesc poolDesc = {}; poolDesc.type = DescriptorHeapType::CBV_SRV_UAV; poolDesc.descriptorCount = 10; poolDesc.shaderVisible = false; RHIDescriptorPool* pool = GetDevice()->CreateDescriptorPool(poolDesc); if (pool == nullptr) { return; } DescriptorSetLayoutDesc layoutDesc = {}; layoutDesc.bindingCount = 1; DescriptorSetLayoutBinding binding = {}; binding.binding = 0; binding.type = static_cast(DescriptorType::CBV); binding.count = 1; layoutDesc.bindings = &binding; RHIDescriptorSet* set = pool->AllocateSet(layoutDesc); if (set != nullptr) { float offsetData[4] = { 100.0f, 200.0f }; set->WriteConstant(0, offsetData, sizeof(offsetData), 0); EXPECT_TRUE(set->IsConstantDirty()); set->MarkConstantClean(); EXPECT_FALSE(set->IsConstantDirty()); set->Shutdown(); delete set; } pool->Shutdown(); delete pool; } TEST_P(RHITestFixture, DescriptorSet_Bind_Unbind) { DescriptorPoolDesc poolDesc = {}; poolDesc.type = DescriptorHeapType::CBV_SRV_UAV; poolDesc.descriptorCount = 10; poolDesc.shaderVisible = true; RHIDescriptorPool* pool = GetDevice()->CreateDescriptorPool(poolDesc); if (pool == nullptr) { return; } DescriptorSetLayoutDesc layoutDesc = {}; layoutDesc.bindingCount = 0; RHIDescriptorSet* set = pool->AllocateSet(layoutDesc); if (set != nullptr) { set->Bind(); set->Unbind(); set->Shutdown(); delete set; } pool->Shutdown(); delete pool; } TEST_P(RHITestFixture, DescriptorSet_GetBindings) { DescriptorPoolDesc poolDesc = {}; poolDesc.type = DescriptorHeapType::CBV_SRV_UAV; poolDesc.descriptorCount = 10; poolDesc.shaderVisible = true; RHIDescriptorPool* pool = GetDevice()->CreateDescriptorPool(poolDesc); if (pool == nullptr) { return; } DescriptorSetLayoutDesc layoutDesc = {}; layoutDesc.bindingCount = 2; DescriptorSetLayoutBinding bindings[2] = {}; bindings[0].binding = 0; bindings[0].type = static_cast(DescriptorType::CBV); bindings[0].count = 1; bindings[1].binding = 1; bindings[1].type = static_cast(DescriptorType::SRV); bindings[1].count = 2; layoutDesc.bindings = bindings; RHIDescriptorSet* set = pool->AllocateSet(layoutDesc); if (set != nullptr) { EXPECT_EQ(set->GetBindingCount(), 2u); const DescriptorSetLayoutBinding* retrievedBindings = set->GetBindings(); ASSERT_NE(retrievedBindings, nullptr); EXPECT_EQ(retrievedBindings[0].binding, 0u); EXPECT_EQ(retrievedBindings[1].binding, 1u); set->Shutdown(); delete set; } pool->Shutdown(); delete pool; } TEST_P(RHITestFixture, DescriptorSet_MultipleAllocations) { DescriptorPoolDesc poolDesc = {}; poolDesc.type = DescriptorHeapType::CBV_SRV_UAV; poolDesc.descriptorCount = 100; poolDesc.shaderVisible = true; RHIDescriptorPool* pool = GetDevice()->CreateDescriptorPool(poolDesc); if (pool == nullptr) { return; } RHIDescriptorSet* sets[10] = { nullptr }; for (int i = 0; i < 10; ++i) { DescriptorSetLayoutDesc layoutDesc = {}; layoutDesc.bindingCount = 0; sets[i] = pool->AllocateSet(layoutDesc); } for (int i = 0; i < 10; ++i) { if (sets[i] != nullptr) { sets[i]->Shutdown(); delete sets[i]; } } pool->Shutdown(); delete pool; } TEST_P(RHITestFixture, DescriptorSet_FreeSet_ViaPool) { DescriptorPoolDesc poolDesc = {}; poolDesc.type = DescriptorHeapType::CBV_SRV_UAV; poolDesc.descriptorCount = 10; poolDesc.shaderVisible = true; RHIDescriptorPool* pool = GetDevice()->CreateDescriptorPool(poolDesc); if (pool == nullptr) { return; } DescriptorSetLayoutDesc layoutDesc = {}; layoutDesc.bindingCount = 0; RHIDescriptorSet* set = pool->AllocateSet(layoutDesc); if (set != nullptr) { pool->FreeSet(set); set = nullptr; } pool->Shutdown(); delete pool; } TEST_P(RHITestFixture, DescriptorSet_ConstantBufferSize) { DescriptorPoolDesc poolDesc = {}; poolDesc.type = DescriptorHeapType::CBV_SRV_UAV; poolDesc.descriptorCount = 10; poolDesc.shaderVisible = false; RHIDescriptorPool* pool = GetDevice()->CreateDescriptorPool(poolDesc); if (pool == nullptr) { return; } DescriptorSetLayoutDesc layoutDesc = {}; layoutDesc.bindingCount = 1; DescriptorSetLayoutBinding binding = {}; binding.binding = 0; binding.type = static_cast(DescriptorType::CBV); binding.count = 1; layoutDesc.bindings = &binding; RHIDescriptorSet* set = pool->AllocateSet(layoutDesc); if (set != nullptr) { float data[64] = {}; set->WriteConstant(0, data, sizeof(data)); EXPECT_GE(set->GetConstantBufferSize(), sizeof(data)); set->Shutdown(); delete set; } pool->Shutdown(); delete pool; } TEST_P(RHITestFixture, DescriptorSet_Update_BufferResourceView) { DescriptorPoolDesc poolDesc = {}; poolDesc.type = DescriptorHeapType::CBV_SRV_UAV; poolDesc.descriptorCount = 10; poolDesc.shaderVisible = true; RHIDescriptorPool* pool = GetDevice()->CreateDescriptorPool(poolDesc); ASSERT_NE(pool, nullptr); BufferDesc bufferDesc = {}; bufferDesc.size = 256; bufferDesc.stride = 16; bufferDesc.bufferType = static_cast(BufferType::Storage); RHIBuffer* buffer = GetDevice()->CreateBuffer(bufferDesc); ASSERT_NE(buffer, nullptr); ResourceViewDesc viewDesc = {}; viewDesc.dimension = ResourceViewDimension::StructuredBuffer; viewDesc.structureByteStride = 16; viewDesc.elementCount = 16; RHIResourceView* srv = GetDevice()->CreateShaderResourceView(buffer, viewDesc); ASSERT_NE(srv, nullptr); DescriptorSetLayoutBinding binding = {}; binding.binding = 0; binding.type = static_cast(DescriptorType::SRV); binding.count = 1; binding.visibility = static_cast(ShaderVisibility::All); binding.resourceDimension = ResourceViewDimension::StructuredBuffer; DescriptorSetLayoutDesc layoutDesc = {}; layoutDesc.bindingCount = 1; layoutDesc.bindings = &binding; RHIDescriptorSet* set = pool->AllocateSet(layoutDesc); ASSERT_NE(set, nullptr); ASSERT_NE(set->GetBindings(), nullptr); EXPECT_EQ(set->GetBindings()[0].resourceDimension, ResourceViewDimension::StructuredBuffer); set->Update(0, srv); set->Shutdown(); delete set; srv->Shutdown(); delete srv; buffer->Shutdown(); delete buffer; pool->Shutdown(); delete pool; } TEST_P(RHITestFixture, DescriptorSet_MultipleAllocations_AdvanceDescriptorOffsets) { DescriptorPoolDesc poolDesc = {}; poolDesc.type = DescriptorHeapType::CBV_SRV_UAV; poolDesc.descriptorCount = 8; poolDesc.shaderVisible = true; RHIDescriptorPool* pool = GetDevice()->CreateDescriptorPool(poolDesc); ASSERT_NE(pool, nullptr); DescriptorSetLayoutBinding bindings[2] = {}; bindings[0].binding = 0; bindings[0].type = static_cast(DescriptorType::SRV); bindings[0].count = 1; bindings[1].binding = 1; bindings[1].type = static_cast(DescriptorType::SRV); bindings[1].count = 1; DescriptorSetLayoutDesc layoutDesc = {}; layoutDesc.bindings = bindings; layoutDesc.bindingCount = 2; RHIDescriptorSet* firstSet = pool->AllocateSet(layoutDesc); RHIDescriptorSet* secondSet = pool->AllocateSet(layoutDesc); ASSERT_NE(firstSet, nullptr); ASSERT_NE(secondSet, nullptr); if (GetBackendType() == RHIType::D3D12) { auto* firstD3D12Set = static_cast(firstSet); auto* secondD3D12Set = static_cast(secondSet); EXPECT_EQ(firstD3D12Set->GetOffset(), 0u); EXPECT_EQ(secondD3D12Set->GetOffset(), 2u); } firstSet->Shutdown(); delete firstSet; secondSet->Shutdown(); delete secondSet; pool->Shutdown(); delete pool; } TEST_P(RHITestFixture, DescriptorSet_Update_BufferViews) { DescriptorPoolDesc poolDesc = {}; poolDesc.type = DescriptorHeapType::CBV_SRV_UAV; poolDesc.descriptorCount = 8; poolDesc.shaderVisible = true; RHIDescriptorPool* pool = GetDevice()->CreateDescriptorPool(poolDesc); ASSERT_NE(pool, nullptr); BufferDesc bufferDesc = {}; bufferDesc.size = 256; bufferDesc.stride = 16; bufferDesc.bufferType = static_cast(BufferType::Storage); RHIBuffer* buffer = GetDevice()->CreateBuffer(bufferDesc); ASSERT_NE(buffer, nullptr); ResourceViewDesc srvDesc = {}; srvDesc.dimension = ResourceViewDimension::StructuredBuffer; srvDesc.structureByteStride = 16; srvDesc.elementCount = 8; ResourceViewDesc uavDesc = {}; uavDesc.dimension = ResourceViewDimension::RawBuffer; uavDesc.firstElement = 4; uavDesc.elementCount = 8; RHIResourceView* srv = GetDevice()->CreateShaderResourceView(buffer, srvDesc); RHIResourceView* uav = GetDevice()->CreateUnorderedAccessView(buffer, uavDesc); ASSERT_NE(srv, nullptr); ASSERT_NE(uav, nullptr); DescriptorSetLayoutBinding bindings[2] = {}; bindings[0].binding = 0; bindings[0].type = static_cast(DescriptorType::SRV); bindings[0].count = 1; bindings[0].resourceDimension = ResourceViewDimension::StructuredBuffer; bindings[1].binding = 1; bindings[1].type = static_cast(DescriptorType::UAV); bindings[1].count = 1; bindings[1].resourceDimension = ResourceViewDimension::RawBuffer; DescriptorSetLayoutDesc layoutDesc = {}; layoutDesc.bindings = bindings; layoutDesc.bindingCount = 2; RHIDescriptorSet* set = pool->AllocateSet(layoutDesc); ASSERT_NE(set, nullptr); set->Update(0, srv); set->Update(1, uav); set->Bind(); set->Unbind(); set->Shutdown(); delete set; srv->Shutdown(); delete srv; uav->Shutdown(); delete uav; buffer->Shutdown(); delete buffer; pool->Shutdown(); delete pool; }