fix: refresh d3d12 swapchain backbuffers on resize
This commit is contained in:
@@ -33,6 +33,9 @@ public:
|
|||||||
void* GetNativeHandle() override;
|
void* GetNativeHandle() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool RefreshBackBuffers();
|
||||||
|
void ReleaseBackBuffers();
|
||||||
|
|
||||||
ComPtr<IDXGISwapChain3> m_swapChain;
|
ComPtr<IDXGISwapChain3> m_swapChain;
|
||||||
ComPtr<ID3D12CommandQueue> m_commandQueue;
|
ComPtr<ID3D12CommandQueue> m_commandQueue;
|
||||||
uint32_t m_width;
|
uint32_t m_width;
|
||||||
|
|||||||
@@ -43,14 +43,7 @@ bool D3D12SwapChain::Initialize(IDXGIFactory4* factory, ID3D12CommandQueue* comm
|
|||||||
m_height = height;
|
m_height = height;
|
||||||
m_bufferCount = bufferCount;
|
m_bufferCount = bufferCount;
|
||||||
|
|
||||||
m_backBuffers.resize(m_bufferCount);
|
return RefreshBackBuffers();
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool D3D12SwapChain::Initialize(IDXGISwapChain* swapChain, uint32_t width, uint32_t height) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_width = width;
|
DXGI_SWAP_CHAIN_DESC desc = {};
|
||||||
m_height = height;
|
hResult = m_swapChain->GetDesc(&desc);
|
||||||
|
if (FAILED(hResult) || desc.BufferCount == 0) {
|
||||||
m_backBuffers.resize(m_bufferCount);
|
return false;
|
||||||
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;
|
m_width = width;
|
||||||
|
m_height = height;
|
||||||
|
m_bufferCount = desc.BufferCount;
|
||||||
|
|
||||||
|
return RefreshBackBuffers();
|
||||||
}
|
}
|
||||||
|
|
||||||
void D3D12SwapChain::Shutdown() {
|
void D3D12SwapChain::Shutdown() {
|
||||||
|
ReleaseBackBuffers();
|
||||||
|
m_commandQueue.Reset();
|
||||||
m_swapChain.Reset();
|
m_swapChain.Reset();
|
||||||
|
m_width = 0;
|
||||||
|
m_height = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t D3D12SwapChain::GetCurrentBackBufferIndex() const {
|
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) {
|
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_width = width;
|
||||||
m_height = height;
|
m_height = height;
|
||||||
|
RefreshBackBuffers();
|
||||||
}
|
}
|
||||||
|
|
||||||
void* D3D12SwapChain::GetNativeHandle() {
|
void* D3D12SwapChain::GetNativeHandle() {
|
||||||
@@ -108,5 +112,34 @@ RHITexture* D3D12SwapChain::GetCurrentBackBuffer() {
|
|||||||
return &GetBackBuffer(GetCurrentBackBufferIndex());
|
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 RHI
|
||||||
} // namespace XCEngine
|
} // namespace XCEngine
|
||||||
|
|||||||
@@ -175,6 +175,30 @@ TEST_F(SwapChainTestFixture, SwapChain_Present_DoesNotCrash) {
|
|||||||
ASSERT_NO_FATAL_FAILURE(mSwapChain.Present(0, 0));
|
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) {
|
TEST_F(SwapChainTestFixture, SwapChain_Shutdown_Cleanup) {
|
||||||
ASSERT_TRUE(mSwapChain.Initialize(
|
ASSERT_TRUE(mSwapChain.Initialize(
|
||||||
mFactory.Get(),
|
mFactory.Get(),
|
||||||
|
|||||||
Reference in New Issue
Block a user