From 8f76564ded4a4bd4daa8d78600c330ee713a4a51 Mon Sep 17 00:00:00 2001 From: ssdfasd <2156608475@qq.com> Date: Wed, 25 Mar 2026 20:50:56 +0800 Subject: [PATCH] test: Add new RHI unit tests for capabilities, views, screenshot, descriptor set and pipeline layout --- tests/RHI/unit/test_capabilities.cpp | 107 +++++++ tests/RHI/unit/test_descriptor_set.cpp | 362 ++++++++++++++++++++++++ tests/RHI/unit/test_pipeline_layout.cpp | 154 ++++++++++ tests/RHI/unit/test_screenshot.cpp | 63 +++++ tests/RHI/unit/test_views.cpp | 247 ++++++++++++++++ 5 files changed, 933 insertions(+) create mode 100644 tests/RHI/unit/test_capabilities.cpp create mode 100644 tests/RHI/unit/test_descriptor_set.cpp create mode 100644 tests/RHI/unit/test_pipeline_layout.cpp create mode 100644 tests/RHI/unit/test_screenshot.cpp create mode 100644 tests/RHI/unit/test_views.cpp diff --git a/tests/RHI/unit/test_capabilities.cpp b/tests/RHI/unit/test_capabilities.cpp new file mode 100644 index 00000000..6978a3cc --- /dev/null +++ b/tests/RHI/unit/test_capabilities.cpp @@ -0,0 +1,107 @@ +#include "fixtures/RHITestFixture.h" +#include "XCEngine/RHI/RHICapabilities.h" + +using namespace XCEngine::RHI; + +TEST_P(RHITestFixture, Capabilities_Query_Basic) { + const RHICapabilities& caps = GetDevice()->GetCapabilities(); + + EXPECT_GE(caps.maxTexture2DSize, 1u); + EXPECT_GE(caps.maxTexture3DSize, 1u); + EXPECT_GE(caps.maxTextureCubeSize, 1u); + EXPECT_GE(caps.maxRenderTargets, 1u); + EXPECT_GE(caps.maxViewports, 1u); + EXPECT_GE(caps.maxVertexAttribs, 1u); + EXPECT_GE(caps.maxColorAttachments, 1u); +} + +TEST_P(RHITestFixture, Capabilities_Query_Version) { + const RHICapabilities& caps = GetDevice()->GetCapabilities(); + + EXPECT_GE(caps.majorVersion, 0); + EXPECT_GE(caps.minorVersion, 0); +} + +TEST_P(RHITestFixture, Capabilities_Query_ShaderModel) { + const RHICapabilities& caps = GetDevice()->GetCapabilities(); + + if (GetBackendType() == RHIType::D3D12) { + EXPECT_FALSE(caps.shaderModel.empty()); + } +} + +TEST_P(RHITestFixture, Capabilities_Query_Anisotropy) { + const RHICapabilities& caps = GetDevice()->GetCapabilities(); + + if (caps.maxAnisotropy > 1) { + EXPECT_GE(caps.maxAnisotropy, 2u); + EXPECT_LE(caps.maxAnisotropy, 16u); + } +} + +TEST_P(RHITestFixture, Capabilities_Query_LineWidth) { + const RHICapabilities& caps = GetDevice()->GetCapabilities(); + + EXPECT_GE(caps.minSmoothedLineWidth, 1.0f); + EXPECT_GE(caps.maxSmoothedLineWidth, 1.0f); + EXPECT_GE(caps.maxLineWidth, 1.0f); +} + +TEST_P(RHITestFixture, Capabilities_Query_PointSize) { + const RHICapabilities& caps = GetDevice()->GetCapabilities(); + + EXPECT_GE(caps.minPointSize, 1.0f); + EXPECT_GE(caps.maxPointSize, 1.0f); + EXPECT_GE(caps.maxPointSizeAA, 1.0f); +} + +TEST_P(RHITestFixture, Capabilities_FeatureFlags) { + const RHICapabilities& caps = GetDevice()->GetCapabilities(); + + if (GetBackendType() == RHIType::D3D12) { + EXPECT_TRUE(caps.bSupportsComputeShaders); + } +} + +TEST_P(RHITestFixture, Capabilities_Query_DeviceInfo) { + const RHIDeviceInfo& info = GetDevice()->GetDeviceInfo(); + + EXPECT_FALSE(info.vendor.empty()); + EXPECT_FALSE(info.renderer.empty()); + EXPECT_GT(info.vendorId, 0u); + EXPECT_GT(info.deviceId, 0u); +} + +TEST_P(RHITestFixture, Capabilities_DeviceInfo_Memory) { + const RHIDeviceInfo& info = GetDevice()->GetDeviceInfo(); + + if (!info.isSoftware) { + EXPECT_GT(info.dedicatedVideoMemory, 0ull); + } +} + +TEST_P(RHITestFixture, Capabilities_MaxTextureSizes) { + const RHICapabilities& caps = GetDevice()->GetCapabilities(); + + EXPECT_GE(caps.maxTexture2DSize, 2048u); + EXPECT_GE(caps.maxTextureCubeSize, 2048u); + + if (GetBackendType() == RHIType::D3D12) { + EXPECT_GE(caps.maxTexture3DSize, 256u); + } +} + +TEST_P(RHITestFixture, Capabilities_RenderTargets) { + const RHICapabilities& caps = GetDevice()->GetCapabilities(); + + EXPECT_GE(caps.maxRenderTargets, 1u); + EXPECT_GE(caps.maxColorAttachments, 1u); + EXPECT_LE(caps.maxRenderTargets, 8u); +} + +TEST_P(RHITestFixture, Capabilities_ConstantBuffer) { + const RHICapabilities& caps = GetDevice()->GetCapabilities(); + + EXPECT_GT(caps.maxConstantBufferSize, 0u); + EXPECT_LE(caps.maxConstantBufferSize, 128 * 1024 * 1024u); +} \ No newline at end of file diff --git a/tests/RHI/unit/test_descriptor_set.cpp b/tests/RHI/unit/test_descriptor_set.cpp new file mode 100644 index 00000000..12d0b2dd --- /dev/null +++ b/tests/RHI/unit/test_descriptor_set.cpp @@ -0,0 +1,362 @@ +#include "fixtures/RHITestFixture.h" +#include "XCEngine/RHI/RHIDescriptorPool.h" +#include "XCEngine/RHI/RHIDescriptorSet.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; +} \ No newline at end of file diff --git a/tests/RHI/unit/test_pipeline_layout.cpp b/tests/RHI/unit/test_pipeline_layout.cpp new file mode 100644 index 00000000..b474504d --- /dev/null +++ b/tests/RHI/unit/test_pipeline_layout.cpp @@ -0,0 +1,154 @@ +#include "fixtures/RHITestFixture.h" +#include "XCEngine/RHI/RHIPipelineLayout.h" +#include "XCEngine/RHI/RHIDescriptorSet.h" + +using namespace XCEngine::RHI; + +TEST_P(RHITestFixture, PipelineLayout_Create_Basic) { + RHIPipelineLayoutDesc desc = {}; + desc.constantBufferCount = 1; + desc.textureCount = 0; + desc.samplerCount = 0; + desc.uavCount = 0; + + RHIPipelineLayout* layout = GetDevice()->CreatePipelineLayout(desc); + if (layout != nullptr) { + EXPECT_NE(layout->GetNativeHandle(), nullptr); + layout->Shutdown(); + delete layout; + } +} + +TEST_P(RHITestFixture, PipelineLayout_Create_WithTextures) { + RHIPipelineLayoutDesc desc = {}; + desc.constantBufferCount = 0; + desc.textureCount = 4; + desc.samplerCount = 0; + desc.uavCount = 0; + + RHIPipelineLayout* layout = GetDevice()->CreatePipelineLayout(desc); + if (layout != nullptr) { + EXPECT_NE(layout->GetNativeHandle(), nullptr); + layout->Shutdown(); + delete layout; + } +} + +TEST_P(RHITestFixture, PipelineLayout_Create_WithSamplers) { + RHIPipelineLayoutDesc desc = {}; + desc.constantBufferCount = 0; + desc.textureCount = 0; + desc.samplerCount = 2; + desc.uavCount = 0; + + RHIPipelineLayout* layout = GetDevice()->CreatePipelineLayout(desc); + if (layout != nullptr) { + EXPECT_NE(layout->GetNativeHandle(), nullptr); + layout->Shutdown(); + delete layout; + } +} + +TEST_P(RHITestFixture, PipelineLayout_Create_WithUAVs) { + RHIPipelineLayoutDesc desc = {}; + desc.constantBufferCount = 0; + desc.textureCount = 0; + desc.samplerCount = 0; + desc.uavCount = 3; + + RHIPipelineLayout* layout = GetDevice()->CreatePipelineLayout(desc); + if (layout != nullptr) { + EXPECT_NE(layout->GetNativeHandle(), nullptr); + layout->Shutdown(); + delete layout; + } +} + +TEST_P(RHITestFixture, PipelineLayout_Create_Complex) { + RHIPipelineLayoutDesc desc = {}; + desc.constantBufferCount = 2; + desc.textureCount = 4; + desc.samplerCount = 2; + desc.uavCount = 1; + + RHIPipelineLayout* layout = GetDevice()->CreatePipelineLayout(desc); + if (layout != nullptr) { + EXPECT_NE(layout->GetNativeHandle(), nullptr); + layout->Shutdown(); + delete layout; + } +} + +TEST_P(RHITestFixture, PipelineLayout_Create_ZeroCounts) { + RHIPipelineLayoutDesc desc = {}; + desc.constantBufferCount = 0; + desc.textureCount = 0; + desc.samplerCount = 0; + desc.uavCount = 0; + + RHIPipelineLayout* layout = GetDevice()->CreatePipelineLayout(desc); + if (layout != nullptr) { + EXPECT_NE(layout->GetNativeHandle(), nullptr); + layout->Shutdown(); + delete layout; + } +} + +TEST_P(RHITestFixture, PipelineLayout_Shutdown) { + RHIPipelineLayoutDesc desc = {}; + desc.constantBufferCount = 1; + desc.textureCount = 2; + desc.samplerCount = 1; + + RHIPipelineLayout* layout = GetDevice()->CreatePipelineLayout(desc); + if (layout != nullptr) { + layout->Shutdown(); + delete layout; + } +} + +TEST_P(RHITestFixture, PipelineLayout_DoubleShutdown) { + RHIPipelineLayoutDesc desc = {}; + desc.constantBufferCount = 1; + + RHIPipelineLayout* layout = GetDevice()->CreatePipelineLayout(desc); + if (layout != nullptr) { + layout->Shutdown(); + layout->Shutdown(); + delete layout; + } +} + +TEST_P(RHITestFixture, PipelineLayout_DescriptorSetAllocation) { + RHIPipelineLayoutDesc layoutDesc = {}; + layoutDesc.constantBufferCount = 1; + layoutDesc.textureCount = 2; + + RHIPipelineLayout* layout = GetDevice()->CreatePipelineLayout(layoutDesc); + if (layout == nullptr) { + return; + } + + DescriptorPoolDesc poolDesc = {}; + poolDesc.type = DescriptorHeapType::CBV_SRV_UAV; + poolDesc.descriptorCount = 10; + poolDesc.shaderVisible = true; + + RHIDescriptorPool* pool = GetDevice()->CreateDescriptorPool(poolDesc); + if (pool != nullptr) { + DescriptorSetLayoutDesc setDesc = {}; + setDesc.bindingCount = 0; + + RHIDescriptorSet* set = pool->AllocateSet(setDesc); + if (set != nullptr) { + EXPECT_GE(set->GetBindingCount(), 0u); + set->Shutdown(); + delete set; + } + pool->Shutdown(); + delete pool; + } + + layout->Shutdown(); + delete layout; +} \ No newline at end of file diff --git a/tests/RHI/unit/test_screenshot.cpp b/tests/RHI/unit/test_screenshot.cpp new file mode 100644 index 00000000..6bc94a27 --- /dev/null +++ b/tests/RHI/unit/test_screenshot.cpp @@ -0,0 +1,63 @@ +#include "fixtures/RHITestFixture.h" +#include "XCEngine/RHI/RHIScreenshot.h" +#include "XCEngine/RHI/RHISwapChain.h" + +using namespace XCEngine::RHI; + +TEST_P(RHITestFixture, Screenshot_Create) { + RHIScreenshot* screenshot = RHIScreenshot::Create(GetBackendType()); + if (screenshot != nullptr) { + screenshot->Shutdown(); + delete screenshot; + } +} + +TEST_P(RHITestFixture, Screenshot_Capture_Basic) { + SwapChainDesc desc = {}; + desc.windowHandle = GetWindowHandle(); + desc.width = 800; + desc.height = 600; + desc.bufferCount = 2; + desc.format = Format::R8G8B8A8_UNorm; + + RHISwapChain* swapChain = GetDevice()->CreateSwapChain(desc); + if (swapChain == nullptr) { + return; + } + + RHIScreenshot* screenshot = RHIScreenshot::Create(GetBackendType()); + if (screenshot != nullptr) { + screenshot->Capture(GetDevice(), swapChain, "test_capture.ppm"); + screenshot->Shutdown(); + delete screenshot; + } + + swapChain->Shutdown(); + delete swapChain; +} + +TEST_P(RHITestFixture, Screenshot_Capture_WithPresent) { + SwapChainDesc desc = {}; + desc.windowHandle = GetWindowHandle(); + desc.width = 800; + desc.height = 600; + desc.bufferCount = 2; + desc.format = Format::R8G8B8A8_UNorm; + + RHISwapChain* swapChain = GetDevice()->CreateSwapChain(desc); + if (swapChain == nullptr) { + return; + } + + swapChain->Present(0, 0); + + RHIScreenshot* screenshot = RHIScreenshot::Create(GetBackendType()); + if (screenshot != nullptr) { + screenshot->Capture(GetDevice(), swapChain, "test_capture2.ppm"); + screenshot->Shutdown(); + delete screenshot; + } + + swapChain->Shutdown(); + delete swapChain; +} \ No newline at end of file diff --git a/tests/RHI/unit/test_views.cpp b/tests/RHI/unit/test_views.cpp new file mode 100644 index 00000000..bd0ed8fc --- /dev/null +++ b/tests/RHI/unit/test_views.cpp @@ -0,0 +1,247 @@ +#include "fixtures/RHITestFixture.h" +#include "XCEngine/RHI/RHIResourceView.h" +#include "XCEngine/RHI/RHITexture.h" + +using namespace XCEngine::RHI; + +TEST_P(RHITestFixture, Device_CreateRenderTargetView) { + 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) { + return; + } + + ResourceViewDesc viewDesc = {}; + viewDesc.format = static_cast(Format::R8G8B8A8_UNorm); + viewDesc.dimension = ResourceViewDimension::Texture2D; + + RHIResourceView* rtv = GetDevice()->CreateRenderTargetView(texture, viewDesc); + if (rtv != nullptr) { + EXPECT_TRUE(rtv->IsValid()); + EXPECT_EQ(rtv->GetViewType(), ResourceViewType::RenderTarget); + EXPECT_EQ(rtv->GetFormat(), Format::R8G8B8A8_UNorm); + rtv->Shutdown(); + delete rtv; + } + + texture->Shutdown(); + delete texture; +} + +TEST_P(RHITestFixture, Device_CreateDepthStencilView) { + TextureDesc texDesc = {}; + texDesc.width = 256; + texDesc.height = 256; + texDesc.format = static_cast(Format::D24_UNorm_S8_UInt); + texDesc.textureType = static_cast(TextureType::Texture2D); + texDesc.sampleCount = 1; + + RHITexture* texture = GetDevice()->CreateTexture(texDesc); + if (texture == nullptr) { + return; + } + + ResourceViewDesc viewDesc = {}; + viewDesc.format = static_cast(Format::D24_UNorm_S8_UInt); + viewDesc.dimension = ResourceViewDimension::Texture2D; + + RHIResourceView* dsv = GetDevice()->CreateDepthStencilView(texture, viewDesc); + if (dsv != nullptr) { + EXPECT_TRUE(dsv->IsValid()); + EXPECT_EQ(dsv->GetViewType(), ResourceViewType::DepthStencil); + dsv->Shutdown(); + delete dsv; + } + + texture->Shutdown(); + delete texture; +} + +TEST_P(RHITestFixture, Device_CreateShaderResourceView) { + 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) { + return; + } + + ResourceViewDesc viewDesc = {}; + viewDesc.format = static_cast(Format::R8G8B8A8_UNorm); + viewDesc.dimension = ResourceViewDimension::Texture2D; + + RHIResourceView* srv = GetDevice()->CreateShaderResourceView(texture, viewDesc); + if (srv != nullptr) { + EXPECT_TRUE(srv->IsValid()); + EXPECT_EQ(srv->GetViewType(), ResourceViewType::ShaderResource); + srv->Shutdown(); + delete srv; + } + + texture->Shutdown(); + delete texture; +} + +TEST_P(RHITestFixture, Device_CreateUnorderedAccessView) { + 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) { + return; + } + + ResourceViewDesc viewDesc = {}; + viewDesc.format = static_cast(Format::R8G8B8A8_UNorm); + viewDesc.dimension = ResourceViewDimension::Texture2D; + + RHIResourceView* uav = GetDevice()->CreateUnorderedAccessView(texture, viewDesc); + if (uav != nullptr) { + EXPECT_TRUE(uav->IsValid()); + EXPECT_EQ(uav->GetViewType(), ResourceViewType::UnorderedAccess); + uav->Shutdown(); + delete uav; + } + + texture->Shutdown(); + delete texture; +} + +TEST_P(RHITestFixture, Device_CreateRenderTargetView_Multiple) { + TextureDesc texDesc = {}; + texDesc.width = 256; + texDesc.height = 256; + texDesc.format = static_cast(Format::R8G8B8A8_UNorm); + texDesc.textureType = static_cast(TextureType::Texture2D); + texDesc.sampleCount = 1; + + RHIResourceView* rtvs[4] = { nullptr }; + + for (int i = 0; i < 4; ++i) { + RHITexture* texture = GetDevice()->CreateTexture(texDesc); + if (texture == nullptr) { + break; + } + + ResourceViewDesc viewDesc = {}; + viewDesc.format = static_cast(Format::R8G8B8A8_UNorm); + viewDesc.dimension = ResourceViewDimension::Texture2D; + + rtvs[i] = GetDevice()->CreateRenderTargetView(texture, viewDesc); + texture->Shutdown(); + delete texture; + } + + for (int i = 0; i < 4; ++i) { + if (rtvs[i] != nullptr) { + EXPECT_TRUE(rtvs[i]->IsValid()); + rtvs[i]->Shutdown(); + delete rtvs[i]; + } + } +} + +TEST_P(RHITestFixture, Device_CreateShaderResourceView_ArrayTexture) { + TextureDesc texDesc = {}; + texDesc.width = 256; + texDesc.height = 256; + texDesc.arraySize = 4; + texDesc.format = static_cast(Format::R8G8B8A8_UNorm); + texDesc.textureType = static_cast(TextureType::Texture2DArray); + texDesc.sampleCount = 1; + + RHITexture* texture = GetDevice()->CreateTexture(texDesc); + if (texture == nullptr) { + return; + } + + ResourceViewDesc viewDesc = {}; + viewDesc.format = static_cast(Format::R8G8B8A8_UNorm); + viewDesc.dimension = ResourceViewDimension::Texture2DArray; + viewDesc.arraySize = 4; + + RHIResourceView* srv = GetDevice()->CreateShaderResourceView(texture, viewDesc); + if (srv != nullptr) { + EXPECT_TRUE(srv->IsValid()); + srv->Shutdown(); + delete srv; + } + + texture->Shutdown(); + delete texture; +} + +TEST_P(RHITestFixture, Device_CreateShaderResourceView_CubeTexture) { + TextureDesc texDesc = {}; + texDesc.width = 256; + texDesc.height = 256; + texDesc.arraySize = 6; + texDesc.format = static_cast(Format::R8G8B8A8_UNorm); + texDesc.textureType = static_cast(TextureType::TextureCube); + texDesc.sampleCount = 1; + + RHITexture* texture = GetDevice()->CreateTexture(texDesc); + if (texture == nullptr) { + return; + } + + ResourceViewDesc viewDesc = {}; + viewDesc.format = static_cast(Format::R8G8B8A8_UNorm); + viewDesc.dimension = ResourceViewDimension::TextureCube; + + RHIResourceView* srv = GetDevice()->CreateShaderResourceView(texture, viewDesc); + if (srv != nullptr) { + EXPECT_TRUE(srv->IsValid()); + srv->Shutdown(); + delete srv; + } + + texture->Shutdown(); + delete texture; +} + +TEST_P(RHITestFixture, Device_CreateDepthStencilView_MipLevels) { + TextureDesc texDesc = {}; + texDesc.width = 256; + texDesc.height = 256; + texDesc.mipLevels = 5; + texDesc.format = static_cast(Format::D24_UNorm_S8_UInt); + texDesc.textureType = static_cast(TextureType::Texture2D); + texDesc.sampleCount = 1; + + RHITexture* texture = GetDevice()->CreateTexture(texDesc); + if (texture == nullptr) { + return; + } + + for (uint32_t mip = 0; mip < texDesc.mipLevels; ++mip) { + ResourceViewDesc viewDesc = {}; + viewDesc.format = static_cast(Format::D24_UNorm_S8_UInt); + viewDesc.dimension = ResourceViewDimension::Texture2D; + viewDesc.mipLevel = mip; + + RHIResourceView* dsv = GetDevice()->CreateDepthStencilView(texture, viewDesc); + if (dsv != nullptr) { + EXPECT_TRUE(dsv->IsValid()); + dsv->Shutdown(); + delete dsv; + } + } + + texture->Shutdown(); + delete texture; +} \ No newline at end of file