From 05c1f2795a077681f836dd783f92442c39c79d52 Mon Sep 17 00:00:00 2001 From: "Ilya.Sevrikov" Date: Thu, 17 Oct 2019 16:53:43 +0300 Subject: [PATCH] Add multi-viewports for DX12. (#2851) (cherry picked from commit 899e48565d1ecefde06063f99c75e702adcef175) --- examples/example_win32_directx12/main.cpp | 4 +- examples/imgui_impl_dx12.cpp | 354 ++++++++++++++++------ examples/imgui_impl_dx12.h | 5 +- 3 files changed, 263 insertions(+), 100 deletions(-) diff --git a/examples/example_win32_directx12/main.cpp b/examples/example_win32_directx12/main.cpp index 26a16f0f..0f519c16 100644 --- a/examples/example_win32_directx12/main.cpp +++ b/examples/example_win32_directx12/main.cpp @@ -73,7 +73,7 @@ int main(int, char**) io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls //io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking - //io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows (FIXME: Currently broken in DX12 back-end, need some work!) + io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows //io.ConfigViewportsNoAutoMerge = true; //io.ConfigViewportsNoTaskBarIcon = true; @@ -92,7 +92,7 @@ int main(int, char**) // Setup Platform/Renderer bindings ImGui_ImplWin32_Init(hwnd); ImGui_ImplDX12_Init(g_pd3dDevice, NUM_FRAMES_IN_FLIGHT, - DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, g_pd3dSrvDescHeap, g_pd3dSrvDescHeap->GetCPUDescriptorHandleForHeapStart(), g_pd3dSrvDescHeap->GetGPUDescriptorHandleForHeapStart()); diff --git a/examples/imgui_impl_dx12.cpp b/examples/imgui_impl_dx12.cpp index d8a46221..7f645d3b 100644 --- a/examples/imgui_impl_dx12.cpp +++ b/examples/imgui_impl_dx12.cpp @@ -4,8 +4,8 @@ // Implemented features: // [X] Renderer: User texture binding. Use 'D3D12_GPU_DESCRIPTOR_HANDLE' as ImTextureID. Read the FAQ about ImTextureID! // [X] Renderer: Support for large meshes (64k+ vertices) with 16-bits indices. +// [X] Renderer: Multi-viewport. // Missing features, issues: -// [ ] Renderer: Missing multi-viewport support. // [ ] 64-bit only for now! (Because sizeof(ImTextureId) == sizeof(void*)). See github.com/ocornut/imgui/pull/301 // You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this. @@ -46,6 +46,8 @@ static ID3D12Resource* g_pFontTextureResource = NULL; static D3D12_CPU_DESCRIPTOR_HANDLE g_hFontSrvCpuDescHandle = {}; static D3D12_GPU_DESCRIPTOR_HANDLE g_hFontSrvGpuDescHandle = {}; +static ID3D12DescriptorHeap* g_pd3dSrvDescHeap = NULL; + struct FrameResources { ID3D12Resource* IndexBuffer; @@ -53,9 +55,80 @@ struct FrameResources int IndexBufferSize; int VertexBufferSize; }; -static FrameResources* g_pFrameResources = NULL; + static UINT g_numFramesInFlight = 0; -static UINT g_frameIndex = UINT_MAX; + +struct FrameContext +{ + ID3D12CommandAllocator* CommandAllocator; + UINT64 FenceValue; + ID3D12Resource* RenderTarget; + D3D12_CPU_DESCRIPTOR_HANDLE RenderTargetCpuDescriptors; +}; + +struct ImGuiViewportDataDx12 +{ + ID3D12CommandQueue* CommandQueue; + ID3D12GraphicsCommandList* CommandList; + + ID3D12DescriptorHeap* RtvDescHeap; + IDXGISwapChain3* SwapChain; + + ID3D12Fence* Fence; + UINT64 FenceSignaledValue; + HANDLE FenceEvent; + + FrameContext* FrameCtx; + FrameResources* Resources; + + UINT FrameIndex; + + ImGuiViewportDataDx12() + { + CommandQueue = NULL; + CommandList = NULL; + + RtvDescHeap = NULL; + SwapChain = NULL; + FenceSignaledValue = 0; + Fence = NULL; + FenceEvent = NULL; + FrameIndex = UINT_MAX; + + FrameCtx = new FrameContext[g_numFramesInFlight]; + Resources = new FrameResources[g_numFramesInFlight]; + + for (UINT i = 0; i < g_numFramesInFlight; ++i) + { + FrameCtx[i].CommandAllocator = NULL; + FrameCtx[i].RenderTarget = NULL; + + // Create buffers with a default size (they will later be grown as needed) + Resources[i].IndexBuffer = NULL; + Resources[i].VertexBuffer = NULL; + Resources[i].VertexBufferSize = 5000; + Resources[i].IndexBufferSize = 10000; + } + + } + ~ImGuiViewportDataDx12() + { + IM_ASSERT(CommandQueue == NULL && CommandList == NULL); + IM_ASSERT(RtvDescHeap == NULL); + IM_ASSERT(SwapChain == NULL); + IM_ASSERT(Fence == NULL); + IM_ASSERT(FenceEvent == NULL); + + for (UINT i = 0; i < g_numFramesInFlight; ++i) + { + IM_ASSERT(FrameCtx[i].CommandAllocator == NULL && FrameCtx[i].RenderTarget == NULL); + IM_ASSERT(Resources[i].IndexBuffer == NULL && Resources[i].VertexBuffer == NULL); + } + + delete[] FrameCtx; FrameCtx = NULL; + delete[] Resources; Resources = NULL; + } +}; struct VERTEX_CONSTANT_BUFFER { @@ -129,10 +202,9 @@ void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandL if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f) return; - // FIXME: I'm assuming that this only gets called once per frame! - // If not, we can't just re-allocate the IB or VB, we'll have to do a proper allocator. - g_frameIndex = g_frameIndex + 1; - FrameResources* fr = &g_pFrameResources[g_frameIndex % g_numFramesInFlight]; + ImGuiViewportDataDx12* render_data = (ImGuiViewportDataDx12*)draw_data->OwnerViewport->RendererUserData; + render_data->FrameIndex++; + FrameResources* fr = &render_data->Resources[render_data->FrameIndex % g_numFramesInFlight]; // Create and grow vertex/index buffers if needed if (fr->VertexBuffer == NULL || fr->VertexBufferSize < draw_data->TotalVtxCount) @@ -599,15 +671,9 @@ void ImGui_ImplDX12_InvalidateDeviceObjects() if (g_pRootSignature) { g_pRootSignature->Release(); g_pRootSignature = NULL; } if (g_pPipelineState) { g_pPipelineState->Release(); g_pPipelineState = NULL; } if (g_pFontTextureResource) { g_pFontTextureResource->Release(); g_pFontTextureResource = NULL; io.Fonts->TexID = NULL; } // We copied g_pFontTextureView to io.Fonts->TexID so let's clear that as well. - for (UINT i = 0; i < g_numFramesInFlight; i++) - { - FrameResources* fr = &g_pFrameResources[i]; - if (fr->IndexBuffer) { fr->IndexBuffer->Release(); fr->IndexBuffer = NULL; } - if (fr->VertexBuffer) { fr->VertexBuffer->Release(); fr->VertexBuffer = NULL; } - } } -bool ImGui_ImplDX12_Init(ID3D12Device* device, int num_frames_in_flight, DXGI_FORMAT rtv_format, +bool ImGui_ImplDX12_Init(ID3D12Device* device, int num_frames_in_flight, DXGI_FORMAT rtv_format, ID3D12DescriptorHeap* cbv_srv_heap, D3D12_CPU_DESCRIPTOR_HANDLE font_srv_cpu_desc_handle, D3D12_GPU_DESCRIPTOR_HANDLE font_srv_gpu_desc_handle) { // Setup back-end capabilities flags @@ -620,20 +686,14 @@ bool ImGui_ImplDX12_Init(ID3D12Device* device, int num_frames_in_flight, DXGI_FO g_RTVFormat = rtv_format; g_hFontSrvCpuDescHandle = font_srv_cpu_desc_handle; g_hFontSrvGpuDescHandle = font_srv_gpu_desc_handle; - g_pFrameResources = new FrameResources[num_frames_in_flight]; g_numFramesInFlight = num_frames_in_flight; - g_frameIndex = UINT_MAX; + g_pd3dSrvDescHeap = cbv_srv_heap; - // Create buffers with a default size (they will later be grown as needed) - for (int i = 0; i < num_frames_in_flight; i++) - { - FrameResources* fr = &g_pFrameResources[i]; - fr->IndexBuffer = NULL; - fr->VertexBuffer = NULL; - fr->IndexBufferSize = 10000; - fr->VertexBufferSize = 5000; - } + ImGuiViewport* main_viewport = ImGui::GetMainViewport(); + main_viewport->RendererUserData = IM_NEW(ImGuiViewportDataDx12); + // Setup back-end capabilities flags + io.BackendFlags |= ImGuiBackendFlags_RendererHasViewports; // We can create multi-viewports on the Renderer side (optional) if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) ImGui_ImplDX12_InitPlatformInterface(); @@ -644,13 +704,17 @@ void ImGui_ImplDX12_Shutdown() { ImGui_ImplDX12_ShutdownPlatformInterface(); ImGui_ImplDX12_InvalidateDeviceObjects(); - delete[] g_pFrameResources; - g_pFrameResources = NULL; + g_pd3dDevice = NULL; g_hFontSrvCpuDescHandle.ptr = 0; g_hFontSrvGpuDescHandle.ptr = 0; g_numFramesInFlight = 0; - g_frameIndex = UINT_MAX; + g_pd3dSrvDescHeap = NULL; + + ImGuiViewport* main_viewport = ImGui::GetMainViewport(); + if (ImGuiViewportDataDx12* data = (ImGuiViewportDataDx12*)main_viewport->RendererUserData) + IM_DELETE(data); + main_viewport->RendererUserData = NULL; } void ImGui_ImplDX12_NewFrame() @@ -665,54 +729,118 @@ void ImGui_ImplDX12_NewFrame() // If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first.. //-------------------------------------------------------------------------------------------------------- -struct ImGuiViewportDataDx12 -{ - IDXGISwapChain3* SwapChain; - - ImGuiViewportDataDx12() { SwapChain = NULL; } - ~ImGuiViewportDataDx12() { IM_ASSERT(SwapChain == NULL); } -}; - static void ImGui_ImplDX12_CreateWindow(ImGuiViewport* viewport) { ImGuiViewportDataDx12* data = IM_NEW(ImGuiViewportDataDx12)(); viewport->RendererUserData = data; - IM_ASSERT(0); - /* - // FIXME-PLATFORM // PlatformHandleRaw should always be a HWND, whereas PlatformHandle might be a higher-level handle (e.g. GLFWWindow*, SDL_Window*). // Some back-ends will leave PlatformHandleRaw NULL, in which case we assume PlatformHandle will contain the HWND. HWND hwnd = viewport->PlatformHandleRaw ? (HWND)viewport->PlatformHandleRaw : (HWND)viewport->PlatformHandle; IM_ASSERT(hwnd != 0); + data->FrameIndex = UINT_MAX; + + // Create command queue. + 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 = g_pd3dDevice->CreateCommandQueue(&queue_desc, IID_PPV_ARGS(&data->CommandQueue)); + IM_ASSERT(res == S_OK); + + // Create command allocator. + for (UINT i = 0; i < g_numFramesInFlight; ++i) + { + res = g_pd3dDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&data->FrameCtx[i].CommandAllocator)); + IM_ASSERT(res == S_OK); + } + + // Create command list. + res = g_pd3dDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, data->FrameCtx[0].CommandAllocator, NULL, IID_PPV_ARGS(&data->CommandList)); + IM_ASSERT(res == S_OK); + data->CommandList->Close(); + + // Create fence. + res = g_pd3dDevice->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&data->Fence)); + IM_ASSERT(res == S_OK); + + data->FenceEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + IM_ASSERT(data->FenceEvent != NULL); + // Create swap chain - DXGI_SWAP_CHAIN_DESC sd; - ZeroMemory(&sd, sizeof(sd)); - sd.BufferDesc.Width = (UINT)viewport->Size.x; - sd.BufferDesc.Height = (UINT)viewport->Size.y; - sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - sd.SampleDesc.Count = 1; - sd.SampleDesc.Quality = 0; - sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; - sd.BufferCount = 1; - sd.OutputWindow = hwnd; - sd.Windowed = TRUE; - sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; - sd.Flags = 0; + DXGI_SWAP_CHAIN_DESC1 sd1; + ZeroMemory(&sd1, sizeof(sd1)); + sd1.BufferCount = g_numFramesInFlight; + sd1.Width = (UINT)viewport->Size.x; + sd1.Height = (UINT)viewport->Size.y; + sd1.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + sd1.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + sd1.SampleDesc.Count = 1; + sd1.SampleDesc.Quality = 0; + sd1.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; + sd1.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED; + sd1.Scaling = DXGI_SCALING_STRETCH; + sd1.Stereo = FALSE; - IM_ASSERT(data->SwapChain == NULL && data->RTView == NULL); - g_pFactory->CreateSwapChain(g_pd3dDevice, &sd, &data->SwapChain); + IM_ASSERT(data->SwapChain == NULL); + IM_ASSERT(data->FrameCtx[0].RenderTarget == NULL && data->FrameCtx[1].RenderTarget == NULL && data->FrameCtx[2].RenderTarget == NULL); - // Create the render target + IDXGIFactory4* dxgi_factory = nullptr; + res = CreateDXGIFactory1(IID_PPV_ARGS(&dxgi_factory)); + IM_ASSERT(res == S_OK); + + IDXGISwapChain1* swap_chain = nullptr; + res = dxgi_factory->CreateSwapChainForHwnd(data->CommandQueue, hwnd, &sd1, NULL, NULL, &swap_chain); + IM_ASSERT(res == S_OK); + + dxgi_factory->Release(); + + // Or swapChain.As(&mSwapChain) + swap_chain->QueryInterface(IID_PPV_ARGS(&data->SwapChain)); + + // Create the render targets if (data->SwapChain) { - ID3D11Texture2D* pBackBuffer; - data->SwapChain->GetBuffer(0, IID_PPV_ARGS(&pBackBuffer)); - g_pd3dDevice->CreateRenderTargetView(pBackBuffer, NULL, &data->RTView); - pBackBuffer->Release(); + D3D12_DESCRIPTOR_HEAP_DESC desc = {}; + desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; + desc.NumDescriptors = g_numFramesInFlight; + desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; + desc.NodeMask = 1; + + IM_ASSERT(g_pd3dDevice->CreateDescriptorHeap(&desc, IID_PPV_ARGS(&data->RtvDescHeap)) == S_OK); + + SIZE_T rtv_descriptor_size = g_pd3dDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); + D3D12_CPU_DESCRIPTOR_HANDLE rtv_handle = data->RtvDescHeap->GetCPUDescriptorHandleForHeapStart(); + for (UINT i = 0; i < g_numFramesInFlight; i++) + { + data->FrameCtx[i].RenderTargetCpuDescriptors = rtv_handle; + rtv_handle.ptr += rtv_descriptor_size; + } + + ID3D12Resource* back_buffer; + for (UINT i = 0; i < g_numFramesInFlight; i++) + { + data->SwapChain->GetBuffer(i, IID_PPV_ARGS(&back_buffer)); + g_pd3dDevice->CreateRenderTargetView(back_buffer, NULL, data->FrameCtx[i].RenderTargetCpuDescriptors); + data->FrameCtx[i].RenderTarget = back_buffer; + } } - */ + + for (UINT i = 0; i < g_numFramesInFlight; i++) + { + if (data->Resources[i].IndexBuffer) { data->Resources[i].VertexBuffer->Release(); data->Resources[i].IndexBuffer = NULL; } + if (data->Resources[i].VertexBuffer) { data->Resources[i].VertexBuffer->Release(); data->Resources[i].VertexBuffer = NULL; } + } +} + +template +void SafeRelease(D12Resource*& res) +{ + if (res) + res->Release(); + res = NULL; } static void ImGui_ImplDX12_DestroyWindow(ImGuiViewport* viewport) @@ -720,16 +848,22 @@ static void ImGui_ImplDX12_DestroyWindow(ImGuiViewport* viewport) // The main viewport (owned by the application) will always have RendererUserData == NULL since we didn't create the data for it. if (ImGuiViewportDataDx12* data = (ImGuiViewportDataDx12*)viewport->RendererUserData) { - IM_ASSERT(0); - /* - if (data->SwapChain) - data->SwapChain->Release(); - data->SwapChain = NULL; - if (data->RTView) - data->RTView->Release(); - data->RTView = NULL; + SafeRelease(data->CommandQueue); + SafeRelease(data->CommandList); + SafeRelease(data->SwapChain); + SafeRelease(data->RtvDescHeap); + SafeRelease(data->Fence); + CloseHandle(data->FenceEvent); data->FenceEvent = NULL; + + for (UINT i = 0; i < g_numFramesInFlight; i++) + { + SafeRelease(data->FrameCtx[i].RenderTarget); + SafeRelease(data->FrameCtx[i].CommandAllocator); + SafeRelease(data->Resources[i].IndexBuffer); + SafeRelease(data->Resources[i].VertexBuffer); + } + IM_DELETE(data); - */ } viewport->RendererUserData = NULL; } @@ -737,51 +871,79 @@ static void ImGui_ImplDX12_DestroyWindow(ImGuiViewport* viewport) static void ImGui_ImplDX12_SetWindowSize(ImGuiViewport* viewport, ImVec2 size) { ImGuiViewportDataDx12* data = (ImGuiViewportDataDx12*)viewport->RendererUserData; - IM_ASSERT(0); - (void)data; (void)size; - /* - if (data->RTView) + + for (UINT i = 0; i < g_numFramesInFlight; i++) { - data->RTView->Release(); - data->RTView = NULL; + SafeRelease(data->FrameCtx[i].RenderTarget); } + if (data->SwapChain) { - ID3D11Texture2D* pBackBuffer = NULL; + ID3D12Resource* back_buffer = NULL; data->SwapChain->ResizeBuffers(0, (UINT)size.x, (UINT)size.y, DXGI_FORMAT_UNKNOWN, 0); - data->SwapChain->GetBuffer(0, IID_PPV_ARGS(&pBackBuffer)); - g_pd3dDevice->CreateRenderTargetView(pBackBuffer, NULL, &data->RTView); - pBackBuffer->Release(); + for (UINT i = 0; i < g_numFramesInFlight; i++) + { + data->SwapChain->GetBuffer(i, IID_PPV_ARGS(&back_buffer)); + g_pd3dDevice->CreateRenderTargetView(back_buffer, NULL, data->FrameCtx[i].RenderTargetCpuDescriptors); + data->FrameCtx[i].RenderTarget = back_buffer; + } } - */ } -// arg = ID3D12GraphicsCommandList* -static void ImGui_ImplDX12_RenderWindow(ImGuiViewport* viewport, void* renderer_arg) +static void ImGui_ImplDX12_RenderWindow(ImGuiViewport* viewport, void*) { ImGuiViewportDataDx12* data = (ImGuiViewportDataDx12*)viewport->RendererUserData; - IM_ASSERT(0); - (void)data; - ID3D12GraphicsCommandList* command_list = (ID3D12GraphicsCommandList*)renderer_arg; - - /* ImVec4 clear_color = ImVec4(0.0f, 0.0f, 0.0f, 1.0f); - g_pd3dDeviceContext->OMSetRenderTargets(1, &data->RTView, NULL); + + //-- + FrameContext* frame_context = &data->FrameCtx[data->FrameIndex % g_numFramesInFlight]; + + UINT back_buffer_idx = data->SwapChain->GetCurrentBackBufferIndex(); + D3D12_RESOURCE_BARRIER barrier = {}; + barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; + barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; + barrier.Transition.pResource = data->FrameCtx[back_buffer_idx].RenderTarget; + barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; + barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT; + barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET; + + //-- draw + ID3D12GraphicsCommandList* cmd_list = data->CommandList; + + frame_context->CommandAllocator->Reset(); + cmd_list->Reset(frame_context->CommandAllocator, NULL); + cmd_list->ResourceBarrier(1, &barrier); + cmd_list->OMSetRenderTargets(1, &data->FrameCtx[back_buffer_idx].RenderTargetCpuDescriptors, FALSE, NULL); if (!(viewport->Flags & ImGuiViewportFlags_NoRendererClear)) - g_pd3dDeviceContext->ClearRenderTargetView(data->RTView, (float*)&clear_color); - */ - ImGui_ImplDX12_RenderDrawData(viewport->DrawData, command_list); + cmd_list->ClearRenderTargetView(data->FrameCtx[back_buffer_idx].RenderTargetCpuDescriptors, (float*)&clear_color, 0, NULL); + cmd_list->SetDescriptorHeaps(1, &g_pd3dSrvDescHeap); + + ImGui_ImplDX12_RenderDrawData(viewport->DrawData, cmd_list); + + barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET; + barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT; + cmd_list->ResourceBarrier(1, &barrier); + cmd_list->Close(); + + //-- + data->CommandQueue->Wait(data->Fence, data->FenceSignaledValue); + //-- + data->CommandQueue->ExecuteCommandLists(1, (ID3D12CommandList* const*)&cmd_list); + //-- + data->CommandQueue->Signal(data->Fence, ++data->FenceSignaledValue); } static void ImGui_ImplDX12_SwapBuffers(ImGuiViewport* viewport, void*) { ImGuiViewportDataDx12* data = (ImGuiViewportDataDx12*)viewport->RendererUserData; - IM_ASSERT(0); - (void)data; - /* - data->SwapChain->Present(0, 0); // Present without vsync - */ + + data->SwapChain->Present(0, 0); + + while (data->Fence->GetCompletedValue() < data->FenceSignaledValue) + { + SwitchToThread(); + } } void ImGui_ImplDX12_InitPlatformInterface() diff --git a/examples/imgui_impl_dx12.h b/examples/imgui_impl_dx12.h index 80c3bfa1..2d3b1fe6 100644 --- a/examples/imgui_impl_dx12.h +++ b/examples/imgui_impl_dx12.h @@ -4,8 +4,8 @@ // Implemented features: // [X] Renderer: User texture binding. Use 'D3D12_GPU_DESCRIPTOR_HANDLE' as ImTextureID. Read the FAQ about ImTextureID! // [X] Renderer: Support for large meshes (64k+ vertices) with 16-bits indices. +// [X] Renderer: Multi-viewport. // Missing features, issues: -// [ ] Renderer: Missing multi-viewport support. // [ ] 64-bit only for now! (Because sizeof(ImTextureId) == sizeof(void*)). See github.com/ocornut/imgui/pull/301 // You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this. @@ -16,6 +16,7 @@ enum DXGI_FORMAT; struct ID3D12Device; +struct ID3D12DescriptorHeap; struct ID3D12GraphicsCommandList; struct D3D12_CPU_DESCRIPTOR_HANDLE; struct D3D12_GPU_DESCRIPTOR_HANDLE; @@ -24,7 +25,7 @@ struct D3D12_GPU_DESCRIPTOR_HANDLE; // Before calling the render function, caller must prepare cmd_list by resetting it and setting the appropriate // render target and descriptor heap that contains font_srv_cpu_desc_handle/font_srv_gpu_desc_handle. // font_srv_cpu_desc_handle and font_srv_gpu_desc_handle are handles to a single SRV descriptor to use for the internal font texture. -IMGUI_IMPL_API bool ImGui_ImplDX12_Init(ID3D12Device* device, int num_frames_in_flight, DXGI_FORMAT rtv_format, +IMGUI_IMPL_API bool ImGui_ImplDX12_Init(ID3D12Device* device, int num_frames_in_flight, DXGI_FORMAT rtv_format, ID3D12DescriptorHeap* cbv_srv_heap, D3D12_CPU_DESCRIPTOR_HANDLE font_srv_cpu_desc_handle, D3D12_GPU_DESCRIPTOR_HANDLE font_srv_gpu_desc_handle); IMGUI_IMPL_API void ImGui_ImplDX12_Shutdown(); IMGUI_IMPL_API void ImGui_ImplDX12_NewFrame();