main.cpp (20027B)
1 // Dear ImGui: standalone example application for DirectX 12 2 // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp. 3 // Read online: https://github.com/ocornut/imgui/tree/master/docs 4 5 // Important: to compile on 32-bit systems, the DirectX12 backend requires code to be compiled with '#define ImTextureID ImU64'. 6 // This is because we need ImTextureID to carry a 64-bit value and by default ImTextureID is defined as void*. 7 // 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. 8 9 #include "imgui.h" 10 #include "imgui_impl_win32.h" 11 #include "imgui_impl_dx12.h" 12 #include <d3d12.h> 13 #include <dxgi1_4.h> 14 #include <tchar.h> 15 16 #ifdef _DEBUG 17 #define DX12_ENABLE_DEBUG_LAYER 18 #endif 19 20 #ifdef DX12_ENABLE_DEBUG_LAYER 21 #include <dxgidebug.h> 22 #pragma comment(lib, "dxguid.lib") 23 #endif 24 25 struct FrameContext 26 { 27 ID3D12CommandAllocator* CommandAllocator; 28 UINT64 FenceValue; 29 }; 30 31 // Data 32 static int const NUM_FRAMES_IN_FLIGHT = 3; 33 static FrameContext g_frameContext[NUM_FRAMES_IN_FLIGHT] = {}; 34 static UINT g_frameIndex = 0; 35 36 static int const NUM_BACK_BUFFERS = 3; 37 static ID3D12Device* g_pd3dDevice = NULL; 38 static ID3D12DescriptorHeap* g_pd3dRtvDescHeap = NULL; 39 static ID3D12DescriptorHeap* g_pd3dSrvDescHeap = NULL; 40 static ID3D12CommandQueue* g_pd3dCommandQueue = NULL; 41 static ID3D12GraphicsCommandList* g_pd3dCommandList = NULL; 42 static ID3D12Fence* g_fence = NULL; 43 static HANDLE g_fenceEvent = NULL; 44 static UINT64 g_fenceLastSignaledValue = 0; 45 static IDXGISwapChain3* g_pSwapChain = NULL; 46 static HANDLE g_hSwapChainWaitableObject = NULL; 47 static ID3D12Resource* g_mainRenderTargetResource[NUM_BACK_BUFFERS] = {}; 48 static D3D12_CPU_DESCRIPTOR_HANDLE g_mainRenderTargetDescriptor[NUM_BACK_BUFFERS] = {}; 49 50 // Forward declarations of helper functions 51 bool CreateDeviceD3D(HWND hWnd); 52 void CleanupDeviceD3D(); 53 void CreateRenderTarget(); 54 void CleanupRenderTarget(); 55 void WaitForLastSubmittedFrame(); 56 FrameContext* WaitForNextFrameResources(); 57 void ResizeSwapChain(HWND hWnd, int width, int height); 58 LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); 59 60 // Main code 61 int main(int, char**) 62 { 63 // Create application window 64 //ImGui_ImplWin32_EnableDpiAwareness(); 65 WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, WndProc, 0L, 0L, GetModuleHandle(NULL), NULL, NULL, NULL, NULL, _T("ImGui Example"), NULL }; 66 ::RegisterClassEx(&wc); 67 HWND hwnd = ::CreateWindow(wc.lpszClassName, _T("Dear ImGui DirectX12 Example"), WS_OVERLAPPEDWINDOW, 100, 100, 1280, 800, NULL, NULL, wc.hInstance, NULL); 68 69 // Initialize Direct3D 70 if (!CreateDeviceD3D(hwnd)) 71 { 72 CleanupDeviceD3D(); 73 ::UnregisterClass(wc.lpszClassName, wc.hInstance); 74 return 1; 75 } 76 77 // Show the window 78 ::ShowWindow(hwnd, SW_SHOWDEFAULT); 79 ::UpdateWindow(hwnd); 80 81 // Setup Dear ImGui context 82 IMGUI_CHECKVERSION(); 83 ImGui::CreateContext(); 84 ImGuiIO& io = ImGui::GetIO(); (void)io; 85 //io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls 86 //io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls 87 88 // Setup Dear ImGui style 89 ImGui::StyleColorsDark(); 90 //ImGui::StyleColorsClassic(); 91 92 // Setup Platform/Renderer backends 93 ImGui_ImplWin32_Init(hwnd); 94 ImGui_ImplDX12_Init(g_pd3dDevice, NUM_FRAMES_IN_FLIGHT, 95 DXGI_FORMAT_R8G8B8A8_UNORM, g_pd3dSrvDescHeap, 96 g_pd3dSrvDescHeap->GetCPUDescriptorHandleForHeapStart(), 97 g_pd3dSrvDescHeap->GetGPUDescriptorHandleForHeapStart()); 98 99 // Load Fonts 100 // - 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. 101 // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. 102 // - If the file cannot be loaded, the function will return NULL. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). 103 // - 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. 104 // - Read 'docs/FONTS.md' for more instructions and details. 105 // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! 106 //io.Fonts->AddFontDefault(); 107 //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); 108 //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f); 109 //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f); 110 //io.Fonts->AddFontFromFileTTF("../../misc/fonts/ProggyTiny.ttf", 10.0f); 111 //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, NULL, io.Fonts->GetGlyphRangesJapanese()); 112 //IM_ASSERT(font != NULL); 113 114 // Our state 115 bool show_demo_window = true; 116 bool show_another_window = false; 117 ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f); 118 119 // Main loop 120 bool done = false; 121 while (!done) 122 { 123 // Poll and handle messages (inputs, window resize, etc.) 124 // You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs. 125 // - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application. 126 // - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application. 127 // Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags. 128 MSG msg; 129 while (::PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE)) 130 { 131 ::TranslateMessage(&msg); 132 ::DispatchMessage(&msg); 133 if (msg.message == WM_QUIT) 134 done = true; 135 } 136 if (done) 137 break; 138 139 // Start the Dear ImGui frame 140 ImGui_ImplDX12_NewFrame(); 141 ImGui_ImplWin32_NewFrame(); 142 ImGui::NewFrame(); 143 144 // 1. Show the big demo window (Most of the sample code is in ImGui::ShowDemoWindow()! You can browse its code to learn more about Dear ImGui!). 145 if (show_demo_window) 146 ImGui::ShowDemoWindow(&show_demo_window); 147 148 // 2. Show a simple window that we create ourselves. We use a Begin/End pair to created a named window. 149 { 150 static float f = 0.0f; 151 static int counter = 0; 152 153 ImGui::Begin("Hello, world!"); // Create a window called "Hello, world!" and append into it. 154 155 ImGui::Text("This is some useful text."); // Display some text (you can use a format strings too) 156 ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our window open/close state 157 ImGui::Checkbox("Another Window", &show_another_window); 158 159 ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f 160 ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color 161 162 if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated) 163 counter++; 164 ImGui::SameLine(); 165 ImGui::Text("counter = %d", counter); 166 167 ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); 168 ImGui::End(); 169 } 170 171 // 3. Show another simple window. 172 if (show_another_window) 173 { 174 ImGui::Begin("Another Window", &show_another_window); // Pass a pointer to our bool variable (the window will have a closing button that will clear the bool when clicked) 175 ImGui::Text("Hello from another window!"); 176 if (ImGui::Button("Close Me")) 177 show_another_window = false; 178 ImGui::End(); 179 } 180 181 // Rendering 182 ImGui::Render(); 183 184 FrameContext* frameCtx = WaitForNextFrameResources(); 185 UINT backBufferIdx = g_pSwapChain->GetCurrentBackBufferIndex(); 186 frameCtx->CommandAllocator->Reset(); 187 188 D3D12_RESOURCE_BARRIER barrier = {}; 189 barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; 190 barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; 191 barrier.Transition.pResource = g_mainRenderTargetResource[backBufferIdx]; 192 barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; 193 barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT; 194 barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET; 195 g_pd3dCommandList->Reset(frameCtx->CommandAllocator, NULL); 196 g_pd3dCommandList->ResourceBarrier(1, &barrier); 197 198 // Render Dear ImGui graphics 199 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 }; 200 g_pd3dCommandList->ClearRenderTargetView(g_mainRenderTargetDescriptor[backBufferIdx], clear_color_with_alpha, 0, NULL); 201 g_pd3dCommandList->OMSetRenderTargets(1, &g_mainRenderTargetDescriptor[backBufferIdx], FALSE, NULL); 202 g_pd3dCommandList->SetDescriptorHeaps(1, &g_pd3dSrvDescHeap); 203 ImGui_ImplDX12_RenderDrawData(ImGui::GetDrawData(), g_pd3dCommandList); 204 barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET; 205 barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT; 206 g_pd3dCommandList->ResourceBarrier(1, &barrier); 207 g_pd3dCommandList->Close(); 208 209 g_pd3dCommandQueue->ExecuteCommandLists(1, (ID3D12CommandList* const*)&g_pd3dCommandList); 210 211 g_pSwapChain->Present(1, 0); // Present with vsync 212 //g_pSwapChain->Present(0, 0); // Present without vsync 213 214 UINT64 fenceValue = g_fenceLastSignaledValue + 1; 215 g_pd3dCommandQueue->Signal(g_fence, fenceValue); 216 g_fenceLastSignaledValue = fenceValue; 217 frameCtx->FenceValue = fenceValue; 218 } 219 220 WaitForLastSubmittedFrame(); 221 222 // Cleanup 223 ImGui_ImplDX12_Shutdown(); 224 ImGui_ImplWin32_Shutdown(); 225 ImGui::DestroyContext(); 226 227 CleanupDeviceD3D(); 228 ::DestroyWindow(hwnd); 229 ::UnregisterClass(wc.lpszClassName, wc.hInstance); 230 231 return 0; 232 } 233 234 // Helper functions 235 236 bool CreateDeviceD3D(HWND hWnd) 237 { 238 // Setup swap chain 239 DXGI_SWAP_CHAIN_DESC1 sd; 240 { 241 ZeroMemory(&sd, sizeof(sd)); 242 sd.BufferCount = NUM_BACK_BUFFERS; 243 sd.Width = 0; 244 sd.Height = 0; 245 sd.Format = DXGI_FORMAT_R8G8B8A8_UNORM; 246 sd.Flags = DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT; 247 sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; 248 sd.SampleDesc.Count = 1; 249 sd.SampleDesc.Quality = 0; 250 sd.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; 251 sd.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED; 252 sd.Scaling = DXGI_SCALING_STRETCH; 253 sd.Stereo = FALSE; 254 } 255 256 // [DEBUG] Enable debug interface 257 #ifdef DX12_ENABLE_DEBUG_LAYER 258 ID3D12Debug* pdx12Debug = NULL; 259 if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&pdx12Debug)))) 260 pdx12Debug->EnableDebugLayer(); 261 #endif 262 263 // Create device 264 D3D_FEATURE_LEVEL featureLevel = D3D_FEATURE_LEVEL_11_0; 265 if (D3D12CreateDevice(NULL, featureLevel, IID_PPV_ARGS(&g_pd3dDevice)) != S_OK) 266 return false; 267 268 // [DEBUG] Setup debug interface to break on any warnings/errors 269 #ifdef DX12_ENABLE_DEBUG_LAYER 270 if (pdx12Debug != NULL) 271 { 272 ID3D12InfoQueue* pInfoQueue = NULL; 273 g_pd3dDevice->QueryInterface(IID_PPV_ARGS(&pInfoQueue)); 274 pInfoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_ERROR, true); 275 pInfoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_CORRUPTION, true); 276 pInfoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_WARNING, true); 277 pInfoQueue->Release(); 278 pdx12Debug->Release(); 279 } 280 #endif 281 282 { 283 D3D12_DESCRIPTOR_HEAP_DESC desc = {}; 284 desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; 285 desc.NumDescriptors = NUM_BACK_BUFFERS; 286 desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; 287 desc.NodeMask = 1; 288 if (g_pd3dDevice->CreateDescriptorHeap(&desc, IID_PPV_ARGS(&g_pd3dRtvDescHeap)) != S_OK) 289 return false; 290 291 SIZE_T rtvDescriptorSize = g_pd3dDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); 292 D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = g_pd3dRtvDescHeap->GetCPUDescriptorHandleForHeapStart(); 293 for (UINT i = 0; i < NUM_BACK_BUFFERS; i++) 294 { 295 g_mainRenderTargetDescriptor[i] = rtvHandle; 296 rtvHandle.ptr += rtvDescriptorSize; 297 } 298 } 299 300 { 301 D3D12_DESCRIPTOR_HEAP_DESC desc = {}; 302 desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; 303 desc.NumDescriptors = 1; 304 desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; 305 if (g_pd3dDevice->CreateDescriptorHeap(&desc, IID_PPV_ARGS(&g_pd3dSrvDescHeap)) != S_OK) 306 return false; 307 } 308 309 { 310 D3D12_COMMAND_QUEUE_DESC desc = {}; 311 desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; 312 desc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; 313 desc.NodeMask = 1; 314 if (g_pd3dDevice->CreateCommandQueue(&desc, IID_PPV_ARGS(&g_pd3dCommandQueue)) != S_OK) 315 return false; 316 } 317 318 for (UINT i = 0; i < NUM_FRAMES_IN_FLIGHT; i++) 319 if (g_pd3dDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&g_frameContext[i].CommandAllocator)) != S_OK) 320 return false; 321 322 if (g_pd3dDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, g_frameContext[0].CommandAllocator, NULL, IID_PPV_ARGS(&g_pd3dCommandList)) != S_OK || 323 g_pd3dCommandList->Close() != S_OK) 324 return false; 325 326 if (g_pd3dDevice->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&g_fence)) != S_OK) 327 return false; 328 329 g_fenceEvent = CreateEvent(NULL, FALSE, FALSE, NULL); 330 if (g_fenceEvent == NULL) 331 return false; 332 333 { 334 IDXGIFactory4* dxgiFactory = NULL; 335 IDXGISwapChain1* swapChain1 = NULL; 336 if (CreateDXGIFactory1(IID_PPV_ARGS(&dxgiFactory)) != S_OK) 337 return false; 338 if (dxgiFactory->CreateSwapChainForHwnd(g_pd3dCommandQueue, hWnd, &sd, NULL, NULL, &swapChain1) != S_OK) 339 return false; 340 if (swapChain1->QueryInterface(IID_PPV_ARGS(&g_pSwapChain)) != S_OK) 341 return false; 342 swapChain1->Release(); 343 dxgiFactory->Release(); 344 g_pSwapChain->SetMaximumFrameLatency(NUM_BACK_BUFFERS); 345 g_hSwapChainWaitableObject = g_pSwapChain->GetFrameLatencyWaitableObject(); 346 } 347 348 CreateRenderTarget(); 349 return true; 350 } 351 352 void CleanupDeviceD3D() 353 { 354 CleanupRenderTarget(); 355 if (g_pSwapChain) { g_pSwapChain->Release(); g_pSwapChain = NULL; } 356 if (g_hSwapChainWaitableObject != NULL) { CloseHandle(g_hSwapChainWaitableObject); } 357 for (UINT i = 0; i < NUM_FRAMES_IN_FLIGHT; i++) 358 if (g_frameContext[i].CommandAllocator) { g_frameContext[i].CommandAllocator->Release(); g_frameContext[i].CommandAllocator = NULL; } 359 if (g_pd3dCommandQueue) { g_pd3dCommandQueue->Release(); g_pd3dCommandQueue = NULL; } 360 if (g_pd3dCommandList) { g_pd3dCommandList->Release(); g_pd3dCommandList = NULL; } 361 if (g_pd3dRtvDescHeap) { g_pd3dRtvDescHeap->Release(); g_pd3dRtvDescHeap = NULL; } 362 if (g_pd3dSrvDescHeap) { g_pd3dSrvDescHeap->Release(); g_pd3dSrvDescHeap = NULL; } 363 if (g_fence) { g_fence->Release(); g_fence = NULL; } 364 if (g_fenceEvent) { CloseHandle(g_fenceEvent); g_fenceEvent = NULL; } 365 if (g_pd3dDevice) { g_pd3dDevice->Release(); g_pd3dDevice = NULL; } 366 367 #ifdef DX12_ENABLE_DEBUG_LAYER 368 IDXGIDebug1* pDebug = NULL; 369 if (SUCCEEDED(DXGIGetDebugInterface1(0, IID_PPV_ARGS(&pDebug)))) 370 { 371 pDebug->ReportLiveObjects(DXGI_DEBUG_ALL, DXGI_DEBUG_RLO_SUMMARY); 372 pDebug->Release(); 373 } 374 #endif 375 } 376 377 void CreateRenderTarget() 378 { 379 for (UINT i = 0; i < NUM_BACK_BUFFERS; i++) 380 { 381 ID3D12Resource* pBackBuffer = NULL; 382 g_pSwapChain->GetBuffer(i, IID_PPV_ARGS(&pBackBuffer)); 383 g_pd3dDevice->CreateRenderTargetView(pBackBuffer, NULL, g_mainRenderTargetDescriptor[i]); 384 g_mainRenderTargetResource[i] = pBackBuffer; 385 } 386 } 387 388 void CleanupRenderTarget() 389 { 390 WaitForLastSubmittedFrame(); 391 392 for (UINT i = 0; i < NUM_BACK_BUFFERS; i++) 393 if (g_mainRenderTargetResource[i]) { g_mainRenderTargetResource[i]->Release(); g_mainRenderTargetResource[i] = NULL; } 394 } 395 396 void WaitForLastSubmittedFrame() 397 { 398 FrameContext* frameCtx = &g_frameContext[g_frameIndex % NUM_FRAMES_IN_FLIGHT]; 399 400 UINT64 fenceValue = frameCtx->FenceValue; 401 if (fenceValue == 0) 402 return; // No fence was signaled 403 404 frameCtx->FenceValue = 0; 405 if (g_fence->GetCompletedValue() >= fenceValue) 406 return; 407 408 g_fence->SetEventOnCompletion(fenceValue, g_fenceEvent); 409 WaitForSingleObject(g_fenceEvent, INFINITE); 410 } 411 412 FrameContext* WaitForNextFrameResources() 413 { 414 UINT nextFrameIndex = g_frameIndex + 1; 415 g_frameIndex = nextFrameIndex; 416 417 HANDLE waitableObjects[] = { g_hSwapChainWaitableObject, NULL }; 418 DWORD numWaitableObjects = 1; 419 420 FrameContext* frameCtx = &g_frameContext[nextFrameIndex % NUM_FRAMES_IN_FLIGHT]; 421 UINT64 fenceValue = frameCtx->FenceValue; 422 if (fenceValue != 0) // means no fence was signaled 423 { 424 frameCtx->FenceValue = 0; 425 g_fence->SetEventOnCompletion(fenceValue, g_fenceEvent); 426 waitableObjects[1] = g_fenceEvent; 427 numWaitableObjects = 2; 428 } 429 430 WaitForMultipleObjects(numWaitableObjects, waitableObjects, TRUE, INFINITE); 431 432 return frameCtx; 433 } 434 435 void ResizeSwapChain(HWND hWnd, int width, int height) 436 { 437 DXGI_SWAP_CHAIN_DESC1 sd; 438 g_pSwapChain->GetDesc1(&sd); 439 sd.Width = width; 440 sd.Height = height; 441 442 IDXGIFactory4* dxgiFactory = NULL; 443 g_pSwapChain->GetParent(IID_PPV_ARGS(&dxgiFactory)); 444 445 g_pSwapChain->Release(); 446 CloseHandle(g_hSwapChainWaitableObject); 447 448 IDXGISwapChain1* swapChain1 = NULL; 449 dxgiFactory->CreateSwapChainForHwnd(g_pd3dCommandQueue, hWnd, &sd, NULL, NULL, &swapChain1); 450 swapChain1->QueryInterface(IID_PPV_ARGS(&g_pSwapChain)); 451 swapChain1->Release(); 452 dxgiFactory->Release(); 453 454 g_pSwapChain->SetMaximumFrameLatency(NUM_BACK_BUFFERS); 455 456 g_hSwapChainWaitableObject = g_pSwapChain->GetFrameLatencyWaitableObject(); 457 assert(g_hSwapChainWaitableObject != NULL); 458 } 459 460 // Forward declare message handler from imgui_impl_win32.cpp 461 extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); 462 463 // Win32 message handler 464 LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) 465 { 466 if (ImGui_ImplWin32_WndProcHandler(hWnd, msg, wParam, lParam)) 467 return true; 468 469 switch (msg) 470 { 471 case WM_SIZE: 472 if (g_pd3dDevice != NULL && wParam != SIZE_MINIMIZED) 473 { 474 WaitForLastSubmittedFrame(); 475 ImGui_ImplDX12_InvalidateDeviceObjects(); 476 CleanupRenderTarget(); 477 ResizeSwapChain(hWnd, (UINT)LOWORD(lParam), (UINT)HIWORD(lParam)); 478 CreateRenderTarget(); 479 ImGui_ImplDX12_CreateDeviceObjects(); 480 } 481 return 0; 482 case WM_SYSCOMMAND: 483 if ((wParam & 0xfff0) == SC_KEYMENU) // Disable ALT application menu 484 return 0; 485 break; 486 case WM_DESTROY: 487 ::PostQuitMessage(0); 488 return 0; 489 } 490 return ::DefWindowProc(hWnd, msg, wParam, lParam); 491 }