Backends: DX12: Rework synchronization logic. (master) (#8961)

This commit is contained in:
Rémy Tassoux
2025-09-26 16:07:38 +02:00
committed by ocornut
parent 3ff195f702
commit bab3ebec14
2 changed files with 22 additions and 40 deletions

View File

@@ -91,6 +91,7 @@ Other Changes:
- Examples: SDL2+DirectX11: Try WARP software driver if hardware driver is - Examples: SDL2+DirectX11: Try WARP software driver if hardware driver is
not available. (#5924, #5562) not available. (#5924, #5562)
- Examples: SDL3+DirectX11: Added SDL3+DirectX11 example. (#8956, #8957) [@tomaz82] - Examples: SDL3+DirectX11: Added SDL3+DirectX11 example. (#8956, #8957) [@tomaz82]
- Examples: Win32+DirectX12: Rework synchronization logic. (#8961) [@RT2Code]
- Examples: made examples's main.cpp consistent with returning 1 on error. - Examples: made examples's main.cpp consistent with returning 1 on error.

View File

@@ -102,8 +102,8 @@ bool CreateDeviceD3D(HWND hWnd);
void CleanupDeviceD3D(); void CleanupDeviceD3D();
void CreateRenderTarget(); void CreateRenderTarget();
void CleanupRenderTarget(); void CleanupRenderTarget();
void WaitForLastSubmittedFrame(); void WaitForPendingOperations();
FrameContext* WaitForNextFrameResources(); FrameContext* WaitForNextFrameContext();
LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
// Main code // Main code
@@ -256,7 +256,7 @@ int main(int, char**)
// Rendering // Rendering
ImGui::Render(); ImGui::Render();
FrameContext* frameCtx = WaitForNextFrameResources(); FrameContext* frameCtx = WaitForNextFrameContext();
UINT backBufferIdx = g_pSwapChain->GetCurrentBackBufferIndex(); UINT backBufferIdx = g_pSwapChain->GetCurrentBackBufferIndex();
frameCtx->CommandAllocator->Reset(); frameCtx->CommandAllocator->Reset();
@@ -282,19 +282,17 @@ int main(int, char**)
g_pd3dCommandList->Close(); g_pd3dCommandList->Close();
g_pd3dCommandQueue->ExecuteCommandLists(1, (ID3D12CommandList* const*)&g_pd3dCommandList); g_pd3dCommandQueue->ExecuteCommandLists(1, (ID3D12CommandList* const*)&g_pd3dCommandList);
g_pd3dCommandQueue->Signal(g_fence, ++g_fenceLastSignaledValue);
frameCtx->FenceValue = g_fenceLastSignaledValue;
// Present // Present
HRESULT hr = g_pSwapChain->Present(1, 0); // Present with vsync HRESULT hr = g_pSwapChain->Present(1, 0); // Present with vsync
//HRESULT hr = g_pSwapChain->Present(0, 0); // Present without vsync //HRESULT hr = g_pSwapChain->Present(0, 0); // Present without vsync
g_SwapChainOccluded = (hr == DXGI_STATUS_OCCLUDED); g_SwapChainOccluded = (hr == DXGI_STATUS_OCCLUDED);
g_frameIndex++;
UINT64 fenceValue = g_fenceLastSignaledValue + 1;
g_pd3dCommandQueue->Signal(g_fence, fenceValue);
g_fenceLastSignaledValue = fenceValue;
frameCtx->FenceValue = fenceValue;
} }
WaitForLastSubmittedFrame(); WaitForPendingOperations();
// Cleanup // Cleanup
ImGui_ImplDX12_Shutdown(); ImGui_ImplDX12_Shutdown();
@@ -465,49 +463,33 @@ void CreateRenderTarget()
void CleanupRenderTarget() void CleanupRenderTarget()
{ {
WaitForLastSubmittedFrame(); WaitForPendingOperations();
for (UINT i = 0; i < APP_NUM_BACK_BUFFERS; i++) for (UINT i = 0; i < APP_NUM_BACK_BUFFERS; i++)
if (g_mainRenderTargetResource[i]) { g_mainRenderTargetResource[i]->Release(); g_mainRenderTargetResource[i] = nullptr; } if (g_mainRenderTargetResource[i]) { g_mainRenderTargetResource[i]->Release(); g_mainRenderTargetResource[i] = nullptr; }
} }
void WaitForLastSubmittedFrame() void WaitForPendingOperations()
{ {
FrameContext* frameCtx = &g_frameContext[g_frameIndex % APP_NUM_FRAMES_IN_FLIGHT]; g_pd3dCommandQueue->Signal(g_fence, ++g_fenceLastSignaledValue);
UINT64 fenceValue = frameCtx->FenceValue; g_fence->SetEventOnCompletion(g_fenceLastSignaledValue, g_fenceEvent);
if (fenceValue == 0) ::WaitForSingleObject(g_fenceEvent, INFINITE);
return; // No fence was signaled
frameCtx->FenceValue = 0;
if (g_fence->GetCompletedValue() >= fenceValue)
return;
g_fence->SetEventOnCompletion(fenceValue, g_fenceEvent);
WaitForSingleObject(g_fenceEvent, INFINITE);
} }
FrameContext* WaitForNextFrameResources() FrameContext* WaitForNextFrameContext()
{ {
UINT nextFrameIndex = g_frameIndex + 1; FrameContext* frame_context = &g_frameContext[g_frameIndex % APP_NUM_FRAMES_IN_FLIGHT];
g_frameIndex = nextFrameIndex; if (g_fence->GetCompletedValue() < frame_context->FenceValue)
HANDLE waitableObjects[] = { g_hSwapChainWaitableObject, nullptr };
DWORD numWaitableObjects = 1;
FrameContext* frameCtx = &g_frameContext[nextFrameIndex % APP_NUM_FRAMES_IN_FLIGHT];
UINT64 fenceValue = frameCtx->FenceValue;
if (fenceValue != 0) // means no fence was signaled
{ {
frameCtx->FenceValue = 0; g_fence->SetEventOnCompletion(frame_context->FenceValue, g_fenceEvent);
g_fence->SetEventOnCompletion(fenceValue, g_fenceEvent); HANDLE waitableObjects[] = { g_hSwapChainWaitableObject, g_fenceEvent };
waitableObjects[1] = g_fenceEvent; ::WaitForMultipleObjects(2, waitableObjects, TRUE, INFINITE);
numWaitableObjects = 2;
} }
else
::WaitForSingleObject(g_hSwapChainWaitableObject, INFINITE);
WaitForMultipleObjects(numWaitableObjects, waitableObjects, TRUE, INFINITE); return frame_context;
return frameCtx;
} }
// Forward declare message handler from imgui_impl_win32.cpp // Forward declare message handler from imgui_impl_win32.cpp
@@ -528,7 +510,6 @@ LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
case WM_SIZE: case WM_SIZE:
if (g_pd3dDevice != nullptr && wParam != SIZE_MINIMIZED) if (g_pd3dDevice != nullptr && wParam != SIZE_MINIMIZED)
{ {
WaitForLastSubmittedFrame();
CleanupRenderTarget(); CleanupRenderTarget();
HRESULT result = g_pSwapChain->ResizeBuffers(0, (UINT)LOWORD(lParam), (UINT)HIWORD(lParam), DXGI_FORMAT_UNKNOWN, DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT); HRESULT result = g_pSwapChain->ResizeBuffers(0, (UINT)LOWORD(lParam), (UINT)HIWORD(lParam), DXGI_FORMAT_UNKNOWN, DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT);
assert(SUCCEEDED(result) && "Failed to resize swapchain."); assert(SUCCEEDED(result) && "Failed to resize swapchain.");