1
0
Fork 0
mirror of https://github.com/ocornut/imgui.git synced 2026-01-09 23:54:20 +00:00
This commit is contained in:
Rémy Tassoux 2025-12-28 15:02:51 +09:00 committed by GitHub
commit ed7b3ea606
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 48 additions and 30 deletions

View file

@ -23,6 +23,7 @@
// CHANGELOG // CHANGELOG
// (minor and older changes stripped away, please see git history for details) // (minor and older changes stripped away, please see git history for details)
// 2025-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. // 2025-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
// 2025-10-25: [Docking] DirectX12: Let user specifies viewports backbuffer count by setting ImGui_ImplDX12_InitInfo::BackBuffer and add support for a single frame in flight.
// 2025-10-23: [Docking] DirectX12: Fixed an issue in synchronization logic improving rendering throughput for secondary viewports. (#8961, #9025) // 2025-10-23: [Docking] DirectX12: Fixed an issue in synchronization logic improving rendering throughput for secondary viewports. (#8961, #9025)
// 2025-10-11: DirectX12: Reuse texture upload buffer and grow it only when necessary. (#9002) // 2025-10-11: DirectX12: Reuse texture upload buffer and grow it only when necessary. (#9002)
// 2025-09-29: DirectX12: Rework synchronization logic. (#8961) // 2025-09-29: DirectX12: Rework synchronization logic. (#8961)
@ -107,6 +108,7 @@ struct ImGui_ImplDX12_Data
ID3D12Fence* Fence; ID3D12Fence* Fence;
UINT64 FenceLastSignaledValue; UINT64 FenceLastSignaledValue;
HANDLE FenceEvent; HANDLE FenceEvent;
UINT numBackbuffer;
UINT numFramesInFlight; UINT numFramesInFlight;
bool tearingSupport; bool tearingSupport;
bool LegacySingleDescriptorUsed; bool LegacySingleDescriptorUsed;
@ -136,13 +138,18 @@ struct ImGui_ImplDX12_RenderBuffers
int VertexBufferSize; int VertexBufferSize;
}; };
// Backbuffers used for secondary viewports created by the multi-viewports systems
struct ImGui_ImplDX12_Backbuffer
{
ID3D12Resource* RenderTarget;
D3D12_CPU_DESCRIPTOR_HANDLE RenderTargetCpuDescriptors;
};
// 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; UINT64 FenceValue;
ID3D12CommandAllocator* CommandAllocator; ID3D12CommandAllocator* CommandAllocator;
ID3D12Resource* RenderTarget;
D3D12_CPU_DESCRIPTOR_HANDLE RenderTargetCpuDescriptors;
}; };
// Helper structure we store in the void* RendererUserData field of each ImGuiViewport to easily retrieve our backend data. // Helper structure we store in the void* RendererUserData field of each ImGuiViewport to easily retrieve our backend data.
@ -156,30 +163,35 @@ struct ImGui_ImplDX12_ViewportData
ID3D12DescriptorHeap* RtvDescHeap; ID3D12DescriptorHeap* RtvDescHeap;
IDXGISwapChain3* SwapChain; IDXGISwapChain3* SwapChain;
HANDLE SwapChainWaitableObject; HANDLE SwapChainWaitableObject;
UINT NumBackBuffer;
ImGui_ImplDX12_Backbuffer* BackBuffer;
UINT NumFramesInFlight; UINT NumFramesInFlight;
ImGui_ImplDX12_FrameContext* FrameCtx; ImGui_ImplDX12_FrameContext* FrameCtx;
// Render buffers // Render buffers
UINT FrameIndex; UINT FrameIndex;
ImGui_ImplDX12_RenderBuffers* FrameRenderBuffers; ImGui_ImplDX12_RenderBuffers* FrameRenderBuffers;
ImGui_ImplDX12_ViewportData(UINT num_frames_in_flight) ImGui_ImplDX12_ViewportData(UINT num_backbuffer, UINT num_frames_in_flight)
{ {
CommandQueue = nullptr; CommandQueue = nullptr;
CommandList = nullptr; CommandList = nullptr;
RtvDescHeap = nullptr; RtvDescHeap = nullptr;
SwapChain = nullptr; SwapChain = nullptr;
SwapChainWaitableObject = nullptr; SwapChainWaitableObject = nullptr;
NumBackBuffer = num_backbuffer;
BackBuffer = new ImGui_ImplDX12_Backbuffer[num_backbuffer];
NumFramesInFlight = num_frames_in_flight; NumFramesInFlight = num_frames_in_flight;
FrameCtx = new ImGui_ImplDX12_FrameContext[NumFramesInFlight]; FrameCtx = new ImGui_ImplDX12_FrameContext[NumFramesInFlight];
FrameIndex = 0; FrameIndex = 0;
FrameRenderBuffers = new ImGui_ImplDX12_RenderBuffers[NumFramesInFlight]; FrameRenderBuffers = new ImGui_ImplDX12_RenderBuffers[NumFramesInFlight];
for (UINT i = 0; i < NumBackBuffer; ++i)
BackBuffer[i].RenderTarget = nullptr;
for (UINT i = 0; i < NumFramesInFlight; ++i) for (UINT i = 0; i < NumFramesInFlight; ++i)
{ {
FrameCtx[i].FenceValue = 0; FrameCtx[i].FenceValue = 0;
FrameCtx[i].CommandAllocator = nullptr; FrameCtx[i].CommandAllocator = nullptr;
FrameCtx[i].RenderTarget = nullptr;
// Create buffers with a default size (they will later be grown as needed) // Create buffers with a default size (they will later be grown as needed)
FrameRenderBuffers[i].IndexBuffer = nullptr; FrameRenderBuffers[i].IndexBuffer = nullptr;
@ -195,12 +207,16 @@ struct ImGui_ImplDX12_ViewportData
IM_ASSERT(SwapChain == nullptr); IM_ASSERT(SwapChain == nullptr);
IM_ASSERT(SwapChainWaitableObject == nullptr); IM_ASSERT(SwapChainWaitableObject == nullptr);
for (UINT i = 0; i < NumBackBuffer; ++i)
IM_ASSERT(BackBuffer[i].RenderTarget == nullptr);
for (UINT i = 0; i < NumFramesInFlight; ++i) for (UINT i = 0; i < NumFramesInFlight; ++i)
{ {
IM_ASSERT(FrameCtx[i].CommandAllocator == nullptr && FrameCtx[i].RenderTarget == nullptr); IM_ASSERT(FrameCtx[i].CommandAllocator == nullptr);
IM_ASSERT(FrameRenderBuffers[i].IndexBuffer == nullptr && FrameRenderBuffers[i].VertexBuffer == nullptr); IM_ASSERT(FrameRenderBuffers[i].IndexBuffer == nullptr && FrameRenderBuffers[i].VertexBuffer == nullptr);
} }
delete[] BackBuffer; BackBuffer = nullptr;
delete[] FrameCtx; FrameCtx = nullptr; delete[] FrameCtx; FrameCtx = nullptr;
delete[] FrameRenderBuffers; FrameRenderBuffers = nullptr; delete[] FrameRenderBuffers; FrameRenderBuffers = nullptr;
} }
@ -955,6 +971,7 @@ bool ImGui_ImplDX12_Init(ImGui_ImplDX12_InitInfo* init_info)
bd->pCommandQueue = init_info->CommandQueue; bd->pCommandQueue = init_info->CommandQueue;
bd->RTVFormat = init_info->RTVFormat; bd->RTVFormat = init_info->RTVFormat;
bd->DSVFormat = init_info->DSVFormat; bd->DSVFormat = init_info->DSVFormat;
bd->numBackbuffer = init_info->NumBackBuffer >= 2 ? init_info->NumBackBuffer : 2;
bd->numFramesInFlight = init_info->NumFramesInFlight; bd->numFramesInFlight = init_info->NumFramesInFlight;
bd->pd3dSrvDescHeap = init_info->SrvDescriptorHeap; bd->pd3dSrvDescHeap = init_info->SrvDescriptorHeap;
bd->tearingSupport = false; bd->tearingSupport = false;
@ -971,7 +988,7 @@ bool ImGui_ImplDX12_Init(ImGui_ImplDX12_InitInfo* init_info)
// Create a dummy ImGui_ImplDX12_ViewportData holder for the main viewport, // Create a dummy ImGui_ImplDX12_ViewportData holder for the main viewport,
// Since this is created and managed by the application, we will only use the ->Resources[] fields. // Since this is created and managed by the application, we will only use the ->Resources[] fields.
ImGuiViewport* main_viewport = ImGui::GetMainViewport(); ImGuiViewport* main_viewport = ImGui::GetMainViewport();
main_viewport->RendererUserData = IM_NEW(ImGui_ImplDX12_ViewportData)(bd->numFramesInFlight); main_viewport->RendererUserData = IM_NEW(ImGui_ImplDX12_ViewportData)(0, bd->numFramesInFlight);
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
if (init_info->SrvDescriptorAllocFn == nullptr) if (init_info->SrvDescriptorAllocFn == nullptr)
@ -1059,7 +1076,7 @@ void ImGui_ImplDX12_NewFrame()
static void ImGui_ImplDX12_CreateWindow(ImGuiViewport* viewport) static void ImGui_ImplDX12_CreateWindow(ImGuiViewport* viewport)
{ {
ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData(); ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
ImGui_ImplDX12_ViewportData* vd = IM_NEW(ImGui_ImplDX12_ViewportData)(bd->numFramesInFlight); ImGui_ImplDX12_ViewportData* vd = IM_NEW(ImGui_ImplDX12_ViewportData)(bd->numBackbuffer, bd->numFramesInFlight);
viewport->RendererUserData = vd; viewport->RendererUserData = vd;
// PlatformHandleRaw should always be a HWND, whereas PlatformHandle might be a higher-level handle (e.g. GLFWWindow*, SDL's WindowID). // PlatformHandleRaw should always be a HWND, whereas PlatformHandle might be a higher-level handle (e.g. GLFWWindow*, SDL's WindowID).
@ -1088,7 +1105,7 @@ static void ImGui_ImplDX12_CreateWindow(ImGuiViewport* viewport)
// FIXME-VIEWPORT: May want to copy/inherit swap chain settings from the user/application. // FIXME-VIEWPORT: May want to copy/inherit swap chain settings from the user/application.
DXGI_SWAP_CHAIN_DESC1 sd1; DXGI_SWAP_CHAIN_DESC1 sd1;
ZeroMemory(&sd1, sizeof(sd1)); ZeroMemory(&sd1, sizeof(sd1));
sd1.BufferCount = bd->numFramesInFlight; sd1.BufferCount = bd->numBackbuffer;
sd1.Width = (UINT)viewport->Size.x; sd1.Width = (UINT)viewport->Size.x;
sd1.Height = (UINT)viewport->Size.y; sd1.Height = (UINT)viewport->Size.y;
sd1.Format = bd->RTVFormat; sd1.Format = bd->RTVFormat;
@ -1120,7 +1137,7 @@ static void ImGui_ImplDX12_CreateWindow(ImGuiViewport* viewport)
{ {
D3D12_DESCRIPTOR_HEAP_DESC desc = {}; D3D12_DESCRIPTOR_HEAP_DESC desc = {};
desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
desc.NumDescriptors = bd->numFramesInFlight; desc.NumDescriptors = bd->numBackbuffer;
desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
desc.NodeMask = 1; desc.NodeMask = 1;
@ -1129,19 +1146,16 @@ static void ImGui_ImplDX12_CreateWindow(ImGuiViewport* viewport)
SIZE_T rtv_descriptor_size = bd->pd3dDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); SIZE_T rtv_descriptor_size = bd->pd3dDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
D3D12_CPU_DESCRIPTOR_HANDLE rtv_handle = vd->RtvDescHeap->GetCPUDescriptorHandleForHeapStart(); D3D12_CPU_DESCRIPTOR_HANDLE rtv_handle = vd->RtvDescHeap->GetCPUDescriptorHandleForHeapStart();
for (UINT i = 0; i < bd->numFramesInFlight; i++)
{
vd->FrameCtx[i].RenderTargetCpuDescriptors = rtv_handle;
rtv_handle.ptr += rtv_descriptor_size;
}
ID3D12Resource* back_buffer; ID3D12Resource* back_buffer;
for (UINT i = 0; i < bd->numFramesInFlight; i++) for (UINT i = 0; i < bd->numBackbuffer; i++)
{ {
IM_ASSERT(vd->FrameCtx[i].RenderTarget == nullptr); vd->BackBuffer[i].RenderTargetCpuDescriptors = rtv_handle;
rtv_handle.ptr += rtv_descriptor_size;
IM_ASSERT(vd->BackBuffer[i].RenderTarget == nullptr);
vd->SwapChain->GetBuffer(i, IID_PPV_ARGS(&back_buffer)); vd->SwapChain->GetBuffer(i, IID_PPV_ARGS(&back_buffer));
bd->pd3dDevice->CreateRenderTargetView(back_buffer, nullptr, vd->FrameCtx[i].RenderTargetCpuDescriptors); bd->pd3dDevice->CreateRenderTargetView(back_buffer, nullptr, vd->BackBuffer[i].RenderTargetCpuDescriptors);
vd->FrameCtx[i].RenderTarget = back_buffer; vd->BackBuffer[i].RenderTarget = back_buffer;
} }
hr = vd->SwapChain->SetMaximumFrameLatency(bd->numFramesInFlight); hr = vd->SwapChain->SetMaximumFrameLatency(bd->numFramesInFlight);
@ -1197,9 +1211,11 @@ static void ImGui_ImplDX12_DestroyWindow(ImGuiViewport* viewport)
SafeRelease(vd->SwapChain); SafeRelease(vd->SwapChain);
SafeRelease(vd->RtvDescHeap); SafeRelease(vd->RtvDescHeap);
for (UINT i = 0; i < bd->numBackbuffer; i++)
SafeRelease(vd->BackBuffer[i].RenderTarget);
for (UINT i = 0; i < bd->numFramesInFlight; i++) for (UINT i = 0; i < bd->numFramesInFlight; i++)
{ {
SafeRelease(vd->FrameCtx[i].RenderTarget);
SafeRelease(vd->FrameCtx[i].CommandAllocator); SafeRelease(vd->FrameCtx[i].CommandAllocator);
ImGui_ImplDX12_DestroyRenderBuffers(&vd->FrameRenderBuffers[i]); ImGui_ImplDX12_DestroyRenderBuffers(&vd->FrameRenderBuffers[i]);
} }
@ -1215,8 +1231,8 @@ static void ImGui_ImplDX12_SetWindowSize(ImGuiViewport* viewport, ImVec2 size)
ImGui_WaitForPendingOperations(vd); ImGui_WaitForPendingOperations(vd);
for (UINT i = 0; i < bd->numFramesInFlight; i++) for (UINT i = 0; i < bd->numBackbuffer; i++)
SafeRelease(vd->FrameCtx[i].RenderTarget); SafeRelease(vd->BackBuffer[i].RenderTarget);
if (vd->SwapChain) if (vd->SwapChain)
{ {
@ -1224,11 +1240,11 @@ static void ImGui_ImplDX12_SetWindowSize(ImGuiViewport* viewport, ImVec2 size)
DXGI_SWAP_CHAIN_DESC1 desc = {}; DXGI_SWAP_CHAIN_DESC1 desc = {};
vd->SwapChain->GetDesc1(&desc); vd->SwapChain->GetDesc1(&desc);
vd->SwapChain->ResizeBuffers(0, (UINT)size.x, (UINT)size.y, desc.Format, desc.Flags); vd->SwapChain->ResizeBuffers(0, (UINT)size.x, (UINT)size.y, desc.Format, desc.Flags);
for (UINT i = 0; i < bd->numFramesInFlight; i++) for (UINT i = 0; i < bd->numBackbuffer; i++)
{ {
vd->SwapChain->GetBuffer(i, IID_PPV_ARGS(&back_buffer)); vd->SwapChain->GetBuffer(i, IID_PPV_ARGS(&back_buffer));
bd->pd3dDevice->CreateRenderTargetView(back_buffer, nullptr, vd->FrameCtx[i].RenderTargetCpuDescriptors); bd->pd3dDevice->CreateRenderTargetView(back_buffer, nullptr, vd->BackBuffer[i].RenderTargetCpuDescriptors);
vd->FrameCtx[i].RenderTarget = back_buffer; vd->BackBuffer[i].RenderTarget = back_buffer;
} }
} }
} }
@ -1245,7 +1261,7 @@ static void ImGui_ImplDX12_RenderWindow(ImGuiViewport* viewport, void*)
D3D12_RESOURCE_BARRIER barrier = {}; D3D12_RESOURCE_BARRIER barrier = {};
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
barrier.Transition.pResource = vd->FrameCtx[back_buffer_idx].RenderTarget; barrier.Transition.pResource = vd->BackBuffer[back_buffer_idx].RenderTarget;
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT; barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT;
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET; barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
@ -1256,9 +1272,9 @@ static void ImGui_ImplDX12_RenderWindow(ImGuiViewport* viewport, void*)
frame_context->CommandAllocator->Reset(); frame_context->CommandAllocator->Reset();
cmd_list->Reset(frame_context->CommandAllocator, nullptr); cmd_list->Reset(frame_context->CommandAllocator, nullptr);
cmd_list->ResourceBarrier(1, &barrier); cmd_list->ResourceBarrier(1, &barrier);
cmd_list->OMSetRenderTargets(1, &vd->FrameCtx[back_buffer_idx].RenderTargetCpuDescriptors, FALSE, nullptr); cmd_list->OMSetRenderTargets(1, &vd->BackBuffer[back_buffer_idx].RenderTargetCpuDescriptors, FALSE, nullptr);
if (!(viewport->Flags & ImGuiViewportFlags_NoRendererClear)) if (!(viewport->Flags & ImGuiViewportFlags_NoRendererClear))
cmd_list->ClearRenderTargetView(vd->FrameCtx[back_buffer_idx].RenderTargetCpuDescriptors, (const float*)&clear_color, 0, nullptr); cmd_list->ClearRenderTargetView(vd->BackBuffer[back_buffer_idx].RenderTargetCpuDescriptors, (const float*)&clear_color, 0, nullptr);
cmd_list->SetDescriptorHeaps(1, &bd->pd3dSrvDescHeap); cmd_list->SetDescriptorHeaps(1, &bd->pd3dSrvDescHeap);
ImGui_ImplDX12_RenderDrawData(viewport->DrawData, cmd_list); ImGui_ImplDX12_RenderDrawData(viewport->DrawData, cmd_list);

View file

@ -30,6 +30,7 @@ struct ImGui_ImplDX12_InitInfo
{ {
ID3D12Device* Device; ID3D12Device* Device;
ID3D12CommandQueue* CommandQueue; // Command queue used for queuing texture uploads. ID3D12CommandQueue* CommandQueue; // Command queue used for queuing texture uploads.
int NumBackBuffer;
int NumFramesInFlight; int NumFramesInFlight;
DXGI_FORMAT RTVFormat; // RenderTarget format. DXGI_FORMAT RTVFormat; // RenderTarget format.
DXGI_FORMAT DSVFormat; // DepthStencilView format. DXGI_FORMAT DSVFormat; // DepthStencilView format.

View file

@ -166,6 +166,7 @@ int main(int, char**)
ImGui_ImplDX12_InitInfo init_info = {}; ImGui_ImplDX12_InitInfo init_info = {};
init_info.Device = g_pd3dDevice; init_info.Device = g_pd3dDevice;
init_info.CommandQueue = g_pd3dCommandQueue; init_info.CommandQueue = g_pd3dCommandQueue;
init_info.NumBackBuffer = APP_NUM_BACK_BUFFERS;
init_info.NumFramesInFlight = APP_NUM_FRAMES_IN_FLIGHT; init_info.NumFramesInFlight = APP_NUM_FRAMES_IN_FLIGHT;
init_info.RTVFormat = DXGI_FORMAT_R8G8B8A8_UNORM; init_info.RTVFormat = DXGI_FORMAT_R8G8B8A8_UNORM;
init_info.DSVFormat = DXGI_FORMAT_UNKNOWN; init_info.DSVFormat = DXGI_FORMAT_UNKNOWN;
@ -460,7 +461,7 @@ bool CreateDeviceD3D(HWND hWnd)
swapChain1->Release(); swapChain1->Release();
dxgiFactory->Release(); dxgiFactory->Release();
g_pSwapChain->SetMaximumFrameLatency(APP_NUM_BACK_BUFFERS); g_pSwapChain->SetMaximumFrameLatency(APP_NUM_FRAMES_IN_FLIGHT);
g_hSwapChainWaitableObject = g_pSwapChain->GetFrameLatencyWaitableObject(); g_hSwapChainWaitableObject = g_pSwapChain->GetFrameLatencyWaitableObject();
} }