#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); ID3D12Resource* resource0 = backBuffer0.GetResource(); ASSERT_NE(resource0, nullptr); D3D12Texture& backBuffer1 = mSwapChain.GetBackBuffer(1); ID3D12Resource* resource1 = backBuffer1.GetResource(); ASSERT_NE(resource1, nullptr); ASSERT_NE(resource0, resource1); } TEST_F(SwapChainTestFixture, DISABLED_SwapChain_GetBackBuffer_InvalidIndex) { ASSERT_TRUE(mSwapChain.Initialize( mFactory.Get(), mCommandQueue.Get(), mHWND, 800, 600, 2 )); ASSERT_DEATH(mSwapChain.GetBackBuffer(99), "BackBuffer index out of range"); } 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()); }