We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Version 1.90.5, Branch: docking
imgui_impl_dx12.cpp + imgui_impl_win32.cpp
Windows11 + msvc2022
Dear ImGui 1.90.5 (19050) -------------------------------- sizeof(size_t): 8, sizeof(ImDrawIdx): 2, sizeof(ImDrawVert): 20 define: __cplusplus=199711 define: _WIN32 define: _WIN64 define: _MSC_VER=1938 define: _MSVC_LANG=201402 define: IMGUI_HAS_VIEWPORT define: IMGUI_HAS_DOCK -------------------------------- io.BackendPlatformName: imgui_impl_win32 io.BackendRendererName: imgui_impl_dx12 io.ConfigFlags: 0x00000443 NavEnableKeyboard NavEnableGamepad DockingEnable ViewportsEnable io.ConfigViewportsNoDecoration io.ConfigInputTextCursorBlink io.ConfigWindowsResizeFromEdges io.ConfigMemoryCompactTimer = 60.0 io.BackendFlags: 0x00001C0E HasMouseCursors HasSetMousePos PlatformHasViewports HasMouseHoveredViewport RendererHasVtxOffset RendererHasViewports -------------------------------- io.Fonts: 1 fonts, Flags: 0x00000000, TexSize: 512,64 io.DisplaySize: 983.00,744.00 io.DisplayFramebufferScale: 1.00,1.00 -------------------------------- style.WindowPadding: 8.00,8.00 style.WindowBorderSize: 1.00 style.FramePadding: 4.00,3.00 style.FrameRounding: 0.00 style.FrameBorderSize: 0.00 style.ItemSpacing: 8.00,4.00 style.ItemInnerSpacing: 4.00,4.00
My Issue/Question:
I would like to display the rendering result in ImGui::Image.
If the viewport is in the main window, it can be resized without problems.
If the viewport is outside the main window, the rendering result is wrong during resizing.
Could you please let me know if there is a solution to this problem.
// Dear ImGui: standalone example application for DirectX 12 // Learn about Dear ImGui: // - FAQ https://dearimgui.com/faq // - Getting Started https://dearimgui.com/getting-started // - Documentation https://dearimgui.com/docs (same as your local docs/ folder). // - Introduction, links and more at the top of imgui.cpp // Important: to compile on 32-bit systems, the DirectX12 backend requires code to be compiled with '#define ImTextureID ImU64'. // This is because we need ImTextureID to carry a 64-bit value and by default ImTextureID is defined as void*. // This define is set in the example .vcxproj file and need to be replicated in your app or by adding it to your imconfig.h file. #include "imgui.h" #include "imgui_impl_win32.h" #include "imgui_impl_dx12.h" #include <d3d12.h> #include <dxgi1_4.h> #include <d3dcompiler.h> #include <tchar.h> #ifdef _DEBUG #define DX12_ENABLE_DEBUG_LAYER #endif #ifdef DX12_ENABLE_DEBUG_LAYER #include <dxgidebug.h> #pragma comment(lib, "dxguid.lib") #endif struct FrameContext { ID3D12CommandAllocator* CommandAllocator; UINT64 FenceValue; }; // Data static int const NUM_FRAMES_IN_FLIGHT = 3; static FrameContext g_frameContext[NUM_FRAMES_IN_FLIGHT] = {}; static UINT g_frameIndex = 0; static int const NUM_BACK_BUFFERS = 3; static ID3D12Device* g_pd3dDevice = nullptr; static ID3D12DescriptorHeap* g_pd3dRtvDescHeap = nullptr; static ID3D12DescriptorHeap* g_pd3dSrvDescHeap = nullptr; static ID3D12CommandQueue* g_pd3dCommandQueue = nullptr; static ID3D12GraphicsCommandList* g_pd3dCommandList = nullptr; static ID3D12Fence* g_fence = nullptr; static HANDLE g_fenceEvent = nullptr; static UINT64 g_fenceLastSignaledValue = 0; static IDXGISwapChain3* g_pSwapChain = nullptr; static HANDLE g_hSwapChainWaitableObject = nullptr; static ID3D12Resource* g_mainRenderTargetResource[NUM_BACK_BUFFERS] = {}; static D3D12_CPU_DESCRIPTOR_HANDLE g_mainRenderTargetDescriptor[NUM_BACK_BUFFERS] = {}; // Forward declarations of helper functions void CreateFramebuffer(UINT64 w, UINT64 h, ID3D12Resource** framebuffer, ID3D12DescriptorHeap* ColorTargetDescHeap, ID3D12DescriptorHeap* TextureDescHeap); bool CreateDeviceD3D(HWND hWnd); void CleanupDeviceD3D(); void CreateRenderTarget(); void CleanupRenderTarget(); void WaitForLastSubmittedFrame(); FrameContext* WaitForNextFrameResources(); LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); // Main code int main(int, char**) { // Create application window //ImGui_ImplWin32_EnableDpiAwareness(); WNDCLASSEXW wc = { sizeof(wc), CS_CLASSDC, WndProc, 0L, 0L, GetModuleHandle(nullptr), nullptr, nullptr, nullptr, nullptr, L"ImGui Example", nullptr }; ::RegisterClassExW(&wc); HWND hwnd = ::CreateWindowW(wc.lpszClassName, L"Dear ImGui DirectX12 Example", WS_OVERLAPPEDWINDOW, 100, 100, 1280, 800, nullptr, nullptr, wc.hInstance, nullptr); // Initialize Direct3D if (!CreateDeviceD3D(hwnd)) { CleanupDeviceD3D(); ::UnregisterClassW(wc.lpszClassName, wc.hInstance); return 1; } // Show the window ::ShowWindow(hwnd, SW_SHOWDEFAULT); ::UpdateWindow(hwnd); // Setup Dear ImGui context IMGUI_CHECKVERSION(); ImGui::CreateContext(); ImGuiIO& io = ImGui::GetIO(); (void)io; 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 //io.ConfigViewportsNoAutoMerge = true; //io.ConfigViewportsNoTaskBarIcon = true; // Setup Dear ImGui style ImGui::StyleColorsDark(); //ImGui::StyleColorsLight(); // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones. ImGuiStyle& style = ImGui::GetStyle(); if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) { style.WindowRounding = 0.0f; style.Colors[ImGuiCol_WindowBg].w = 1.0f; } // Setup Platform/Renderer backends ImGui_ImplWin32_Init(hwnd); ImGui_ImplDX12_Init(g_pd3dDevice, NUM_FRAMES_IN_FLIGHT, DXGI_FORMAT_R8G8B8A8_UNORM, g_pd3dSrvDescHeap, g_pd3dSrvDescHeap->GetCPUDescriptorHandleForHeapStart(), g_pd3dSrvDescHeap->GetGPUDescriptorHandleForHeapStart()); // Load Fonts // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. // - If the file cannot be loaded, the function will return a nullptr. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call. // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering. // - Read 'docs/FONTS.md' for more instructions and details. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! //io.Fonts->AddFontDefault(); //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf", 18.0f); //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f); //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f); //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, nullptr, io.Fonts->GetGlyphRangesJapanese()); //IM_ASSERT(font != nullptr); // Our state bool show_demo_window = true; bool show_another_window = false; ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f); UINT64 ColorTargetWidth = 0, ColorTargetHeight = 0; ID3D12Resource* ColorTargetResource{ nullptr }; ID3D12DescriptorHeap* ColorTargetDescHeap{ nullptr }; ID3D12DescriptorHeap* TextureDescHeap{ nullptr }; { D3D12_DESCRIPTOR_HEAP_DESC desc = {}; desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; desc.NumDescriptors = 1; desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; g_pd3dDevice->CreateDescriptorHeap(&desc, IID_PPV_ARGS(&ColorTargetDescHeap)); desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; g_pd3dDevice->CreateDescriptorHeap(&desc, IID_PPV_ARGS(&TextureDescHeap)); } const UINT64 GlobalHeapStart = 1; const UINT64 GlobalHeapLast = 1'000'000 - 1; UINT64 GlobalHeapOffset = GlobalHeapStart; const UINT HeapIncementSize = g_pd3dDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); ID3D12RootSignature* signature{ nullptr }; { D3D12_VERSIONED_ROOT_SIGNATURE_DESC desc{}; desc.Version = D3D_ROOT_SIGNATURE_VERSION_1_0; desc.Desc_1_0.NumParameters = 0; desc.Desc_1_0.pParameters = nullptr; desc.Desc_1_0.NumStaticSamplers = 0; desc.Desc_1_0.pStaticSamplers = nullptr; desc.Desc_1_0.Flags = D3D12_ROOT_SIGNATURE_FLAG_NONE; ID3DBlob* blob{ nullptr }, * error{ nullptr }; D3D12SerializeVersionedRootSignature(&desc, &blob, &error); g_pd3dDevice->CreateRootSignature(0, blob->GetBufferPointer(), blob->GetBufferSize(), IID_PPV_ARGS(&signature)); if (blob) blob->Release(); if (error) error->Release(); } ID3D12PipelineState* PipelineState{ nullptr }; { ID3DBlob* vs{ nullptr }; ID3DBlob* ps{ nullptr }; { static const char* vs_hlsl = R"( float4 main(uint VertexID : SV_VertexID) : SV_POSITION { float4 Pos[3]; Pos[0] = float4(-0.5, -0.5, 0.0, 1.0); Pos[1] = float4(+0.5, -0.5, 0.0, 1.0); Pos[2] = float4( 0.0, +0.5, 0.0, 1.0); return Pos[VertexID]; })"; static const char* ps_hlsl = R"( float4 main() : SV_TARGET0 { return float4(0, 1, 0, 1); })"; D3DCompile(vs_hlsl, strlen(vs_hlsl), nullptr, nullptr, nullptr, "main", "vs_5_0", 0, 0, &vs, nullptr); D3DCompile(ps_hlsl, strlen(ps_hlsl), nullptr, nullptr, nullptr, "main", "ps_5_0", 0, 0, &ps, nullptr); } D3D12_GRAPHICS_PIPELINE_STATE_DESC desc{}; desc.pRootSignature = signature; desc.VS = { vs->GetBufferPointer(), vs->GetBufferSize() }; desc.PS = { ps->GetBufferPointer(), ps->GetBufferSize() }; desc.BlendState.AlphaToCoverageEnable = FALSE; desc.BlendState.IndependentBlendEnable = FALSE; desc.BlendState.RenderTarget[0].BlendEnable = FALSE; desc.BlendState.RenderTarget[0].LogicOpEnable = FALSE; desc.BlendState.RenderTarget[0].RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL; desc.SampleMask = D3D12_DEFAULT_SAMPLE_MASK; desc.RasterizerState.MultisampleEnable = false; desc.RasterizerState.CullMode = D3D12_CULL_MODE_NONE; desc.RasterizerState.FillMode = D3D12_FILL_MODE_SOLID; desc.RasterizerState.DepthClipEnable = true; desc.DepthStencilState.DepthEnable = FALSE; desc.InputLayout.pInputElementDescs = nullptr; desc.InputLayout.NumElements = 0; desc.IBStripCutValue = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_DISABLED; desc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; desc.NumRenderTargets = 1; desc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM; desc.SampleDesc.Count = 1; desc.NodeMask = 0; desc.Flags = D3D12_PIPELINE_STATE_FLAG_NONE; g_pd3dDevice->CreateGraphicsPipelineState(&desc, IID_PPV_ARGS(&PipelineState)); assert(PipelineState); vs->Release(); ps->Release(); } // Main loop bool done = false; while (!done) { // Poll and handle messages (inputs, window resize, etc.) // See the WndProc() function below for our to dispatch events to the Win32 backend. MSG msg; while (::PeekMessage(&msg, nullptr, 0U, 0U, PM_REMOVE)) { ::TranslateMessage(&msg); ::DispatchMessage(&msg); if (msg.message == WM_QUIT) done = true; } if (done) break; // Start the Dear ImGui frame ImGui_ImplDX12_NewFrame(); ImGui_ImplWin32_NewFrame(); ImGui::NewFrame(); if (ImGui::Begin("Viewport")) { if (ImGui::BeginChild("ViewportChild")) { // Resize ColorTarget const ImVec2 window_size = ImGui::GetContentRegionAvail(); if (ColorTargetWidth != window_size.x || ColorTargetHeight != window_size.y) { static int count = 0; ColorTargetWidth = window_size.x; ColorTargetHeight = window_size.y; CreateFramebuffer(ColorTargetWidth, ColorTargetHeight, &ColorTargetResource, ColorTargetDescHeap, TextureDescHeap); ColorTargetResource->SetName(L"ColorTarget"); } // Copy to shader visible descriptor heap auto CpuHandleShaderVisibleHeap = g_pd3dSrvDescHeap->GetCPUDescriptorHandleForHeapStart(); CpuHandleShaderVisibleHeap.ptr += GlobalHeapOffset * HeapIncementSize; g_pd3dDevice->CopyDescriptorsSimple(1, CpuHandleShaderVisibleHeap, TextureDescHeap->GetCPUDescriptorHandleForHeapStart(), D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); // Image auto GpuHandleShaderVisibleHeap = g_pd3dSrvDescHeap->GetGPUDescriptorHandleForHeapStart(); GpuHandleShaderVisibleHeap.ptr += GlobalHeapOffset * HeapIncementSize; ImGui::Image((ImTextureID)(GpuHandleShaderVisibleHeap.ptr), window_size); GlobalHeapOffset = GlobalHeapOffset == GlobalHeapLast ? GlobalHeapStart : GlobalHeapOffset + 1; } ImGui::EndChild(); } ImGui::ShowDemoWindow(); ImGui::End(); // Rendering ImGui::Render(); FrameContext* frameCtx = WaitForNextFrameResources(); UINT backBufferIdx = g_pSwapChain->GetCurrentBackBufferIndex(); frameCtx->CommandAllocator->Reset(); D3D12_RESOURCE_BARRIER barrier = {}; barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; barrier.Transition.pResource = g_mainRenderTargetResource[backBufferIdx]; barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT; barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET; g_pd3dCommandList->Reset(frameCtx->CommandAllocator, nullptr); g_pd3dCommandList->ResourceBarrier(1, &barrier); g_pd3dCommandList->SetGraphicsRootSignature(signature); g_pd3dCommandList->SetDescriptorHeaps(1, &g_pd3dSrvDescHeap); { D3D12_RESOURCE_BARRIER desc[1]{}; desc[0].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; desc[0].Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; desc[0].Transition.pResource = ColorTargetResource; desc[0].Transition.StateBefore = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE; desc[0].Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET; desc[0].Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; g_pd3dCommandList->ResourceBarrier(_countof(desc), desc); D3D12_VIEWPORT viewport{}; viewport.Width = ColorTargetWidth; viewport.Height = ColorTargetHeight; viewport.MinDepth = 0.0; viewport.MaxDepth = 1.0f; viewport.TopLeftX = 0.0f; viewport.TopLeftY = 0.0f; g_pd3dCommandList->RSSetViewports(1, &viewport); D3D12_RECT rect{}; rect.left = 0; rect.top = 0; rect.right = LONG(ColorTargetWidth); rect.bottom = LONG(ColorTargetHeight); g_pd3dCommandList->RSSetScissorRects(1, &rect); const D3D12_CPU_DESCRIPTOR_HANDLE rtvs[]{ ColorTargetDescHeap->GetCPUDescriptorHandleForHeapStart() }; const FLOAT ClearColor[4]{ 1.0f, 0.0f, 0.0f, 1.0f }; g_pd3dCommandList->ClearRenderTargetView(rtvs[0], ClearColor, 0, nullptr); g_pd3dCommandList->OMSetRenderTargets(_countof(rtvs), rtvs, false, nullptr); g_pd3dCommandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); g_pd3dCommandList->SetPipelineState(PipelineState); g_pd3dCommandList->DrawInstanced(3, 1, 0, 0); desc[0].Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET; desc[0].Transition.StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE; g_pd3dCommandList->ResourceBarrier(_countof(desc), desc); } // Render Dear ImGui graphics const float clear_color_with_alpha[4] = { clear_color.x * clear_color.w, clear_color.y * clear_color.w, clear_color.z * clear_color.w, clear_color.w }; g_pd3dCommandList->ClearRenderTargetView(g_mainRenderTargetDescriptor[backBufferIdx], clear_color_with_alpha, 0, nullptr); g_pd3dCommandList->OMSetRenderTargets(1, &g_mainRenderTargetDescriptor[backBufferIdx], FALSE, nullptr); g_pd3dCommandList->SetDescriptorHeaps(1, &g_pd3dSrvDescHeap); ImGui_ImplDX12_RenderDrawData(ImGui::GetDrawData(), g_pd3dCommandList); barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET; barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT; g_pd3dCommandList->ResourceBarrier(1, &barrier); g_pd3dCommandList->Close(); g_pd3dCommandQueue->ExecuteCommandLists(1, (ID3D12CommandList* const*)&g_pd3dCommandList); // Update and Render additional Platform Windows if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) { ImGui::UpdatePlatformWindows(); ImGui::RenderPlatformWindowsDefault(nullptr, (void*)g_pd3dCommandList); } g_pSwapChain->Present(1, 0); // Present with vsync //g_pSwapChain->Present(0, 0); // Present without vsync UINT64 fenceValue = g_fenceLastSignaledValue + 1; g_pd3dCommandQueue->Signal(g_fence, fenceValue); g_fenceLastSignaledValue = fenceValue; frameCtx->FenceValue = fenceValue; } WaitForLastSubmittedFrame(); // Cleanup ImGui_ImplDX12_Shutdown(); ImGui_ImplWin32_Shutdown(); ImGui::DestroyContext(); CleanupDeviceD3D(); ::DestroyWindow(hwnd); ::UnregisterClassW(wc.lpszClassName, wc.hInstance); return 0; } void CreateFramebuffer(UINT64 w, UINT64 h, ID3D12Resource** framebuffer, ID3D12DescriptorHeap* ColorTargetDescHeap, ID3D12DescriptorHeap* TextureDescHeap) { HRESULT hr{}; { D3D12_HEAP_PROPERTIES heap{}; heap.Type = D3D12_HEAP_TYPE_DEFAULT; D3D12_RESOURCE_DESC desc{}; desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; desc.Alignment = 0; desc.Width = w; desc.Height = h; desc.DepthOrArraySize = 1; desc.MipLevels = 1; desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; desc.SampleDesc.Count = 1; desc.SampleDesc.Quality = 0; desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET; desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; D3D12_CLEAR_VALUE clear_color{}; clear_color.Format = DXGI_FORMAT_R8G8B8A8_UNORM; clear_color.Color[0] = 1.0f; clear_color.Color[1] = 0.0f; clear_color.Color[2] = 0.0f; clear_color.Color[3] = 1.0f; g_pd3dDevice->CreateCommittedResource( &heap, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, &clear_color, IID_PPV_ARGS(framebuffer)); } { D3D12_RENDER_TARGET_VIEW_DESC desc{}; desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D; g_pd3dDevice->CreateRenderTargetView(*framebuffer, &desc, ColorTargetDescHeap->GetCPUDescriptorHandleForHeapStart()); } { D3D12_SHADER_RESOURCE_VIEW_DESC desc{}; desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; desc.Texture2D.MipLevels = 1; desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; g_pd3dDevice->CreateShaderResourceView(*framebuffer, &desc, TextureDescHeap->GetCPUDescriptorHandleForHeapStart()); } } // Helper functions bool CreateDeviceD3D(HWND hWnd) { // Setup swap chain DXGI_SWAP_CHAIN_DESC1 sd; { ZeroMemory(&sd, sizeof(sd)); sd.BufferCount = NUM_BACK_BUFFERS; sd.Width = 0; sd.Height = 0; sd.Format = DXGI_FORMAT_R8G8B8A8_UNORM; sd.Flags = DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT; sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; sd.SampleDesc.Count = 1; sd.SampleDesc.Quality = 0; sd.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; sd.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED; sd.Scaling = DXGI_SCALING_STRETCH; sd.Stereo = FALSE; } // [DEBUG] Enable debug interface #ifdef DX12_ENABLE_DEBUG_LAYER ID3D12Debug* pdx12Debug = nullptr; if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&pdx12Debug)))) pdx12Debug->EnableDebugLayer(); #endif // Create device D3D_FEATURE_LEVEL featureLevel = D3D_FEATURE_LEVEL_11_0; if (D3D12CreateDevice(nullptr, featureLevel, IID_PPV_ARGS(&g_pd3dDevice)) != S_OK) return false; // [DEBUG] Setup debug interface to break on any warnings/errors #ifdef DX12_ENABLE_DEBUG_LAYER if (pdx12Debug != nullptr) { ID3D12InfoQueue* pInfoQueue = nullptr; g_pd3dDevice->QueryInterface(IID_PPV_ARGS(&pInfoQueue)); pInfoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_ERROR, true); pInfoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_CORRUPTION, true); pInfoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_WARNING, true); pInfoQueue->Release(); pdx12Debug->Release(); } #endif { D3D12_DESCRIPTOR_HEAP_DESC desc = {}; desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; desc.NumDescriptors = NUM_BACK_BUFFERS; desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; desc.NodeMask = 1; if (g_pd3dDevice->CreateDescriptorHeap(&desc, IID_PPV_ARGS(&g_pd3dRtvDescHeap)) != S_OK) return false; SIZE_T rtvDescriptorSize = g_pd3dDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = g_pd3dRtvDescHeap->GetCPUDescriptorHandleForHeapStart(); for (UINT i = 0; i < NUM_BACK_BUFFERS; i++) { g_mainRenderTargetDescriptor[i] = rtvHandle; rtvHandle.ptr += rtvDescriptorSize; } } { D3D12_DESCRIPTOR_HEAP_DESC desc = {}; desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; //desc.NumDescriptors = 1; desc.NumDescriptors = 1'000'000; desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; if (g_pd3dDevice->CreateDescriptorHeap(&desc, IID_PPV_ARGS(&g_pd3dSrvDescHeap)) != S_OK) return false; } { D3D12_COMMAND_QUEUE_DESC desc = {}; desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; desc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; desc.NodeMask = 1; if (g_pd3dDevice->CreateCommandQueue(&desc, IID_PPV_ARGS(&g_pd3dCommandQueue)) != S_OK) return false; } for (UINT i = 0; i < NUM_FRAMES_IN_FLIGHT; i++) if (g_pd3dDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&g_frameContext[i].CommandAllocator)) != S_OK) return false; if (g_pd3dDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, g_frameContext[0].CommandAllocator, nullptr, IID_PPV_ARGS(&g_pd3dCommandList)) != S_OK || g_pd3dCommandList->Close() != S_OK) return false; if (g_pd3dDevice->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&g_fence)) != S_OK) return false; g_fenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr); if (g_fenceEvent == nullptr) return false; { IDXGIFactory4* dxgiFactory = nullptr; IDXGISwapChain1* swapChain1 = nullptr; if (CreateDXGIFactory1(IID_PPV_ARGS(&dxgiFactory)) != S_OK) return false; if (dxgiFactory->CreateSwapChainForHwnd(g_pd3dCommandQueue, hWnd, &sd, nullptr, nullptr, &swapChain1) != S_OK) return false; if (swapChain1->QueryInterface(IID_PPV_ARGS(&g_pSwapChain)) != S_OK) return false; swapChain1->Release(); dxgiFactory->Release(); g_pSwapChain->SetMaximumFrameLatency(NUM_BACK_BUFFERS); g_hSwapChainWaitableObject = g_pSwapChain->GetFrameLatencyWaitableObject(); } CreateRenderTarget(); return true; } void CleanupDeviceD3D() { CleanupRenderTarget(); if (g_pSwapChain) { g_pSwapChain->SetFullscreenState(false, nullptr); g_pSwapChain->Release(); g_pSwapChain = nullptr; } if (g_hSwapChainWaitableObject != nullptr) { CloseHandle(g_hSwapChainWaitableObject); } for (UINT i = 0; i < NUM_FRAMES_IN_FLIGHT; i++) if (g_frameContext[i].CommandAllocator) { g_frameContext[i].CommandAllocator->Release(); g_frameContext[i].CommandAllocator = nullptr; } if (g_pd3dCommandQueue) { g_pd3dCommandQueue->Release(); g_pd3dCommandQueue = nullptr; } if (g_pd3dCommandList) { g_pd3dCommandList->Release(); g_pd3dCommandList = nullptr; } if (g_pd3dRtvDescHeap) { g_pd3dRtvDescHeap->Release(); g_pd3dRtvDescHeap = nullptr; } if (g_pd3dSrvDescHeap) { g_pd3dSrvDescHeap->Release(); g_pd3dSrvDescHeap = nullptr; } if (g_fence) { g_fence->Release(); g_fence = nullptr; } if (g_fenceEvent) { CloseHandle(g_fenceEvent); g_fenceEvent = nullptr; } if (g_pd3dDevice) { g_pd3dDevice->Release(); g_pd3dDevice = nullptr; } #ifdef DX12_ENABLE_DEBUG_LAYER IDXGIDebug1* pDebug = nullptr; //if (SUCCEEDED(DXGIGetDebugInterface1(0, IID_PPV_ARGS(&pDebug)))) //{ // pDebug->ReportLiveObjects(DXGI_DEBUG_ALL, DXGI_DEBUG_RLO_SUMMARY); // pDebug->Release(); //} #endif } void CreateRenderTarget() { for (UINT i = 0; i < NUM_BACK_BUFFERS; i++) { ID3D12Resource* pBackBuffer = nullptr; g_pSwapChain->GetBuffer(i, IID_PPV_ARGS(&pBackBuffer)); g_pd3dDevice->CreateRenderTargetView(pBackBuffer, nullptr, g_mainRenderTargetDescriptor[i]); g_mainRenderTargetResource[i] = pBackBuffer; } } void CleanupRenderTarget() { WaitForLastSubmittedFrame(); for (UINT i = 0; i < NUM_BACK_BUFFERS; i++) if (g_mainRenderTargetResource[i]) { g_mainRenderTargetResource[i]->Release(); g_mainRenderTargetResource[i] = nullptr; } } void WaitForLastSubmittedFrame() { FrameContext* frameCtx = &g_frameContext[g_frameIndex % NUM_FRAMES_IN_FLIGHT]; UINT64 fenceValue = frameCtx->FenceValue; if (fenceValue == 0) 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() { UINT nextFrameIndex = g_frameIndex + 1; g_frameIndex = nextFrameIndex; HANDLE waitableObjects[] = { g_hSwapChainWaitableObject, nullptr }; DWORD numWaitableObjects = 1; FrameContext* frameCtx = &g_frameContext[nextFrameIndex % NUM_FRAMES_IN_FLIGHT]; UINT64 fenceValue = frameCtx->FenceValue; if (fenceValue != 0) // means no fence was signaled { frameCtx->FenceValue = 0; g_fence->SetEventOnCompletion(fenceValue, g_fenceEvent); waitableObjects[1] = g_fenceEvent; numWaitableObjects = 2; } WaitForMultipleObjects(numWaitableObjects, waitableObjects, TRUE, INFINITE); return frameCtx; } // Forward declare message handler from imgui_impl_win32.cpp extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); // Win32 message handler // You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs. // - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or clear/overwrite your copy of the mouse data. // - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data. // Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags. LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { if (ImGui_ImplWin32_WndProcHandler(hWnd, msg, wParam, lParam)) return true; switch (msg) { case WM_SIZE: if (g_pd3dDevice != nullptr && wParam != SIZE_MINIMIZED) { WaitForLastSubmittedFrame(); CleanupRenderTarget(); 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."); CreateRenderTarget(); } return 0; case WM_SYSCOMMAND: if ((wParam & 0xfff0) == SC_KEYMENU) // Disable ALT application menu return 0; break; case WM_DESTROY: ::PostQuitMessage(0); return 0; } return ::DefWindowProcW(hWnd, msg, wParam, lParam); }
The text was updated successfully, but these errors were encountered:
I append.
I assume it is a CommandQueues synchronization issue.
For a single window, there is one CommandQueue.
Therefore, GUI is drawed after drawing of a triangle.
On the other hand, for multiple windows, I think it is not guaranteed.
The CommandQueue of ImGuiViewport should wait for a signal from my CommandQueue.
But the CommandQueue of ImGuiViewport is hidden in imgui_impl_dx12.cpp
Sorry, something went wrong.
No branches or pull requests
Version/Branch of Dear ImGui:
Version 1.90.5, Branch: docking
Back-ends:
imgui_impl_dx12.cpp + imgui_impl_win32.cpp
Compiler, OS:
Windows11 + msvc2022
Full config/build information:
Details:
My Issue/Question:
I would like to display the rendering result in ImGui::Image.
If the viewport is in the main window, it can be resized without problems.
If the viewport is outside the main window, the rendering result is wrong during resizing.
Could you please let me know if there is a solution to this problem.
Screenshots/Video:
Minimal, Complete and Verifiable Example code:
The text was updated successfully, but these errors were encountered: