fix: refresh d3d12 swapchain backbuffers on resize
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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(),
|
||||
|
||||
Reference in New Issue
Block a user