6 #include "backends/imgui_impl_win32.h"
7 #include "backends/imgui_impl_dx12.h"
16 #define DX12_ENABLE_DEBUG_LAYER
19 #ifdef DX12_ENABLE_DEBUG_LAYER
20 #include <dxgidebug.h>
21 #pragma comment(lib, "dxguid.lib")
31 static int const NUM_FRAMES_IN_FLIGHT = 3;
32 static FrameContext g_frameContext[NUM_FRAMES_IN_FLIGHT] = {};
33 static UINT g_frameIndex = 0;
35 static int const NUM_BACK_BUFFERS = 3;
36 static IDXGIAdapter3* g_adapter =
nullptr;
37 static ID3D12Device* g_pd3dDevice =
nullptr;
38 static ID3D12DescriptorHeap* g_pd3dRtvDescHeap =
nullptr;
39 static ID3D12DescriptorHeap* g_pd3dSrvDescHeap =
nullptr;
40 static ID3D12CommandQueue* g_pd3dCommandQueue =
nullptr;
41 static ID3D12GraphicsCommandList* g_pd3dCommandList =
nullptr;
42 static ID3D12Fence* g_fence =
nullptr;
43 static HANDLE g_fenceEvent =
nullptr;
44 static UINT64 g_fenceLastSignaledValue = 0;
45 static IDXGISwapChain3* g_pSwapChain =
nullptr;
46 static HANDLE g_hSwapChainWaitableObject =
nullptr;
47 static ID3D12Resource* g_mainRenderTargetResource[NUM_BACK_BUFFERS] = {};
48 static D3D12_CPU_DESCRIPTOR_HANDLE g_mainRenderTargetDescriptor[NUM_BACK_BUFFERS] = {};
50 static WNDCLASSEXW wc;
60 LRESULT WINAPI
WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
66 DXGI_SWAP_CHAIN_DESC1 sd;
68 ZeroMemory(&sd,
sizeof(sd));
69 sd.BufferCount = NUM_BACK_BUFFERS;
72 sd.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
73 sd.Flags = DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT;
74 sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
75 sd.SampleDesc.Count = 1;
76 sd.SampleDesc.Quality = 0;
77 sd.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
78 sd.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED;
79 sd.Scaling = DXGI_SCALING_STRETCH;
84 #ifdef DX12_ENABLE_DEBUG_LAYER
85 ID3D12Debug* pdx12Debug =
nullptr;
86 if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&pdx12Debug))))
87 pdx12Debug->EnableDebugLayer();
92 IDXGIFactory4* dxgiFactory =
nullptr;
93 if (CreateDXGIFactory1(IID_PPV_ARGS(&dxgiFactory)) != S_OK)
95 if (dxgiFactory->EnumWarpAdapter(IID_PPV_ARGS(&g_adapter)) != S_OK)
97 dxgiFactory->Release();
101 D3D_FEATURE_LEVEL featureLevel = D3D_FEATURE_LEVEL_11_0;
102 if (D3D12CreateDevice(g_adapter, featureLevel, IID_PPV_ARGS(&g_pd3dDevice)) != S_OK)
106 #ifdef DX12_ENABLE_DEBUG_LAYER
107 if (pdx12Debug !=
nullptr)
109 ID3D12InfoQueue* pInfoQueue =
nullptr;
110 g_pd3dDevice->QueryInterface(IID_PPV_ARGS(&pInfoQueue));
111 pInfoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_ERROR,
true);
112 pInfoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_CORRUPTION,
true);
113 pInfoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_WARNING,
true);
114 pInfoQueue->Release();
115 pdx12Debug->Release();
120 D3D12_DESCRIPTOR_HEAP_DESC desc = {};
121 desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
122 desc.NumDescriptors = NUM_BACK_BUFFERS;
123 desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
125 if (g_pd3dDevice->CreateDescriptorHeap(&desc, IID_PPV_ARGS(&g_pd3dRtvDescHeap)) != S_OK)
128 SIZE_T rtvDescriptorSize = g_pd3dDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
129 D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = g_pd3dRtvDescHeap->GetCPUDescriptorHandleForHeapStart();
130 for (UINT i = 0; i < NUM_BACK_BUFFERS; i++)
132 g_mainRenderTargetDescriptor[i] = rtvHandle;
133 rtvHandle.ptr += rtvDescriptorSize;
138 D3D12_DESCRIPTOR_HEAP_DESC desc = {};
139 desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
140 desc.NumDescriptors = 1;
141 desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
142 if (g_pd3dDevice->CreateDescriptorHeap(&desc, IID_PPV_ARGS(&g_pd3dSrvDescHeap)) != S_OK)
147 D3D12_COMMAND_QUEUE_DESC desc = {};
148 desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
149 desc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
151 if (g_pd3dDevice->CreateCommandQueue(&desc, IID_PPV_ARGS(&g_pd3dCommandQueue)) != S_OK)
155 for (UINT i = 0; i < NUM_FRAMES_IN_FLIGHT; i++)
156 if (g_pd3dDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&g_frameContext[i].CommandAllocator)) != S_OK)
159 if (g_pd3dDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, g_frameContext[0].
CommandAllocator,
nullptr, IID_PPV_ARGS(&g_pd3dCommandList)) != S_OK ||
160 g_pd3dCommandList->Close() != S_OK)
163 if (g_pd3dDevice->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&g_fence)) != S_OK)
166 g_fenceEvent = CreateEvent(
nullptr, FALSE, FALSE,
nullptr);
167 if (g_fenceEvent ==
nullptr)
171 IDXGIFactory4* dxgiFactory =
nullptr;
172 IDXGISwapChain1* swapChain1 =
nullptr;
173 if (CreateDXGIFactory1(IID_PPV_ARGS(&dxgiFactory)) != S_OK)
175 if (dxgiFactory->CreateSwapChainForHwnd(g_pd3dCommandQueue, hWnd, &sd,
nullptr,
nullptr, &swapChain1) != S_OK)
177 if (swapChain1->QueryInterface(IID_PPV_ARGS(&g_pSwapChain)) != S_OK)
179 swapChain1->Release();
180 dxgiFactory->Release();
181 g_pSwapChain->SetMaximumFrameLatency(NUM_BACK_BUFFERS);
182 g_hSwapChainWaitableObject = g_pSwapChain->GetFrameLatencyWaitableObject();
192 if (g_pSwapChain) { g_pSwapChain->SetFullscreenState(
false,
nullptr); g_pSwapChain->Release(); g_pSwapChain =
nullptr; }
193 if (g_hSwapChainWaitableObject !=
nullptr) { CloseHandle(g_hSwapChainWaitableObject); }
194 for (UINT i = 0; i < NUM_FRAMES_IN_FLIGHT; i++)
196 if (g_pd3dCommandQueue) { g_pd3dCommandQueue->Release(); g_pd3dCommandQueue =
nullptr; }
197 if (g_pd3dCommandList) { g_pd3dCommandList->Release(); g_pd3dCommandList =
nullptr; }
198 if (g_pd3dRtvDescHeap) { g_pd3dRtvDescHeap->Release(); g_pd3dRtvDescHeap =
nullptr; }
199 if (g_pd3dSrvDescHeap) { g_pd3dSrvDescHeap->Release(); g_pd3dSrvDescHeap =
nullptr; }
200 if (g_fence) { g_fence->Release(); g_fence =
nullptr; }
201 if (g_fenceEvent) { CloseHandle(g_fenceEvent); g_fenceEvent =
nullptr; }
202 if (g_pd3dDevice) { g_pd3dDevice->Release(); g_pd3dDevice =
nullptr; }
204 #ifdef DX12_ENABLE_DEBUG_LAYER
205 IDXGIDebug1* pDebug =
nullptr;
206 if (SUCCEEDED(DXGIGetDebugInterface1(0, IID_PPV_ARGS(&pDebug))))
208 pDebug->ReportLiveObjects(DXGI_DEBUG_ALL, DXGI_DEBUG_RLO_SUMMARY);
213 if (g_adapter) { g_adapter->Release(); g_adapter =
nullptr; }
218 for (UINT i = 0; i < NUM_BACK_BUFFERS; i++)
220 ID3D12Resource* pBackBuffer =
nullptr;
221 g_pSwapChain->GetBuffer(i, IID_PPV_ARGS(&pBackBuffer));
222 g_pd3dDevice->CreateRenderTargetView(pBackBuffer,
nullptr, g_mainRenderTargetDescriptor[i]);
223 g_mainRenderTargetResource[i] = pBackBuffer;
231 for (UINT i = 0; i < NUM_BACK_BUFFERS; i++)
232 if (g_mainRenderTargetResource[i]) { g_mainRenderTargetResource[i]->Release(); g_mainRenderTargetResource[i] =
nullptr; }
237 FrameContext* frameCtx = &g_frameContext[g_frameIndex % NUM_FRAMES_IN_FLIGHT];
244 if (g_fence->GetCompletedValue() >= fenceValue)
247 g_fence->SetEventOnCompletion(fenceValue, g_fenceEvent);
248 WaitForSingleObject(g_fenceEvent, INFINITE);
253 UINT nextFrameIndex = g_frameIndex + 1;
254 g_frameIndex = nextFrameIndex;
256 HANDLE waitableObjects[] = { g_hSwapChainWaitableObject,
nullptr };
257 DWORD numWaitableObjects = 1;
259 FrameContext* frameCtx = &g_frameContext[nextFrameIndex % NUM_FRAMES_IN_FLIGHT];
264 g_fence->SetEventOnCompletion(fenceValue, g_fenceEvent);
265 waitableObjects[1] = g_fenceEvent;
266 numWaitableObjects = 2;
269 WaitForMultipleObjects(numWaitableObjects, waitableObjects, TRUE, INFINITE);
282 LRESULT WINAPI
WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
290 if (g_pd3dDevice !=
nullptr && wParam != SIZE_MINIMIZED)
294 HRESULT result = g_pSwapChain->ResizeBuffers(0, (UINT)LOWORD(lParam), (UINT)HIWORD(lParam), DXGI_FORMAT_UNKNOWN, DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT);
295 CTASSERT(SUCCEEDED(result) &&
"Failed to resize swapchain.");
300 if ((wParam & 0xfff0) == SC_KEYMENU)
304 ::PostQuitMessage(0);
307 return ::DefWindowProcW(hWnd, msg, wParam, lParam);
314 wc = {
sizeof(wc), CS_CLASSDC,
WndProc, 0L, 0L, GetModuleHandle(
nullptr),
nullptr,
nullptr,
nullptr,
nullptr, L
"ImGui Example",
nullptr };
315 ::RegisterClassExW(&wc);
316 hwnd = ::CreateWindowW(wc.lpszClassName, config.
title, WS_OVERLAPPEDWINDOW, 100, 100, 1280, 800,
nullptr,
nullptr, wc.hInstance,
nullptr);
320 GetWindowRect(hwnd, &rc);
321 int xPos = (GetSystemMetrics(SM_CXSCREEN) - rc.right) / 2;
322 int yPos = (GetSystemMetrics(SM_CYSCREEN) - rc.bottom) / 2;
323 SetWindowPos(hwnd, 0, xPos, yPos, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
329 ::UnregisterClassW(wc.lpszClassName, wc.hInstance);
334 ::ShowWindow(hwnd, SW_SHOWDEFAULT);
335 ::UpdateWindow(hwnd);
338 IMGUI_CHECKVERSION();
339 ImGui::CreateContext();
340 ImGuiIO& io = ImGui::GetIO(); (void)io;
341 io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
342 io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;
343 io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
344 io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;
348 ImPlot::CreateContext();
351 ImGui::StyleColorsDark();
352 ImPlot::StyleColorsDark();
356 ImGuiStyle& style = ImGui::GetStyle();
357 if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
359 style.WindowRounding = 0.0f;
360 style.Colors[ImGuiCol_WindowBg].w = 1.0f;
364 ImGui_ImplWin32_Init(hwnd);
365 ImGui_ImplDX12_Init(g_pd3dDevice, NUM_FRAMES_IN_FLIGHT,
366 DXGI_FORMAT_R8G8B8A8_UNORM, g_pd3dSrvDescHeap,
367 g_pd3dSrvDescHeap->GetCPUDescriptorHandleForHeapStart(),
368 g_pd3dSrvDescHeap->GetGPUDescriptorHandleForHeapStart());
394 ImGui_ImplDX12_Shutdown();
395 ImGui_ImplWin32_Shutdown();
396 ImPlot::DestroyContext();
397 ImGui::DestroyContext();
400 ::DestroyWindow(hwnd);
401 ::UnregisterClassW(wc.lpszClassName, wc.hInstance);
410 while (::PeekMessage(&msg,
nullptr, 0U, 0U, PM_REMOVE))
412 ::TranslateMessage(&msg);
413 ::DispatchMessage(&msg);
414 if (msg.message == WM_QUIT)
421 ImGui_ImplDX12_NewFrame();
422 ImGui_ImplWin32_NewFrame();
430 ::PostMessage(hwnd, WM_CLOSE, 0, 0);
435 ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);
441 UINT backBufferIdx = g_pSwapChain->GetCurrentBackBufferIndex();
444 D3D12_RESOURCE_BARRIER barrier = {};
445 barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
446 barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
447 barrier.Transition.pResource = g_mainRenderTargetResource[backBufferIdx];
448 barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
449 barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT;
450 barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
452 g_pd3dCommandList->ResourceBarrier(1, &barrier);
455 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 };
456 g_pd3dCommandList->ClearRenderTargetView(g_mainRenderTargetDescriptor[backBufferIdx], clear_color_with_alpha, 0,
nullptr);
457 g_pd3dCommandList->OMSetRenderTargets(1, &g_mainRenderTargetDescriptor[backBufferIdx], FALSE,
nullptr);
458 g_pd3dCommandList->SetDescriptorHeaps(1, &g_pd3dSrvDescHeap);
459 ImGui_ImplDX12_RenderDrawData(ImGui::GetDrawData(), g_pd3dCommandList);
460 barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
461 barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT;
462 g_pd3dCommandList->ResourceBarrier(1, &barrier);
463 g_pd3dCommandList->Close();
465 g_pd3dCommandQueue->ExecuteCommandLists(1, (ID3D12CommandList*
const*)&g_pd3dCommandList);
467 ImGuiIO& io = ImGui::GetIO();
470 if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
472 ImGui::UpdatePlatformWindows();
473 ImGui::RenderPlatformWindowsDefault(
nullptr, (
void*)g_pd3dCommandList);
476 g_pSwapChain->Present(1, 0);
479 UINT64 fenceValue = g_fenceLastSignaledValue + 1;
480 g_pd3dCommandQueue->Signal(g_fence, fenceValue);
481 g_fenceLastSignaledValue = fenceValue;
FrameContext * WaitForNextFrameResources()
void CleanupRenderTarget()
IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
bool CreateDeviceD3D(HWND hWnd)
LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
void CreateRenderTarget()
void WaitForLastSubmittedFrame()
#define CTASSERT(expr)
assert a condition, prints the condition as a message
bool create(const config_t &config)
ID3D12CommandAllocator * CommandAllocator