fix: refresh d3d12 swapchain backbuffers on resize

This commit is contained in:
2026-03-28 16:26:31 +08:00
parent 1fa97dc246
commit ec1535ad25
3 changed files with 78 additions and 18 deletions

View File

@@ -33,6 +33,9 @@ public:
void* GetNativeHandle() override;
private:
bool RefreshBackBuffers();
void ReleaseBackBuffers();
ComPtr<IDXGISwapChain3> m_swapChain;
ComPtr<ID3D12CommandQueue> m_commandQueue;
uint32_t m_width;

View File

@@ -43,14 +43,7 @@ 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, false);
}
return true;
return RefreshBackBuffers();
}
bool D3D12SwapChain::Initialize(IDXGISwapChain* swapChain, uint32_t width, uint32_t height) {
@@ -59,21 +52,25 @@ bool D3D12SwapChain::Initialize(IDXGISwapChain* swapChain, uint32_t width, uint3
return false;
}
m_width = width;
m_height = height;
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, false);
DXGI_SWAP_CHAIN_DESC desc = {};
hResult = m_swapChain->GetDesc(&desc);
if (FAILED(hResult) || desc.BufferCount == 0) {
return false;
}
return true;
m_width = width;
m_height = height;
m_bufferCount = desc.BufferCount;
return RefreshBackBuffers();
}
void D3D12SwapChain::Shutdown() {
ReleaseBackBuffers();
m_commandQueue.Reset();
m_swapChain.Reset();
m_width = 0;
m_height = 0;
}
uint32_t D3D12SwapChain::GetCurrentBackBufferIndex() const {
@@ -95,9 +92,16 @@ void D3D12SwapChain::Present(uint32_t syncInterval, uint32_t flags) {
}
void D3D12SwapChain::Resize(uint32_t width, uint32_t height) {
m_swapChain->ResizeBuffers(m_bufferCount, width, height, DXGI_FORMAT_R8G8B8A8_UNORM, 0);
ReleaseBackBuffers();
const HRESULT hResult = m_swapChain->ResizeBuffers(m_bufferCount, width, height, DXGI_FORMAT_R8G8B8A8_UNORM, 0);
if (FAILED(hResult)) {
return;
}
m_width = width;
m_height = height;
RefreshBackBuffers();
}
void* D3D12SwapChain::GetNativeHandle() {
@@ -108,5 +112,34 @@ RHITexture* D3D12SwapChain::GetCurrentBackBuffer() {
return &GetBackBuffer(GetCurrentBackBufferIndex());
}
bool D3D12SwapChain::RefreshBackBuffers() {
if (!m_swapChain || m_bufferCount == 0) {
return false;
}
m_backBuffers.clear();
m_backBuffers.resize(m_bufferCount);
for (uint32_t i = 0; i < m_bufferCount; ++i) {
ComPtr<ID3D12Resource> resource;
const HRESULT hResult = m_swapChain->GetBuffer(i, IID_PPV_ARGS(&resource));
if (FAILED(hResult) || resource == nullptr) {
ReleaseBackBuffers();
return false;
}
m_backBuffers[i].InitializeFromExisting(resource.Get(), false);
}
return true;
}
void D3D12SwapChain::ReleaseBackBuffers() {
for (D3D12Texture& backBuffer : m_backBuffers) {
backBuffer.Shutdown();
}
m_backBuffers.clear();
}
} // namespace RHI
} // namespace XCEngine

View File

@@ -175,6 +175,30 @@ TEST_F(SwapChainTestFixture, SwapChain_Present_DoesNotCrash) {
ASSERT_NO_FATAL_FAILURE(mSwapChain.Present(0, 0));
}
TEST_F(SwapChainTestFixture, SwapChain_Resize_RecreatesBackBuffers) {
ASSERT_TRUE(mSwapChain.Initialize(
mFactory.Get(),
mCommandQueue.Get(),
mHWND,
800,
600,
2
));
ID3D12Resource* beforeResize = mSwapChain.GetBackBuffer(0).GetResource();
ASSERT_NE(beforeResize, nullptr);
EXPECT_EQ(mSwapChain.GetBackBuffer(0).GetWidth(), 800u);
EXPECT_EQ(mSwapChain.GetBackBuffer(0).GetHeight(), 600u);
ASSERT_NO_FATAL_FAILURE(mSwapChain.Resize(1024, 768));
ID3D12Resource* afterResize = mSwapChain.GetBackBuffer(0).GetResource();
ASSERT_NE(afterResize, nullptr);
EXPECT_EQ(mSwapChain.GetBackBuffer(0).GetWidth(), 1024u);
EXPECT_EQ(mSwapChain.GetBackBuffer(0).GetHeight(), 768u);
EXPECT_NE(beforeResize, afterResize);
}
TEST_F(SwapChainTestFixture, SwapChain_Shutdown_Cleanup) {
ASSERT_TRUE(mSwapChain.Initialize(
mFactory.Get(),