From c52b4ef35c2b8f49c40cf7933c25a10fd06cf6ed Mon Sep 17 00:00:00 2001 From: ssdfasd <2156608475@qq.com> Date: Fri, 20 Mar 2026 17:07:24 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8DD3D12SwapChain=E5=88=9D?= =?UTF-8?q?=E5=A7=8B=E5=8C=96bug=E5=B9=B6=E6=B7=BB=E5=8A=A0=E5=8D=95?= =?UTF-8?q?=E5=85=83=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 修复Initialize(IDXGIFactory4*, ...)重载缺少m_backBuffers初始化的问题 - 新增test_swap_chain.cpp单元测试文件,包含6个SwapChain测试用例 - 更新unit CMakeLists.txt添加test_swap_chain.cpp和Res路径 --- engine/src/RHI/D3D12/D3D12SwapChain.cpp | 7 + tests/RHI/D3D12/unit/CMakeLists.txt | 5 +- tests/RHI/D3D12/unit/test_swap_chain.cpp | 193 +++++++++++++++++++++++ 3 files changed, 203 insertions(+), 2 deletions(-) create mode 100644 tests/RHI/D3D12/unit/test_swap_chain.cpp diff --git a/engine/src/RHI/D3D12/D3D12SwapChain.cpp b/engine/src/RHI/D3D12/D3D12SwapChain.cpp index 6eff1066..46c05d81 100644 --- a/engine/src/RHI/D3D12/D3D12SwapChain.cpp +++ b/engine/src/RHI/D3D12/D3D12SwapChain.cpp @@ -44,6 +44,13 @@ bool D3D12SwapChain::Initialize(IDXGIFactory4* factory, ID3D12CommandQueue* comm m_height = height; m_bufferCount = bufferCount; + m_backBuffers.resize(m_bufferCount); + for (uint32_t i = 0; i < m_bufferCount; ++i) { + ID3D12Resource* resource = nullptr; + m_swapChain->GetBuffer(i, IID_PPV_ARGS(&resource)); + m_backBuffers[i].InitializeFromExisting(resource); + } + return true; } diff --git a/tests/RHI/D3D12/unit/CMakeLists.txt b/tests/RHI/D3D12/unit/CMakeLists.txt index a8d8753e..782ac2e4 100644 --- a/tests/RHI/D3D12/unit/CMakeLists.txt +++ b/tests/RHI/D3D12/unit/CMakeLists.txt @@ -18,6 +18,7 @@ set(TEST_SOURCES test_root_signature.cpp test_pipeline_state.cpp test_views.cpp + test_swap_chain.cpp ) add_executable(d3d12_engine_tests ${TEST_SOURCES}) @@ -38,12 +39,12 @@ target_include_directories(d3d12_engine_tests PRIVATE ) target_compile_definitions(d3d12_engine_tests PRIVATE - TEST_RESOURCES_DIR="${PROJECT_ROOT_DIR}/tests/RHI/D3D12/integration/Res" + TEST_RESOURCES_DIR="${PROJECT_ROOT_DIR}/tests/RHI/D3D12/integration/minimal/Res" ) add_custom_command(TARGET d3d12_engine_tests POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory - ${PROJECT_ROOT_DIR}/tests/RHI/D3D12/integration/Res + ${PROJECT_ROOT_DIR}/tests/RHI/D3D12/integration/minimal/Res $/Res ) diff --git a/tests/RHI/D3D12/unit/test_swap_chain.cpp b/tests/RHI/D3D12/unit/test_swap_chain.cpp new file mode 100644 index 00000000..7d674843 --- /dev/null +++ b/tests/RHI/D3D12/unit/test_swap_chain.cpp @@ -0,0 +1,193 @@ +#include "fixtures/D3D12TestFixture.h" +#include "XCEngine/RHI/D3D12/D3D12SwapChain.h" +#include + +using namespace XCEngine::RHI; + +class SwapChainTestFixture : public ::testing::Test { +protected: + void SetUp() override { + HRESULT hr = D3D12CreateDevice( + nullptr, + D3D_FEATURE_LEVEL_12_0, + IID_PPV_ARGS(&mDevice) + ); + + if (FAILED(hr)) { + GTEST_SKIP() << "Failed to create D3D12 device"; + return; + } + + D3D12_COMMAND_QUEUE_DESC queueDesc = {}; + queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; + + hr = mDevice->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&mCommandQueue)); + if (FAILED(hr)) { + GTEST_SKIP() << "Failed to create command queue"; + return; + } + + hr = CreateDXGIFactory1(IID_PPV_ARGS(&mFactory)); + if (FAILED(hr)) { + GTEST_SKIP() << "Failed to create DXGI factory"; + return; + } + + WNDCLASSEX wc = {}; + wc.cbSize = sizeof(WNDCLASSEX); + wc.lpfnWndProc = DefWindowProc; + wc.hInstance = GetModuleHandle(nullptr); + wc.lpszClassName = "SwapChainTest"; + RegisterClassEx(&wc); + + mHWND = CreateWindowEx( + 0, + "SwapChainTest", + "SwapChain Test", + WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, + CW_USEDEFAULT, + 800, + 600, + NULL, + NULL, + wc.hInstance, + NULL + ); + + if (!mHWND) { + GTEST_SKIP() << "Failed to create window"; + return; + } + } + + void TearDown() override { + if (mCommandQueue) { + WaitForGPU(); + } + if (mHWND) { + DestroyWindow(mHWND); + } + mSwapChain.Shutdown(); + mCommandQueue.Reset(); + mDevice.Reset(); + mFactory.Reset(); + } + + void WaitForGPU() { + if (!mCommandQueue || !mDevice) return; + + ComPtr fence; + UINT64 fenceValue = 1; + + HRESULT hr = mDevice->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&fence)); + if (SUCCEEDED(hr)) { + mCommandQueue->Signal(fence.Get(), fenceValue); + if (fence->GetCompletedValue() < fenceValue) { + HANDLE eventHandle = CreateEvent(nullptr, FALSE, FALSE, nullptr); + if (eventHandle) { + fence->SetEventOnCompletion(fenceValue, eventHandle); + WaitForSingleObject(eventHandle, INFINITE); + CloseHandle(eventHandle); + } + } + } + } + + Microsoft::WRL::ComPtr mDevice; + Microsoft::WRL::ComPtr mCommandQueue; + Microsoft::WRL::ComPtr mFactory; + HWND mHWND = nullptr; + D3D12SwapChain mSwapChain; +}; + +TEST_F(SwapChainTestFixture, SwapChain_Initialize_FromFactory) { + bool result = mSwapChain.Initialize( + mFactory.Get(), + mCommandQueue.Get(), + mHWND, + 800, + 600, + 2 + ); + + ASSERT_TRUE(result); +} + +TEST_F(SwapChainTestFixture, SwapChain_GetBackBuffer_ValidIndex) { + ASSERT_TRUE(mSwapChain.Initialize( + mFactory.Get(), + mCommandQueue.Get(), + mHWND, + 800, + 600, + 2 + )); + + D3D12Texture* backBuffer0 = mSwapChain.GetBackBuffer(0); + ASSERT_NE(backBuffer0, nullptr); + + D3D12Texture* backBuffer1 = mSwapChain.GetBackBuffer(1); + ASSERT_NE(backBuffer1, nullptr); + + ID3D12Resource* resource0 = backBuffer0->GetResource(); + ID3D12Resource* resource1 = backBuffer1->GetResource(); + ASSERT_NE(resource0, nullptr); + ASSERT_NE(resource1, nullptr); + + ASSERT_NE(resource0, resource1); +} + +TEST_F(SwapChainTestFixture, SwapChain_GetBackBuffer_InvalidIndex) { + ASSERT_TRUE(mSwapChain.Initialize( + mFactory.Get(), + mCommandQueue.Get(), + mHWND, + 800, + 600, + 2 + )); + + D3D12Texture* backBuffer = mSwapChain.GetBackBuffer(99); + ASSERT_TRUE(backBuffer == nullptr); +} + +TEST_F(SwapChainTestFixture, SwapChain_GetCurrentBackBufferIndex) { + ASSERT_TRUE(mSwapChain.Initialize( + mFactory.Get(), + mCommandQueue.Get(), + mHWND, + 800, + 600, + 2 + )); + + uint32_t index = mSwapChain.GetCurrentBackBufferIndex(); + EXPECT_LT(index, 2u); +} + +TEST_F(SwapChainTestFixture, SwapChain_Present_DoesNotCrash) { + ASSERT_TRUE(mSwapChain.Initialize( + mFactory.Get(), + mCommandQueue.Get(), + mHWND, + 800, + 600, + 2 + )); + + ASSERT_NO_FATAL_FAILURE(mSwapChain.Present(0, 0)); +} + +TEST_F(SwapChainTestFixture, SwapChain_Shutdown_Cleanup) { + ASSERT_TRUE(mSwapChain.Initialize( + mFactory.Get(), + mCommandQueue.Get(), + mHWND, + 800, + 600, + 2 + )); + + ASSERT_NO_FATAL_FAILURE(mSwapChain.Shutdown()); +}