mirror of
https://github.com/ocornut/imgui.git
synced 2025-10-03 16:46:29 +00:00
Backends: DX12: Rework synchronization logic. (docking) (#8961)
This commit is contained in:
@@ -135,6 +135,7 @@ struct ImGui_ImplDX12_RenderBuffers
|
|||||||
// Buffers used for secondary viewports created by the multi-viewports systems
|
// Buffers used for secondary viewports created by the multi-viewports systems
|
||||||
struct ImGui_ImplDX12_FrameContext
|
struct ImGui_ImplDX12_FrameContext
|
||||||
{
|
{
|
||||||
|
UINT64 FenceValue;
|
||||||
ID3D12CommandAllocator* CommandAllocator;
|
ID3D12CommandAllocator* CommandAllocator;
|
||||||
ID3D12Resource* RenderTarget;
|
ID3D12Resource* RenderTarget;
|
||||||
D3D12_CPU_DESCRIPTOR_HANDLE RenderTargetCpuDescriptors;
|
D3D12_CPU_DESCRIPTOR_HANDLE RenderTargetCpuDescriptors;
|
||||||
@@ -150,8 +151,9 @@ struct ImGui_ImplDX12_ViewportData
|
|||||||
ID3D12GraphicsCommandList* CommandList;
|
ID3D12GraphicsCommandList* CommandList;
|
||||||
ID3D12DescriptorHeap* RtvDescHeap;
|
ID3D12DescriptorHeap* RtvDescHeap;
|
||||||
IDXGISwapChain3* SwapChain;
|
IDXGISwapChain3* SwapChain;
|
||||||
|
HANDLE SwapChainWaitableObject;
|
||||||
ID3D12Fence* Fence;
|
ID3D12Fence* Fence;
|
||||||
UINT64 FenceSignaledValue;
|
UINT64 FenceLastSignaledValue;
|
||||||
HANDLE FenceEvent;
|
HANDLE FenceEvent;
|
||||||
UINT NumFramesInFlight;
|
UINT NumFramesInFlight;
|
||||||
ImGui_ImplDX12_FrameContext* FrameCtx;
|
ImGui_ImplDX12_FrameContext* FrameCtx;
|
||||||
@@ -166,16 +168,18 @@ struct ImGui_ImplDX12_ViewportData
|
|||||||
CommandList = nullptr;
|
CommandList = nullptr;
|
||||||
RtvDescHeap = nullptr;
|
RtvDescHeap = nullptr;
|
||||||
SwapChain = nullptr;
|
SwapChain = nullptr;
|
||||||
|
SwapChainWaitableObject = nullptr;
|
||||||
Fence = nullptr;
|
Fence = nullptr;
|
||||||
FenceSignaledValue = 0;
|
FenceLastSignaledValue = 0;
|
||||||
FenceEvent = nullptr;
|
FenceEvent = nullptr;
|
||||||
NumFramesInFlight = num_frames_in_flight;
|
NumFramesInFlight = num_frames_in_flight;
|
||||||
FrameCtx = new ImGui_ImplDX12_FrameContext[NumFramesInFlight];
|
FrameCtx = new ImGui_ImplDX12_FrameContext[NumFramesInFlight];
|
||||||
FrameIndex = UINT_MAX;
|
FrameIndex = 0;
|
||||||
FrameRenderBuffers = new ImGui_ImplDX12_RenderBuffers[NumFramesInFlight];
|
FrameRenderBuffers = new ImGui_ImplDX12_RenderBuffers[NumFramesInFlight];
|
||||||
|
|
||||||
for (UINT i = 0; i < NumFramesInFlight; ++i)
|
for (UINT i = 0; i < NumFramesInFlight; ++i)
|
||||||
{
|
{
|
||||||
|
FrameCtx[i].FenceValue = 0;
|
||||||
FrameCtx[i].CommandAllocator = nullptr;
|
FrameCtx[i].CommandAllocator = nullptr;
|
||||||
FrameCtx[i].RenderTarget = nullptr;
|
FrameCtx[i].RenderTarget = nullptr;
|
||||||
|
|
||||||
@@ -191,6 +195,7 @@ struct ImGui_ImplDX12_ViewportData
|
|||||||
IM_ASSERT(CommandQueue == nullptr && CommandList == nullptr);
|
IM_ASSERT(CommandQueue == nullptr && CommandList == nullptr);
|
||||||
IM_ASSERT(RtvDescHeap == nullptr);
|
IM_ASSERT(RtvDescHeap == nullptr);
|
||||||
IM_ASSERT(SwapChain == nullptr);
|
IM_ASSERT(SwapChain == nullptr);
|
||||||
|
IM_ASSERT(SwapChainWaitableObject == nullptr);
|
||||||
IM_ASSERT(Fence == nullptr);
|
IM_ASSERT(Fence == nullptr);
|
||||||
IM_ASSERT(FenceEvent == nullptr);
|
IM_ASSERT(FenceEvent == nullptr);
|
||||||
|
|
||||||
@@ -1043,18 +1048,12 @@ static void ImGui_ImplDX12_CreateWindow(ImGuiViewport* viewport)
|
|||||||
HWND hwnd = viewport->PlatformHandleRaw ? (HWND)viewport->PlatformHandleRaw : (HWND)viewport->PlatformHandle;
|
HWND hwnd = viewport->PlatformHandleRaw ? (HWND)viewport->PlatformHandleRaw : (HWND)viewport->PlatformHandle;
|
||||||
IM_ASSERT(hwnd != 0);
|
IM_ASSERT(hwnd != 0);
|
||||||
|
|
||||||
vd->FrameIndex = UINT_MAX;
|
// Use shared command queue from init info
|
||||||
|
vd->FrameIndex = 0;
|
||||||
// Create command queue.
|
vd->CommandQueue = bd->pCommandQueue;
|
||||||
D3D12_COMMAND_QUEUE_DESC queue_desc = {};
|
|
||||||
queue_desc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
|
|
||||||
queue_desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
|
|
||||||
|
|
||||||
HRESULT res = S_OK;
|
|
||||||
res = bd->pd3dDevice->CreateCommandQueue(&queue_desc, IID_PPV_ARGS(&vd->CommandQueue));
|
|
||||||
IM_ASSERT(res == S_OK);
|
|
||||||
|
|
||||||
// Create command allocator.
|
// Create command allocator.
|
||||||
|
HRESULT res = S_OK;
|
||||||
for (UINT i = 0; i < bd->numFramesInFlight; ++i)
|
for (UINT i = 0; i < bd->numFramesInFlight; ++i)
|
||||||
{
|
{
|
||||||
res = bd->pd3dDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&vd->FrameCtx[i].CommandAllocator));
|
res = bd->pd3dDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&vd->FrameCtx[i].CommandAllocator));
|
||||||
@@ -1088,6 +1087,7 @@ static void ImGui_ImplDX12_CreateWindow(ImGuiViewport* viewport)
|
|||||||
sd1.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED;
|
sd1.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED;
|
||||||
sd1.Scaling = DXGI_SCALING_NONE;
|
sd1.Scaling = DXGI_SCALING_NONE;
|
||||||
sd1.Stereo = FALSE;
|
sd1.Stereo = FALSE;
|
||||||
|
sd1.Flags = DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT;
|
||||||
|
|
||||||
IDXGIFactory4* dxgi_factory = nullptr;
|
IDXGIFactory4* dxgi_factory = nullptr;
|
||||||
res = ::CreateDXGIFactory1(IID_PPV_ARGS(&dxgi_factory));
|
res = ::CreateDXGIFactory1(IID_PPV_ARGS(&dxgi_factory));
|
||||||
@@ -1106,7 +1106,7 @@ static void ImGui_ImplDX12_CreateWindow(ImGuiViewport* viewport)
|
|||||||
swap_chain->QueryInterface(IID_PPV_ARGS(&vd->SwapChain));
|
swap_chain->QueryInterface(IID_PPV_ARGS(&vd->SwapChain));
|
||||||
swap_chain->Release();
|
swap_chain->Release();
|
||||||
|
|
||||||
// Create the render targets
|
// Create the render targets and waitable object
|
||||||
if (vd->SwapChain)
|
if (vd->SwapChain)
|
||||||
{
|
{
|
||||||
D3D12_DESCRIPTOR_HEAP_DESC desc = {};
|
D3D12_DESCRIPTOR_HEAP_DESC desc = {};
|
||||||
@@ -1134,6 +1134,10 @@ static void ImGui_ImplDX12_CreateWindow(ImGuiViewport* viewport)
|
|||||||
bd->pd3dDevice->CreateRenderTargetView(back_buffer, nullptr, vd->FrameCtx[i].RenderTargetCpuDescriptors);
|
bd->pd3dDevice->CreateRenderTargetView(back_buffer, nullptr, vd->FrameCtx[i].RenderTargetCpuDescriptors);
|
||||||
vd->FrameCtx[i].RenderTarget = back_buffer;
|
vd->FrameCtx[i].RenderTarget = back_buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hr = vd->SwapChain->SetMaximumFrameLatency(bd->numFramesInFlight);
|
||||||
|
IM_ASSERT(hr == S_OK);
|
||||||
|
vd->SwapChainWaitableObject = vd->SwapChain->GetFrameLatencyWaitableObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (UINT i = 0; i < bd->numFramesInFlight; i++)
|
for (UINT i = 0; i < bd->numFramesInFlight; i++)
|
||||||
@@ -1142,16 +1146,29 @@ static void ImGui_ImplDX12_CreateWindow(ImGuiViewport* viewport)
|
|||||||
|
|
||||||
static void ImGui_WaitForPendingOperations(ImGui_ImplDX12_ViewportData* vd)
|
static void ImGui_WaitForPendingOperations(ImGui_ImplDX12_ViewportData* vd)
|
||||||
{
|
{
|
||||||
HRESULT hr = S_FALSE;
|
HRESULT hr = vd->CommandQueue->Signal(vd->Fence, ++vd->FenceLastSignaledValue);
|
||||||
if (vd && vd->CommandQueue && vd->Fence && vd->FenceEvent)
|
IM_ASSERT(hr == S_OK);
|
||||||
|
|
||||||
|
hr = vd->Fence->SetEventOnCompletion(vd->FenceLastSignaledValue, vd->FenceEvent);
|
||||||
|
IM_ASSERT(hr == S_OK);
|
||||||
|
::WaitForSingleObject(vd->FenceEvent, INFINITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ImGui_ImplDX12_FrameContext* ImGui_WaitForNextFrameContext(ImGui_ImplDX12_ViewportData* vd)
|
||||||
|
{
|
||||||
|
ImGui_ImplDX12_FrameContext* frame_context = &vd->FrameCtx[vd->FrameIndex % vd->NumFramesInFlight];
|
||||||
|
if (vd->Fence->GetCompletedValue() < frame_context->FenceValue)
|
||||||
{
|
{
|
||||||
hr = vd->CommandQueue->Signal(vd->Fence, ++vd->FenceSignaledValue);
|
HRESULT hr = vd->Fence->SetEventOnCompletion(frame_context->FenceValue, vd->FenceEvent);
|
||||||
IM_ASSERT(hr == S_OK);
|
IM_ASSERT(hr == S_OK);
|
||||||
::WaitForSingleObject(vd->FenceEvent, 0); // Reset any forgotten waits
|
HANDLE waitableObjects[] = { vd->SwapChainWaitableObject, vd->FenceEvent };
|
||||||
hr = vd->Fence->SetEventOnCompletion(vd->FenceSignaledValue, vd->FenceEvent);
|
::WaitForMultipleObjects(2, waitableObjects, TRUE, INFINITE);
|
||||||
IM_ASSERT(hr == S_OK);
|
|
||||||
::WaitForSingleObject(vd->FenceEvent, INFINITE);
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
::WaitForSingleObject(vd->SwapChainWaitableObject, INFINITE);
|
||||||
|
}
|
||||||
|
return frame_context;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ImGui_ImplDX12_DestroyWindow(ImGuiViewport* viewport)
|
static void ImGui_ImplDX12_DestroyWindow(ImGuiViewport* viewport)
|
||||||
@@ -1162,7 +1179,9 @@ static void ImGui_ImplDX12_DestroyWindow(ImGuiViewport* viewport)
|
|||||||
{
|
{
|
||||||
ImGui_WaitForPendingOperations(vd);
|
ImGui_WaitForPendingOperations(vd);
|
||||||
|
|
||||||
SafeRelease(vd->CommandQueue);
|
vd->CommandQueue = nullptr;
|
||||||
|
::CloseHandle(vd->SwapChainWaitableObject);
|
||||||
|
vd->SwapChainWaitableObject = nullptr;
|
||||||
SafeRelease(vd->CommandList);
|
SafeRelease(vd->CommandList);
|
||||||
SafeRelease(vd->SwapChain);
|
SafeRelease(vd->SwapChain);
|
||||||
SafeRelease(vd->RtvDescHeap);
|
SafeRelease(vd->RtvDescHeap);
|
||||||
@@ -1194,7 +1213,7 @@ static void ImGui_ImplDX12_SetWindowSize(ImGuiViewport* viewport, ImVec2 size)
|
|||||||
if (vd->SwapChain)
|
if (vd->SwapChain)
|
||||||
{
|
{
|
||||||
ID3D12Resource* back_buffer = nullptr;
|
ID3D12Resource* back_buffer = nullptr;
|
||||||
vd->SwapChain->ResizeBuffers(0, (UINT)size.x, (UINT)size.y, DXGI_FORMAT_UNKNOWN, 0);
|
vd->SwapChain->ResizeBuffers(0, (UINT)size.x, (UINT)size.y, DXGI_FORMAT_UNKNOWN, DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT);
|
||||||
for (UINT i = 0; i < bd->numFramesInFlight; i++)
|
for (UINT i = 0; i < bd->numFramesInFlight; i++)
|
||||||
{
|
{
|
||||||
vd->SwapChain->GetBuffer(i, IID_PPV_ARGS(&back_buffer));
|
vd->SwapChain->GetBuffer(i, IID_PPV_ARGS(&back_buffer));
|
||||||
@@ -1209,7 +1228,7 @@ static void ImGui_ImplDX12_RenderWindow(ImGuiViewport* viewport, void*)
|
|||||||
ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
|
ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
|
||||||
ImGui_ImplDX12_ViewportData* vd = (ImGui_ImplDX12_ViewportData*)viewport->RendererUserData;
|
ImGui_ImplDX12_ViewportData* vd = (ImGui_ImplDX12_ViewportData*)viewport->RendererUserData;
|
||||||
|
|
||||||
ImGui_ImplDX12_FrameContext* frame_context = &vd->FrameCtx[vd->FrameIndex % bd->numFramesInFlight];
|
ImGui_ImplDX12_FrameContext* frame_context = ImGui_WaitForNextFrameContext(vd);
|
||||||
UINT back_buffer_idx = vd->SwapChain->GetCurrentBackBufferIndex();
|
UINT back_buffer_idx = vd->SwapChain->GetCurrentBackBufferIndex();
|
||||||
|
|
||||||
const ImVec4 clear_color = ImVec4(0.0f, 0.0f, 0.0f, 1.0f);
|
const ImVec4 clear_color = ImVec4(0.0f, 0.0f, 0.0f, 1.0f);
|
||||||
@@ -1239,9 +1258,11 @@ static void ImGui_ImplDX12_RenderWindow(ImGuiViewport* viewport, void*)
|
|||||||
cmd_list->ResourceBarrier(1, &barrier);
|
cmd_list->ResourceBarrier(1, &barrier);
|
||||||
cmd_list->Close();
|
cmd_list->Close();
|
||||||
|
|
||||||
vd->CommandQueue->Wait(vd->Fence, vd->FenceSignaledValue);
|
|
||||||
vd->CommandQueue->ExecuteCommandLists(1, (ID3D12CommandList* const*)&cmd_list);
|
vd->CommandQueue->ExecuteCommandLists(1, (ID3D12CommandList* const*)&cmd_list);
|
||||||
vd->CommandQueue->Signal(vd->Fence, ++vd->FenceSignaledValue);
|
|
||||||
|
HRESULT hr = vd->CommandQueue->Signal(vd->Fence, ++vd->FenceLastSignaledValue);
|
||||||
|
IM_ASSERT(hr == S_OK);
|
||||||
|
frame_context->FenceValue = vd->FenceLastSignaledValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ImGui_ImplDX12_SwapBuffers(ImGuiViewport* viewport, void*)
|
static void ImGui_ImplDX12_SwapBuffers(ImGuiViewport* viewport, void*)
|
||||||
@@ -1249,8 +1270,7 @@ static void ImGui_ImplDX12_SwapBuffers(ImGuiViewport* viewport, void*)
|
|||||||
ImGui_ImplDX12_ViewportData* vd = (ImGui_ImplDX12_ViewportData*)viewport->RendererUserData;
|
ImGui_ImplDX12_ViewportData* vd = (ImGui_ImplDX12_ViewportData*)viewport->RendererUserData;
|
||||||
|
|
||||||
vd->SwapChain->Present(0, 0);
|
vd->SwapChain->Present(0, 0);
|
||||||
while (vd->Fence->GetCompletedValue() < vd->FenceSignaledValue)
|
vd->FrameIndex++;
|
||||||
::SwitchToThread();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImGui_ImplDX12_InitMultiViewportSupport()
|
void ImGui_ImplDX12_InitMultiViewportSupport()
|
||||||
|
@@ -295,8 +295,6 @@ 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;
|
|
||||||
|
|
||||||
// Update and Render additional Platform Windows
|
// Update and Render additional Platform Windows
|
||||||
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
|
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
|
||||||
@@ -305,6 +303,9 @@ int main(int, char**)
|
|||||||
ImGui::RenderPlatformWindowsDefault();
|
ImGui::RenderPlatformWindowsDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
Reference in New Issue
Block a user