修复D3D12SwapChain初始化bug并添加单元测试
- 修复Initialize(IDXGIFactory4*, ...)重载缺少m_backBuffers初始化的问题 - 新增test_swap_chain.cpp单元测试文件,包含6个SwapChain测试用例 - 更新unit CMakeLists.txt添加test_swap_chain.cpp和Res路径
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
$<TARGET_FILE_DIR:d3d12_engine_tests>/Res
|
||||
)
|
||||
|
||||
|
||||
193
tests/RHI/D3D12/unit/test_swap_chain.cpp
Normal file
193
tests/RHI/D3D12/unit/test_swap_chain.cpp
Normal file
@@ -0,0 +1,193 @@
|
||||
#include "fixtures/D3D12TestFixture.h"
|
||||
#include "XCEngine/RHI/D3D12/D3D12SwapChain.h"
|
||||
#include <windows.h>
|
||||
|
||||
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<ID3D12Fence> 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<ID3D12Device> mDevice;
|
||||
Microsoft::WRL::ComPtr<ID3D12CommandQueue> mCommandQueue;
|
||||
Microsoft::WRL::ComPtr<IDXGIFactory4> 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());
|
||||
}
|
||||
Reference in New Issue
Block a user