1 | // dear imgui: Renderer Backend for DirectX12 |
---|---|
2 | // This needs to be used along with a Platform Backend (e.g. Win32) |
3 | |
4 | // Implemented features: |
5 | // [X] Renderer: User texture binding. Use 'D3D12_GPU_DESCRIPTOR_HANDLE' as ImTextureID. Read the FAQ about ImTextureID! |
6 | // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). |
7 | // [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. |
8 | // [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'. |
9 | // FIXME: The transition from removing a viewport and moving the window in an existing hosted viewport tends to flicker. |
10 | |
11 | // The aim of imgui_impl_dx12.h/.cpp is to be usable in your engine without any modification. |
12 | // IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/ |
13 | |
14 | // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. |
15 | // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. |
16 | // Learn about Dear ImGui: |
17 | // - FAQ https://dearimgui.com/faq |
18 | // - Getting Started https://dearimgui.com/getting-started |
19 | // - Documentation https://dearimgui.com/docs (same as your local docs/ folder). |
20 | // - Introduction, links and more at the top of imgui.cpp |
21 | |
22 | // CHANGELOG |
23 | // (minor and older changes stripped away, please see git history for details) |
24 | // 2025-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. |
25 | // 2025-02-24: DirectX12: Fixed an issue where ImGui_ImplDX12_Init() signature change from 2024-11-15 combined with change from 2025-01-15 made legacy ImGui_ImplDX12_Init() crash. (#8429) |
26 | // 2025-01-15: DirectX12: Texture upload use the command queue provided in ImGui_ImplDX12_InitInfo instead of creating its own. |
27 | // 2024-12-09: DirectX12: Let user specifies the DepthStencilView format by setting ImGui_ImplDX12_InitInfo::DSVFormat. |
28 | // 2024-11-15: DirectX12: *BREAKING CHANGE* Changed ImGui_ImplDX12_Init() signature to take a ImGui_ImplDX12_InitInfo struct. Legacy ImGui_ImplDX12_Init() signature is still supported (will obsolete). |
29 | // 2024-11-15: DirectX12: *BREAKING CHANGE* User is now required to pass function pointers to allocate/free SRV Descriptors. We provide convenience legacy fields to pass a single descriptor, matching the old API, but upcoming features will want multiple. |
30 | // 2024-10-23: DirectX12: Unmap() call specify written range. The range is informational and may be used by debug tools. |
31 | // 2024-10-07: DirectX12: Changed default texture sampler to Clamp instead of Repeat/Wrap. |
32 | // 2024-10-07: DirectX12: Expose selected render state in ImGui_ImplDX12_RenderState, which you can access in 'void* platform_io.Renderer_RenderState' during draw callbacks. |
33 | // 2024-10-07: DirectX12: Compiling with '#define ImTextureID=ImU64' is unnecessary now that dear imgui defaults ImTextureID to u64 instead of void*. |
34 | // 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11. |
35 | // 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX). |
36 | // 2021-05-19: DirectX12: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement) |
37 | // 2021-02-18: DirectX12: Change blending equation to preserve alpha in output buffer. |
38 | // 2021-01-11: DirectX12: Improve Windows 7 compatibility (for D3D12On7) by loading d3d12.dll dynamically. |
39 | // 2020-09-16: DirectX12: Avoid rendering calls with zero-sized scissor rectangle since it generates a validation layer warning. |
40 | // 2020-09-08: DirectX12: Clarified support for building on 32-bit systems by redefining ImTextureID. |
41 | // 2019-10-18: DirectX12: *BREAKING CHANGE* Added extra ID3D12DescriptorHeap parameter to ImGui_ImplDX12_Init() function. |
42 | // 2019-05-29: DirectX12: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag. |
43 | // 2019-04-30: DirectX12: Added support for special ImDrawCallback_ResetRenderState callback to reset render state. |
44 | // 2019-03-29: Misc: Various minor tidying up. |
45 | // 2018-12-03: Misc: Added #pragma comment statement to automatically link with d3dcompiler.lib when using D3DCompile(). |
46 | // 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window. |
47 | // 2018-06-12: DirectX12: Moved the ID3D12GraphicsCommandList* parameter from NewFrame() to RenderDrawData(). |
48 | // 2018-06-08: Misc: Extracted imgui_impl_dx12.cpp/.h away from the old combined DX12+Win32 example. |
49 | // 2018-06-08: DirectX12: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle (to ease support for future multi-viewport). |
50 | // 2018-02-22: Merged into master with all Win32 code synchronized to other examples. |
51 | |
52 | #include "imgui.h" |
53 | #ifndef IMGUI_DISABLE |
54 | #include "imgui_impl_dx12.h" |
55 | |
56 | // DirectX |
57 | #include <d3d12.h> |
58 | #include <dxgi1_4.h> |
59 | #include <d3dcompiler.h> |
60 | #ifdef _MSC_VER |
61 | #pragma comment(lib, "d3dcompiler") // Automatically link with d3dcompiler.lib as we are using D3DCompile() below. |
62 | #endif |
63 | |
64 | // DirectX12 data |
65 | struct ImGui_ImplDX12_RenderBuffers; |
66 | |
67 | struct ImGui_ImplDX12_Texture |
68 | { |
69 | ID3D12Resource* pTextureResource; |
70 | D3D12_CPU_DESCRIPTOR_HANDLE hFontSrvCpuDescHandle; |
71 | D3D12_GPU_DESCRIPTOR_HANDLE hFontSrvGpuDescHandle; |
72 | |
73 | ImGui_ImplDX12_Texture() { memset(s: (void*)this, c: 0, n: sizeof(*this)); } |
74 | }; |
75 | |
76 | struct ImGui_ImplDX12_Data |
77 | { |
78 | ImGui_ImplDX12_InitInfo InitInfo; |
79 | ID3D12Device* pd3dDevice; |
80 | ID3D12RootSignature* pRootSignature; |
81 | ID3D12PipelineState* pPipelineState; |
82 | ID3D12CommandQueue* pCommandQueue; |
83 | bool commandQueueOwned; |
84 | DXGI_FORMAT RTVFormat; |
85 | DXGI_FORMAT DSVFormat; |
86 | ID3D12DescriptorHeap* pd3dSrvDescHeap; |
87 | UINT numFramesInFlight; |
88 | ImGui_ImplDX12_Texture FontTexture; |
89 | bool LegacySingleDescriptorUsed; |
90 | |
91 | ImGui_ImplDX12_Data() { memset(s: (void*)this, c: 0, n: sizeof(*this)); } |
92 | }; |
93 | |
94 | // Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts |
95 | // It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts. |
96 | static ImGui_ImplDX12_Data* ImGui_ImplDX12_GetBackendData() |
97 | { |
98 | return ImGui::GetCurrentContext() ? (ImGui_ImplDX12_Data*)ImGui::GetIO().BackendRendererUserData : nullptr; |
99 | } |
100 | |
101 | // Buffers used during the rendering of a frame |
102 | struct ImGui_ImplDX12_RenderBuffers |
103 | { |
104 | ID3D12Resource* IndexBuffer; |
105 | ID3D12Resource* VertexBuffer; |
106 | int IndexBufferSize; |
107 | int VertexBufferSize; |
108 | }; |
109 | |
110 | // Buffers used for secondary viewports created by the multi-viewports systems |
111 | struct ImGui_ImplDX12_FrameContext |
112 | { |
113 | ID3D12CommandAllocator* CommandAllocator; |
114 | ID3D12Resource* RenderTarget; |
115 | D3D12_CPU_DESCRIPTOR_HANDLE RenderTargetCpuDescriptors; |
116 | }; |
117 | |
118 | // Helper structure we store in the void* RendererUserData field of each ImGuiViewport to easily retrieve our backend data. |
119 | // Main viewport created by application will only use the Resources field. |
120 | // Secondary viewports created by this backend will use all the fields (including Window fields), |
121 | struct ImGui_ImplDX12_ViewportData |
122 | { |
123 | // Window |
124 | ID3D12CommandQueue* CommandQueue; |
125 | ID3D12GraphicsCommandList* CommandList; |
126 | ID3D12DescriptorHeap* RtvDescHeap; |
127 | IDXGISwapChain3* SwapChain; |
128 | ID3D12Fence* Fence; |
129 | UINT64 FenceSignaledValue; |
130 | HANDLE FenceEvent; |
131 | UINT NumFramesInFlight; |
132 | ImGui_ImplDX12_FrameContext* FrameCtx; |
133 | |
134 | // Render buffers |
135 | UINT FrameIndex; |
136 | ImGui_ImplDX12_RenderBuffers* FrameRenderBuffers; |
137 | |
138 | ImGui_ImplDX12_ViewportData(UINT num_frames_in_flight) |
139 | { |
140 | CommandQueue = nullptr; |
141 | CommandList = nullptr; |
142 | RtvDescHeap = nullptr; |
143 | SwapChain = nullptr; |
144 | Fence = nullptr; |
145 | FenceSignaledValue = 0; |
146 | FenceEvent = nullptr; |
147 | NumFramesInFlight = num_frames_in_flight; |
148 | FrameCtx = new ImGui_ImplDX12_FrameContext[NumFramesInFlight]; |
149 | FrameIndex = UINT_MAX; |
150 | FrameRenderBuffers = new ImGui_ImplDX12_RenderBuffers[NumFramesInFlight]; |
151 | |
152 | for (UINT i = 0; i < NumFramesInFlight; ++i) |
153 | { |
154 | FrameCtx[i].CommandAllocator = nullptr; |
155 | FrameCtx[i].RenderTarget = nullptr; |
156 | |
157 | // Create buffers with a default size (they will later be grown as needed) |
158 | FrameRenderBuffers[i].IndexBuffer = nullptr; |
159 | FrameRenderBuffers[i].VertexBuffer = nullptr; |
160 | FrameRenderBuffers[i].VertexBufferSize = 5000; |
161 | FrameRenderBuffers[i].IndexBufferSize = 10000; |
162 | } |
163 | } |
164 | ~ImGui_ImplDX12_ViewportData() |
165 | { |
166 | IM_ASSERT(CommandQueue == nullptr && CommandList == nullptr); |
167 | IM_ASSERT(RtvDescHeap == nullptr); |
168 | IM_ASSERT(SwapChain == nullptr); |
169 | IM_ASSERT(Fence == nullptr); |
170 | IM_ASSERT(FenceEvent == nullptr); |
171 | |
172 | for (UINT i = 0; i < NumFramesInFlight; ++i) |
173 | { |
174 | IM_ASSERT(FrameCtx[i].CommandAllocator == nullptr && FrameCtx[i].RenderTarget == nullptr); |
175 | IM_ASSERT(FrameRenderBuffers[i].IndexBuffer == nullptr && FrameRenderBuffers[i].VertexBuffer == nullptr); |
176 | } |
177 | |
178 | delete[] FrameCtx; FrameCtx = nullptr; |
179 | delete[] FrameRenderBuffers; FrameRenderBuffers = nullptr; |
180 | } |
181 | }; |
182 | |
183 | struct VERTEX_CONSTANT_BUFFER_DX12 |
184 | { |
185 | float mvp[4][4]; |
186 | }; |
187 | |
188 | // Forward Declarations |
189 | static void ImGui_ImplDX12_InitPlatformInterface(); |
190 | static void ImGui_ImplDX12_ShutdownPlatformInterface(); |
191 | |
192 | // Functions |
193 | static void ImGui_ImplDX12_SetupRenderState(ImDrawData* draw_data, ID3D12GraphicsCommandList* command_list, ImGui_ImplDX12_RenderBuffers* fr) |
194 | { |
195 | ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData(); |
196 | |
197 | // Setup orthographic projection matrix into our constant buffer |
198 | // Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). |
199 | VERTEX_CONSTANT_BUFFER_DX12 vertex_constant_buffer; |
200 | { |
201 | float L = draw_data->DisplayPos.x; |
202 | float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x; |
203 | float T = draw_data->DisplayPos.y; |
204 | float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y; |
205 | float mvp[4][4] = |
206 | { |
207 | { 2.0f/(R-L), 0.0f, 0.0f, 0.0f }, |
208 | { 0.0f, 2.0f/(T-B), 0.0f, 0.0f }, |
209 | { 0.0f, 0.0f, 0.5f, 0.0f }, |
210 | { (R+L)/(L-R), (T+B)/(B-T), 0.5f, 1.0f }, |
211 | }; |
212 | memcpy(dest: &vertex_constant_buffer.mvp, src: mvp, n: sizeof(mvp)); |
213 | } |
214 | |
215 | // Setup viewport |
216 | D3D12_VIEWPORT vp = {}; |
217 | vp.Width = draw_data->DisplaySize.x; |
218 | vp.Height = draw_data->DisplaySize.y; |
219 | vp.MinDepth = 0.0f; |
220 | vp.MaxDepth = 1.0f; |
221 | vp.TopLeftX = vp.TopLeftY = 0.0f; |
222 | command_list->RSSetViewports(1, &vp); |
223 | |
224 | // Bind shader and vertex buffers |
225 | unsigned int stride = sizeof(ImDrawVert); |
226 | unsigned int offset = 0; |
227 | D3D12_VERTEX_BUFFER_VIEW vbv = {}; |
228 | vbv.BufferLocation = fr->VertexBuffer->GetGPUVirtualAddress() + offset; |
229 | vbv.SizeInBytes = fr->VertexBufferSize * stride; |
230 | vbv.StrideInBytes = stride; |
231 | command_list->IASetVertexBuffers(0, 1, &vbv); |
232 | D3D12_INDEX_BUFFER_VIEW ibv = {}; |
233 | ibv.BufferLocation = fr->IndexBuffer->GetGPUVirtualAddress(); |
234 | ibv.SizeInBytes = fr->IndexBufferSize * sizeof(ImDrawIdx); |
235 | ibv.Format = sizeof(ImDrawIdx) == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT; |
236 | command_list->IASetIndexBuffer(&ibv); |
237 | command_list->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); |
238 | command_list->SetPipelineState(bd->pPipelineState); |
239 | command_list->SetGraphicsRootSignature(bd->pRootSignature); |
240 | command_list->SetGraphicsRoot32BitConstants(0, 16, &vertex_constant_buffer, 0); |
241 | |
242 | // Setup blend factor |
243 | const float blend_factor[4] = { 0.f, 0.f, 0.f, 0.f }; |
244 | command_list->OMSetBlendFactor(blend_factor); |
245 | } |
246 | |
247 | template<typename T> |
248 | static inline void SafeRelease(T*& res) |
249 | { |
250 | if (res) |
251 | res->Release(); |
252 | res = nullptr; |
253 | } |
254 | |
255 | // Render function |
256 | void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandList* command_list) |
257 | { |
258 | // Avoid rendering when minimized |
259 | if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f) |
260 | return; |
261 | |
262 | // FIXME: We are assuming that this only gets called once per frame! |
263 | ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData(); |
264 | ImGui_ImplDX12_ViewportData* vd = (ImGui_ImplDX12_ViewportData*)draw_data->OwnerViewport->RendererUserData; |
265 | vd->FrameIndex++; |
266 | ImGui_ImplDX12_RenderBuffers* fr = &vd->FrameRenderBuffers[vd->FrameIndex % bd->numFramesInFlight]; |
267 | |
268 | // Create and grow vertex/index buffers if needed |
269 | if (fr->VertexBuffer == nullptr || fr->VertexBufferSize < draw_data->TotalVtxCount) |
270 | { |
271 | SafeRelease(res&: fr->VertexBuffer); |
272 | fr->VertexBufferSize = draw_data->TotalVtxCount + 5000; |
273 | D3D12_HEAP_PROPERTIES props = {}; |
274 | props.Type = D3D12_HEAP_TYPE_UPLOAD; |
275 | props.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; |
276 | props.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; |
277 | D3D12_RESOURCE_DESC desc = {}; |
278 | desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; |
279 | desc.Width = fr->VertexBufferSize * sizeof(ImDrawVert); |
280 | desc.Height = 1; |
281 | desc.DepthOrArraySize = 1; |
282 | desc.MipLevels = 1; |
283 | desc.Format = DXGI_FORMAT_UNKNOWN; |
284 | desc.SampleDesc.Count = 1; |
285 | desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; |
286 | desc.Flags = D3D12_RESOURCE_FLAG_NONE; |
287 | if (bd->pd3dDevice->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&fr->VertexBuffer)) < 0) |
288 | return; |
289 | } |
290 | if (fr->IndexBuffer == nullptr || fr->IndexBufferSize < draw_data->TotalIdxCount) |
291 | { |
292 | SafeRelease(res&: fr->IndexBuffer); |
293 | fr->IndexBufferSize = draw_data->TotalIdxCount + 10000; |
294 | D3D12_HEAP_PROPERTIES props = {}; |
295 | props.Type = D3D12_HEAP_TYPE_UPLOAD; |
296 | props.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; |
297 | props.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; |
298 | D3D12_RESOURCE_DESC desc = {}; |
299 | desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; |
300 | desc.Width = fr->IndexBufferSize * sizeof(ImDrawIdx); |
301 | desc.Height = 1; |
302 | desc.DepthOrArraySize = 1; |
303 | desc.MipLevels = 1; |
304 | desc.Format = DXGI_FORMAT_UNKNOWN; |
305 | desc.SampleDesc.Count = 1; |
306 | desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; |
307 | desc.Flags = D3D12_RESOURCE_FLAG_NONE; |
308 | if (bd->pd3dDevice->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&fr->IndexBuffer)) < 0) |
309 | return; |
310 | } |
311 | |
312 | // Upload vertex/index data into a single contiguous GPU buffer |
313 | // During Map() we specify a null read range (as per DX12 API, this is informational and for tooling only) |
314 | void* vtx_resource, *idx_resource; |
315 | D3D12_RANGE range = { 0, 0 }; |
316 | if (fr->VertexBuffer->Map(0, &range, &vtx_resource) != S_OK) |
317 | return; |
318 | if (fr->IndexBuffer->Map(0, &range, &idx_resource) != S_OK) |
319 | return; |
320 | ImDrawVert* vtx_dst = (ImDrawVert*)vtx_resource; |
321 | ImDrawIdx* idx_dst = (ImDrawIdx*)idx_resource; |
322 | for (int n = 0; n < draw_data->CmdListsCount; n++) |
323 | { |
324 | const ImDrawList* draw_list = draw_data->CmdLists[n]; |
325 | memcpy(dest: vtx_dst, src: draw_list->VtxBuffer.Data, n: draw_list->VtxBuffer.Size * sizeof(ImDrawVert)); |
326 | memcpy(dest: idx_dst, src: draw_list->IdxBuffer.Data, n: draw_list->IdxBuffer.Size * sizeof(ImDrawIdx)); |
327 | vtx_dst += draw_list->VtxBuffer.Size; |
328 | idx_dst += draw_list->IdxBuffer.Size; |
329 | } |
330 | |
331 | // During Unmap() we specify the written range (as per DX12 API, this is informational and for tooling only) |
332 | range.End = (SIZE_T)((intptr_t)vtx_dst - (intptr_t)vtx_resource); |
333 | IM_ASSERT(range.End == draw_data->TotalVtxCount * sizeof(ImDrawVert)); |
334 | fr->VertexBuffer->Unmap(0, &range); |
335 | range.End = (SIZE_T)((intptr_t)idx_dst - (intptr_t)idx_resource); |
336 | IM_ASSERT(range.End == draw_data->TotalIdxCount * sizeof(ImDrawIdx)); |
337 | fr->IndexBuffer->Unmap(0, &range); |
338 | |
339 | // Setup desired DX state |
340 | ImGui_ImplDX12_SetupRenderState(draw_data, command_list, fr); |
341 | |
342 | // Setup render state structure (for callbacks and custom texture bindings) |
343 | ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); |
344 | ImGui_ImplDX12_RenderState render_state; |
345 | render_state.Device = bd->pd3dDevice; |
346 | render_state.CommandList = command_list; |
347 | platform_io.Renderer_RenderState = &render_state; |
348 | |
349 | // Render command lists |
350 | // (Because we merged all buffers into a single one, we maintain our own offset into them) |
351 | int global_vtx_offset = 0; |
352 | int global_idx_offset = 0; |
353 | ImVec2 clip_off = draw_data->DisplayPos; |
354 | for (int n = 0; n < draw_data->CmdListsCount; n++) |
355 | { |
356 | const ImDrawList* draw_list = draw_data->CmdLists[n]; |
357 | for (int cmd_i = 0; cmd_i < draw_list->CmdBuffer.Size; cmd_i++) |
358 | { |
359 | const ImDrawCmd* pcmd = &draw_list->CmdBuffer[cmd_i]; |
360 | if (pcmd->UserCallback != nullptr) |
361 | { |
362 | // User callback, registered via ImDrawList::AddCallback() |
363 | // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.) |
364 | if (pcmd->UserCallback == ImDrawCallback_ResetRenderState) |
365 | ImGui_ImplDX12_SetupRenderState(draw_data, command_list, fr); |
366 | else |
367 | pcmd->UserCallback(draw_list, pcmd); |
368 | } |
369 | else |
370 | { |
371 | // Project scissor/clipping rectangles into framebuffer space |
372 | ImVec2 clip_min(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y); |
373 | ImVec2 clip_max(pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w - clip_off.y); |
374 | if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y) |
375 | continue; |
376 | |
377 | // Apply scissor/clipping rectangle |
378 | const D3D12_RECT r = { (LONG)clip_min.x, (LONG)clip_min.y, (LONG)clip_max.x, (LONG)clip_max.y }; |
379 | command_list->RSSetScissorRects(1, &r); |
380 | |
381 | // Bind texture, Draw |
382 | D3D12_GPU_DESCRIPTOR_HANDLE texture_handle = {}; |
383 | texture_handle.ptr = (UINT64)pcmd->GetTexID(); |
384 | command_list->SetGraphicsRootDescriptorTable(1, texture_handle); |
385 | command_list->DrawIndexedInstanced(pcmd->ElemCount, 1, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset, 0); |
386 | } |
387 | } |
388 | global_idx_offset += draw_list->IdxBuffer.Size; |
389 | global_vtx_offset += draw_list->VtxBuffer.Size; |
390 | } |
391 | platform_io.Renderer_RenderState = nullptr; |
392 | } |
393 | |
394 | static void ImGui_ImplDX12_CreateFontsTexture() |
395 | { |
396 | // Build texture atlas |
397 | ImGuiIO& io = ImGui::GetIO(); |
398 | ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData(); |
399 | unsigned char* pixels; |
400 | int width, height; |
401 | io.Fonts->GetTexDataAsRGBA32(out_pixels: &pixels, out_width: &width, out_height: &height); |
402 | |
403 | // Upload texture to graphics system |
404 | ImGui_ImplDX12_Texture* font_tex = &bd->FontTexture; |
405 | { |
406 | D3D12_HEAP_PROPERTIES props = {}; |
407 | props.Type = D3D12_HEAP_TYPE_DEFAULT; |
408 | props.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; |
409 | props.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; |
410 | |
411 | D3D12_RESOURCE_DESC desc; |
412 | ZeroMemory(&desc, sizeof(desc)); |
413 | desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; |
414 | desc.Alignment = 0; |
415 | desc.Width = width; |
416 | desc.Height = height; |
417 | desc.DepthOrArraySize = 1; |
418 | desc.MipLevels = 1; |
419 | desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; |
420 | desc.SampleDesc.Count = 1; |
421 | desc.SampleDesc.Quality = 0; |
422 | desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; |
423 | desc.Flags = D3D12_RESOURCE_FLAG_NONE; |
424 | |
425 | ID3D12Resource* pTexture = nullptr; |
426 | bd->pd3dDevice->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc, |
427 | D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&pTexture)); |
428 | |
429 | UINT upload_pitch = (width * 4 + D3D12_TEXTURE_DATA_PITCH_ALIGNMENT - 1u) & ~(D3D12_TEXTURE_DATA_PITCH_ALIGNMENT - 1u); |
430 | UINT upload_size = height * upload_pitch; |
431 | desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; |
432 | desc.Alignment = 0; |
433 | desc.Width = upload_size; |
434 | desc.Height = 1; |
435 | desc.DepthOrArraySize = 1; |
436 | desc.MipLevels = 1; |
437 | desc.Format = DXGI_FORMAT_UNKNOWN; |
438 | desc.SampleDesc.Count = 1; |
439 | desc.SampleDesc.Quality = 0; |
440 | desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; |
441 | desc.Flags = D3D12_RESOURCE_FLAG_NONE; |
442 | |
443 | props.Type = D3D12_HEAP_TYPE_UPLOAD; |
444 | props.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; |
445 | props.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; |
446 | |
447 | ID3D12Resource* uploadBuffer = nullptr; |
448 | HRESULT hr = bd->pd3dDevice->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc, |
449 | D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&uploadBuffer)); |
450 | IM_ASSERT(SUCCEEDED(hr)); |
451 | |
452 | void* mapped = nullptr; |
453 | D3D12_RANGE range = { 0, upload_size }; |
454 | hr = uploadBuffer->Map(0, &range, &mapped); |
455 | IM_ASSERT(SUCCEEDED(hr)); |
456 | for (int y = 0; y < height; y++) |
457 | memcpy((void*) ((uintptr_t) mapped + y * upload_pitch), pixels + y * width * 4, width * 4); |
458 | uploadBuffer->Unmap(0, &range); |
459 | |
460 | D3D12_TEXTURE_COPY_LOCATION srcLocation = {}; |
461 | D3D12_TEXTURE_COPY_LOCATION dstLocation = {}; |
462 | { |
463 | srcLocation.pResource = uploadBuffer; |
464 | srcLocation.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; |
465 | srcLocation.PlacedFootprint.Footprint.Format = DXGI_FORMAT_R8G8B8A8_UNORM; |
466 | srcLocation.PlacedFootprint.Footprint.Width = width; |
467 | srcLocation.PlacedFootprint.Footprint.Height = height; |
468 | srcLocation.PlacedFootprint.Footprint.Depth = 1; |
469 | srcLocation.PlacedFootprint.Footprint.RowPitch = upload_pitch; |
470 | |
471 | dstLocation.pResource = pTexture; |
472 | dstLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; |
473 | dstLocation.SubresourceIndex = 0; |
474 | } |
475 | |
476 | D3D12_RESOURCE_BARRIER barrier = {}; |
477 | barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; |
478 | barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; |
479 | barrier.Transition.pResource = pTexture; |
480 | barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; |
481 | barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST; |
482 | barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE; |
483 | |
484 | ID3D12Fence* fence = nullptr; |
485 | hr = bd->pd3dDevice->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&fence)); |
486 | IM_ASSERT(SUCCEEDED(hr)); |
487 | |
488 | HANDLE event = ::CreateEvent(0, 0, 0, 0); |
489 | IM_ASSERT(event != nullptr); |
490 | |
491 | ID3D12CommandAllocator* cmdAlloc = nullptr; |
492 | hr = bd->pd3dDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&cmdAlloc)); |
493 | IM_ASSERT(SUCCEEDED(hr)); |
494 | |
495 | ID3D12GraphicsCommandList* cmdList = nullptr; |
496 | hr = bd->pd3dDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, cmdAlloc, nullptr, IID_PPV_ARGS(&cmdList)); |
497 | IM_ASSERT(SUCCEEDED(hr)); |
498 | |
499 | cmdList->CopyTextureRegion(&dstLocation, 0, 0, 0, &srcLocation, nullptr); |
500 | cmdList->ResourceBarrier(1, &barrier); |
501 | |
502 | hr = cmdList->Close(); |
503 | IM_ASSERT(SUCCEEDED(hr)); |
504 | |
505 | ID3D12CommandQueue* cmdQueue = bd->pCommandQueue; |
506 | cmdQueue->ExecuteCommandLists(1, (ID3D12CommandList* const*)&cmdList); |
507 | hr = cmdQueue->Signal(fence, 1); |
508 | IM_ASSERT(SUCCEEDED(hr)); |
509 | |
510 | fence->SetEventOnCompletion(1, event); |
511 | ::WaitForSingleObject(event, INFINITE); |
512 | |
513 | cmdList->Release(); |
514 | cmdAlloc->Release(); |
515 | ::CloseHandle(event); |
516 | fence->Release(); |
517 | uploadBuffer->Release(); |
518 | |
519 | // Create texture view |
520 | D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc; |
521 | ZeroMemory(&srvDesc, sizeof(srvDesc)); |
522 | srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; |
523 | srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; |
524 | srvDesc.Texture2D.MipLevels = desc.MipLevels; |
525 | srvDesc.Texture2D.MostDetailedMip = 0; |
526 | srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; |
527 | bd->pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, font_tex->hFontSrvCpuDescHandle); |
528 | SafeRelease(res&: font_tex->pTextureResource); |
529 | font_tex->pTextureResource = pTexture; |
530 | } |
531 | |
532 | // Store our identifier |
533 | io.Fonts->SetTexID((ImTextureID)font_tex->hFontSrvGpuDescHandle.ptr); |
534 | } |
535 | |
536 | bool ImGui_ImplDX12_CreateDeviceObjects() |
537 | { |
538 | ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData(); |
539 | if (!bd || !bd->pd3dDevice) |
540 | return false; |
541 | if (bd->pPipelineState) |
542 | ImGui_ImplDX12_InvalidateDeviceObjects(); |
543 | |
544 | // Create the root signature |
545 | { |
546 | D3D12_DESCRIPTOR_RANGE descRange = {}; |
547 | descRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; |
548 | descRange.NumDescriptors = 1; |
549 | descRange.BaseShaderRegister = 0; |
550 | descRange.RegisterSpace = 0; |
551 | descRange.OffsetInDescriptorsFromTableStart = 0; |
552 | |
553 | D3D12_ROOT_PARAMETER param[2] = {}; |
554 | |
555 | param[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS; |
556 | param[0].Constants.ShaderRegister = 0; |
557 | param[0].Constants.RegisterSpace = 0; |
558 | param[0].Constants.Num32BitValues = 16; |
559 | param[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_VERTEX; |
560 | |
561 | param[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; |
562 | param[1].DescriptorTable.NumDescriptorRanges = 1; |
563 | param[1].DescriptorTable.pDescriptorRanges = &descRange; |
564 | param[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL; |
565 | |
566 | // Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling. |
567 | D3D12_STATIC_SAMPLER_DESC staticSampler = {}; |
568 | staticSampler.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR; |
569 | staticSampler.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP; |
570 | staticSampler.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP; |
571 | staticSampler.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP; |
572 | staticSampler.MipLODBias = 0.f; |
573 | staticSampler.MaxAnisotropy = 0; |
574 | staticSampler.ComparisonFunc = D3D12_COMPARISON_FUNC_ALWAYS; |
575 | staticSampler.BorderColor = D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK; |
576 | staticSampler.MinLOD = 0.f; |
577 | staticSampler.MaxLOD = 0.f; |
578 | staticSampler.ShaderRegister = 0; |
579 | staticSampler.RegisterSpace = 0; |
580 | staticSampler.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL; |
581 | |
582 | D3D12_ROOT_SIGNATURE_DESC desc = {}; |
583 | desc.NumParameters = _countof(param); |
584 | desc.pParameters = param; |
585 | desc.NumStaticSamplers = 1; |
586 | desc.pStaticSamplers = &staticSampler; |
587 | desc.Flags = |
588 | D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT | |
589 | D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS | |
590 | D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS | |
591 | D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS; |
592 | |
593 | // Load d3d12.dll and D3D12SerializeRootSignature() function address dynamically to facilitate using with D3D12On7. |
594 | // See if any version of d3d12.dll is already loaded in the process. If so, give preference to that. |
595 | static HINSTANCE d3d12_dll = ::GetModuleHandleA("d3d12.dll"); |
596 | if (d3d12_dll == nullptr) |
597 | { |
598 | // Attempt to load d3d12.dll from local directories. This will only succeed if |
599 | // (1) the current OS is Windows 7, and |
600 | // (2) there exists a version of d3d12.dll for Windows 7 (D3D12On7) in one of the following directories. |
601 | // See https://github.com/ocornut/imgui/pull/3696 for details. |
602 | const char* localD3d12Paths[] = { ".\\d3d12.dll", ".\\d3d12on7\\d3d12.dll", ".\\12on7\\d3d12.dll"}; // A. current directory, B. used by some games, C. used in Microsoft D3D12On7 sample |
603 | for (int i = 0; i < IM_ARRAYSIZE(localD3d12Paths); i++) |
604 | if ((d3d12_dll = ::LoadLibraryA(localD3d12Paths[i])) != nullptr) |
605 | break; |
606 | |
607 | // If failed, we are on Windows >= 10. |
608 | if (d3d12_dll == nullptr) |
609 | d3d12_dll = ::LoadLibraryA("d3d12.dll"); |
610 | |
611 | if (d3d12_dll == nullptr) |
612 | return false; |
613 | } |
614 | |
615 | PFN_D3D12_SERIALIZE_ROOT_SIGNATURE D3D12SerializeRootSignatureFn = (PFN_D3D12_SERIALIZE_ROOT_SIGNATURE)::GetProcAddress(d3d12_dll, "D3D12SerializeRootSignature"); |
616 | if (D3D12SerializeRootSignatureFn == nullptr) |
617 | return false; |
618 | |
619 | ID3DBlob* blob = nullptr; |
620 | if (D3D12SerializeRootSignatureFn(&desc, D3D_ROOT_SIGNATURE_VERSION_1, &blob, nullptr) != S_OK) |
621 | return false; |
622 | |
623 | bd->pd3dDevice->CreateRootSignature(0, blob->GetBufferPointer(), blob->GetBufferSize(), IID_PPV_ARGS(&bd->pRootSignature)); |
624 | blob->Release(); |
625 | } |
626 | |
627 | // By using D3DCompile() from <d3dcompiler.h> / d3dcompiler.lib, we introduce a dependency to a given version of d3dcompiler_XX.dll (see D3DCOMPILER_DLL_A) |
628 | // If you would like to use this DX12 sample code but remove this dependency you can: |
629 | // 1) compile once, save the compiled shader blobs into a file or source code and assign them to psoDesc.VS/PS [preferred solution] |
630 | // 2) use code to detect any version of the DLL and grab a pointer to D3DCompile from the DLL. |
631 | // See https://github.com/ocornut/imgui/pull/638 for sources and details. |
632 | |
633 | D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {}; |
634 | psoDesc.NodeMask = 1; |
635 | psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; |
636 | psoDesc.pRootSignature = bd->pRootSignature; |
637 | psoDesc.SampleMask = UINT_MAX; |
638 | psoDesc.NumRenderTargets = 1; |
639 | psoDesc.RTVFormats[0] = bd->RTVFormat; |
640 | psoDesc.DSVFormat = bd->DSVFormat; |
641 | psoDesc.SampleDesc.Count = 1; |
642 | psoDesc.Flags = D3D12_PIPELINE_STATE_FLAG_NONE; |
643 | |
644 | ID3DBlob* vertexShaderBlob; |
645 | ID3DBlob* pixelShaderBlob; |
646 | |
647 | // Create the vertex shader |
648 | { |
649 | static const char* vertexShader = |
650 | "cbuffer vertexBuffer : register(b0) \ |
651 | {\ |
652 | float4x4 ProjectionMatrix; \ |
653 | };\ |
654 | struct VS_INPUT\ |
655 | {\ |
656 | float2 pos : POSITION;\ |
657 | float4 col : COLOR0;\ |
658 | float2 uv : TEXCOORD0;\ |
659 | };\ |
660 | \ |
661 | struct PS_INPUT\ |
662 | {\ |
663 | float4 pos : SV_POSITION;\ |
664 | float4 col : COLOR0;\ |
665 | float2 uv : TEXCOORD0;\ |
666 | };\ |
667 | \ |
668 | PS_INPUT main(VS_INPUT input)\ |
669 | {\ |
670 | PS_INPUT output;\ |
671 | output.pos = mul( ProjectionMatrix, float4(input.pos.xy, 0.f, 1.f));\ |
672 | output.col = input.col;\ |
673 | output.uv = input.uv;\ |
674 | return output;\ |
675 | }"; |
676 | |
677 | if (FAILED(D3DCompile(vertexShader, strlen(s: vertexShader), nullptr, nullptr, nullptr, "main", "vs_5_0", 0, 0, &vertexShaderBlob, nullptr))) |
678 | return false; // NB: Pass ID3DBlob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob! |
679 | psoDesc.VS = { vertexShaderBlob->GetBufferPointer(), vertexShaderBlob->GetBufferSize() }; |
680 | |
681 | // Create the input layout |
682 | static D3D12_INPUT_ELEMENT_DESC local_layout[] = |
683 | { |
684 | { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (UINT)offsetof(ImDrawVert, pos), D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, |
685 | { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (UINT)offsetof(ImDrawVert, uv), D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, |
686 | { "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, (UINT)offsetof(ImDrawVert, col), D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, |
687 | }; |
688 | psoDesc.InputLayout = { local_layout, 3 }; |
689 | } |
690 | |
691 | // Create the pixel shader |
692 | { |
693 | static const char* pixelShader = |
694 | "struct PS_INPUT\ |
695 | {\ |
696 | float4 pos : SV_POSITION;\ |
697 | float4 col : COLOR0;\ |
698 | float2 uv : TEXCOORD0;\ |
699 | };\ |
700 | SamplerState sampler0 : register(s0);\ |
701 | Texture2D texture0 : register(t0);\ |
702 | \ |
703 | float4 main(PS_INPUT input) : SV_Target\ |
704 | {\ |
705 | float4 out_col = input.col * texture0.Sample(sampler0, input.uv); \ |
706 | return out_col; \ |
707 | }"; |
708 | |
709 | if (FAILED(D3DCompile(pixelShader, strlen(s: pixelShader), nullptr, nullptr, nullptr, "main", "ps_5_0", 0, 0, &pixelShaderBlob, nullptr))) |
710 | { |
711 | vertexShaderBlob->Release(); |
712 | return false; // NB: Pass ID3DBlob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob! |
713 | } |
714 | psoDesc.PS = { pixelShaderBlob->GetBufferPointer(), pixelShaderBlob->GetBufferSize() }; |
715 | } |
716 | |
717 | // Create the blending setup |
718 | { |
719 | D3D12_BLEND_DESC& desc = psoDesc.BlendState; |
720 | desc.AlphaToCoverageEnable = false; |
721 | desc.RenderTarget[0].BlendEnable = true; |
722 | desc.RenderTarget[0].SrcBlend = D3D12_BLEND_SRC_ALPHA; |
723 | desc.RenderTarget[0].DestBlend = D3D12_BLEND_INV_SRC_ALPHA; |
724 | desc.RenderTarget[0].BlendOp = D3D12_BLEND_OP_ADD; |
725 | desc.RenderTarget[0].SrcBlendAlpha = D3D12_BLEND_ONE; |
726 | desc.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_INV_SRC_ALPHA; |
727 | desc.RenderTarget[0].BlendOpAlpha = D3D12_BLEND_OP_ADD; |
728 | desc.RenderTarget[0].RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL; |
729 | } |
730 | |
731 | // Create the rasterizer state |
732 | { |
733 | D3D12_RASTERIZER_DESC& desc = psoDesc.RasterizerState; |
734 | desc.FillMode = D3D12_FILL_MODE_SOLID; |
735 | desc.CullMode = D3D12_CULL_MODE_NONE; |
736 | desc.FrontCounterClockwise = FALSE; |
737 | desc.DepthBias = D3D12_DEFAULT_DEPTH_BIAS; |
738 | desc.DepthBiasClamp = D3D12_DEFAULT_DEPTH_BIAS_CLAMP; |
739 | desc.SlopeScaledDepthBias = D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS; |
740 | desc.DepthClipEnable = true; |
741 | desc.MultisampleEnable = FALSE; |
742 | desc.AntialiasedLineEnable = FALSE; |
743 | desc.ForcedSampleCount = 0; |
744 | desc.ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF; |
745 | } |
746 | |
747 | // Create depth-stencil State |
748 | { |
749 | D3D12_DEPTH_STENCIL_DESC& desc = psoDesc.DepthStencilState; |
750 | desc.DepthEnable = false; |
751 | desc.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL; |
752 | desc.DepthFunc = D3D12_COMPARISON_FUNC_ALWAYS; |
753 | desc.StencilEnable = false; |
754 | desc.FrontFace.StencilFailOp = desc.FrontFace.StencilDepthFailOp = desc.FrontFace.StencilPassOp = D3D12_STENCIL_OP_KEEP; |
755 | desc.FrontFace.StencilFunc = D3D12_COMPARISON_FUNC_ALWAYS; |
756 | desc.BackFace = desc.FrontFace; |
757 | } |
758 | |
759 | HRESULT result_pipeline_state = bd->pd3dDevice->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&bd->pPipelineState)); |
760 | vertexShaderBlob->Release(); |
761 | pixelShaderBlob->Release(); |
762 | if (result_pipeline_state != S_OK) |
763 | return false; |
764 | |
765 | ImGui_ImplDX12_CreateFontsTexture(); |
766 | |
767 | return true; |
768 | } |
769 | |
770 | static void ImGui_ImplDX12_DestroyRenderBuffers(ImGui_ImplDX12_RenderBuffers* render_buffers) |
771 | { |
772 | SafeRelease(res&: render_buffers->IndexBuffer); |
773 | SafeRelease(res&: render_buffers->VertexBuffer); |
774 | render_buffers->IndexBufferSize = render_buffers->VertexBufferSize = 0; |
775 | } |
776 | |
777 | void ImGui_ImplDX12_InvalidateDeviceObjects() |
778 | { |
779 | ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData(); |
780 | if (!bd || !bd->pd3dDevice) |
781 | return; |
782 | |
783 | if (bd->commandQueueOwned) |
784 | SafeRelease(res&: bd->pCommandQueue); |
785 | bd->commandQueueOwned = false; |
786 | SafeRelease(res&: bd->pRootSignature); |
787 | SafeRelease(res&: bd->pPipelineState); |
788 | |
789 | // Free SRV descriptor used by texture |
790 | ImGuiIO& io = ImGui::GetIO(); |
791 | ImGui_ImplDX12_Texture* font_tex = &bd->FontTexture; |
792 | bd->InitInfo.SrvDescriptorFreeFn(&bd->InitInfo, font_tex->hFontSrvCpuDescHandle, font_tex->hFontSrvGpuDescHandle); |
793 | SafeRelease(res&: font_tex->pTextureResource); |
794 | io.Fonts->SetTexID(0); // We copied bd->hFontSrvGpuDescHandle to io.Fonts->TexID so let's clear that as well. |
795 | } |
796 | |
797 | bool ImGui_ImplDX12_Init(ImGui_ImplDX12_InitInfo* init_info) |
798 | { |
799 | ImGuiIO& io = ImGui::GetIO(); |
800 | IMGUI_CHECKVERSION(); |
801 | IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!"); |
802 | |
803 | // Setup backend capabilities flags |
804 | ImGui_ImplDX12_Data* bd = IM_NEW(ImGui_ImplDX12_Data)(); |
805 | bd->InitInfo = *init_info; // Deep copy |
806 | init_info = &bd->InitInfo; |
807 | |
808 | bd->pd3dDevice = init_info->Device; |
809 | IM_ASSERT(init_info->CommandQueue != NULL); |
810 | bd->pCommandQueue = init_info->CommandQueue; |
811 | bd->RTVFormat = init_info->RTVFormat; |
812 | bd->DSVFormat = init_info->DSVFormat; |
813 | bd->numFramesInFlight = init_info->NumFramesInFlight; |
814 | bd->pd3dSrvDescHeap = init_info->SrvDescriptorHeap; |
815 | |
816 | io.BackendRendererUserData = (void*)bd; |
817 | io.BackendRendererName = "imgui_impl_dx12"; |
818 | io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. |
819 | io.BackendFlags |= ImGuiBackendFlags_RendererHasViewports; // We can create multi-viewports on the Renderer side (optional) |
820 | if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) |
821 | ImGui_ImplDX12_InitPlatformInterface(); |
822 | |
823 | // Create a dummy ImGui_ImplDX12_ViewportData holder for the main viewport, |
824 | // Since this is created and managed by the application, we will only use the ->Resources[] fields. |
825 | ImGuiViewport* main_viewport = ImGui::GetMainViewport(); |
826 | main_viewport->RendererUserData = IM_NEW(ImGui_ImplDX12_ViewportData)(bd->numFramesInFlight); |
827 | |
828 | #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS |
829 | if (init_info->SrvDescriptorAllocFn == nullptr) |
830 | { |
831 | // Wrap legacy behavior of passing space for a single descriptor |
832 | IM_ASSERT(init_info->LegacySingleSrvCpuDescriptor.ptr != 0 && init_info->LegacySingleSrvGpuDescriptor.ptr != 0); |
833 | init_info->SrvDescriptorAllocFn = [](ImGui_ImplDX12_InitInfo*, D3D12_CPU_DESCRIPTOR_HANDLE* out_cpu_handle, D3D12_GPU_DESCRIPTOR_HANDLE* out_gpu_handle) |
834 | { |
835 | ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData(); |
836 | IM_ASSERT(bd->LegacySingleDescriptorUsed == false && "Only 1 simultaneous texture allowed with legacy ImGui_ImplDX12_Init() signature!"); |
837 | *out_cpu_handle = bd->InitInfo.LegacySingleSrvCpuDescriptor; |
838 | *out_gpu_handle = bd->InitInfo.LegacySingleSrvGpuDescriptor; |
839 | bd->LegacySingleDescriptorUsed = true; |
840 | }; |
841 | init_info->SrvDescriptorFreeFn = [](ImGui_ImplDX12_InitInfo*, D3D12_CPU_DESCRIPTOR_HANDLE, D3D12_GPU_DESCRIPTOR_HANDLE) |
842 | { |
843 | ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData(); |
844 | IM_ASSERT(bd->LegacySingleDescriptorUsed == true); |
845 | bd->LegacySingleDescriptorUsed = false; |
846 | }; |
847 | } |
848 | #endif |
849 | |
850 | // Allocate 1 SRV descriptor for the font texture |
851 | IM_ASSERT(init_info->SrvDescriptorAllocFn != nullptr && init_info->SrvDescriptorFreeFn != nullptr); |
852 | init_info->SrvDescriptorAllocFn(&bd->InitInfo, &bd->FontTexture.hFontSrvCpuDescHandle, &bd->FontTexture.hFontSrvGpuDescHandle); |
853 | |
854 | return true; |
855 | } |
856 | |
857 | #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS |
858 | // Legacy initialization API Obsoleted in 1.91.5 |
859 | // 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, they must be in 'srv_descriptor_heap' |
860 | bool ImGui_ImplDX12_Init(ID3D12Device* device, int num_frames_in_flight, DXGI_FORMAT rtv_format, ID3D12DescriptorHeap* srv_descriptor_heap, D3D12_CPU_DESCRIPTOR_HANDLE font_srv_cpu_desc_handle, D3D12_GPU_DESCRIPTOR_HANDLE font_srv_gpu_desc_handle) |
861 | { |
862 | ImGui_ImplDX12_InitInfo init_info; |
863 | init_info.Device = device; |
864 | init_info.NumFramesInFlight = num_frames_in_flight; |
865 | init_info.RTVFormat = rtv_format; |
866 | init_info.SrvDescriptorHeap = srv_descriptor_heap; |
867 | init_info.LegacySingleSrvCpuDescriptor = font_srv_cpu_desc_handle; |
868 | init_info.LegacySingleSrvGpuDescriptor = font_srv_gpu_desc_handle; |
869 | |
870 | D3D12_COMMAND_QUEUE_DESC queueDesc = {}; |
871 | queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; |
872 | queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; |
873 | queueDesc.NodeMask = 1; |
874 | HRESULT hr = device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&init_info.CommandQueue)); |
875 | IM_ASSERT(SUCCEEDED(hr)); |
876 | |
877 | bool ret = ImGui_ImplDX12_Init(init_info: &init_info); |
878 | ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData(); |
879 | bd->commandQueueOwned = true; |
880 | return ret; |
881 | } |
882 | #endif |
883 | |
884 | void ImGui_ImplDX12_Shutdown() |
885 | { |
886 | ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData(); |
887 | IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?"); |
888 | ImGuiIO& io = ImGui::GetIO(); |
889 | |
890 | // Manually delete main viewport render resources in-case we haven't initialized for viewports |
891 | ImGuiViewport* main_viewport = ImGui::GetMainViewport(); |
892 | if (ImGui_ImplDX12_ViewportData* vd = (ImGui_ImplDX12_ViewportData*)main_viewport->RendererUserData) |
893 | { |
894 | // We could just call ImGui_ImplDX12_DestroyWindow(main_viewport) as a convenience but that would be misleading since we only use data->Resources[] |
895 | for (UINT i = 0; i < bd->numFramesInFlight; i++) |
896 | ImGui_ImplDX12_DestroyRenderBuffers(&vd->FrameRenderBuffers[i]); |
897 | IM_DELETE(p: vd); |
898 | main_viewport->RendererUserData = nullptr; |
899 | } |
900 | |
901 | // Clean up windows and device objects |
902 | ImGui_ImplDX12_ShutdownPlatformInterface(); |
903 | ImGui_ImplDX12_InvalidateDeviceObjects(); |
904 | |
905 | io.BackendRendererName = nullptr; |
906 | io.BackendRendererUserData = nullptr; |
907 | io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasViewports); |
908 | IM_DELETE(p: bd); |
909 | } |
910 | |
911 | void ImGui_ImplDX12_NewFrame() |
912 | { |
913 | ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData(); |
914 | IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplDX12_Init()?"); |
915 | |
916 | if (!bd->pPipelineState) |
917 | ImGui_ImplDX12_CreateDeviceObjects(); |
918 | } |
919 | |
920 | //-------------------------------------------------------------------------------------------------------- |
921 | // MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT |
922 | // This is an _advanced_ and _optional_ feature, allowing the backend to create and handle multiple viewports simultaneously. |
923 | // 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.. |
924 | //-------------------------------------------------------------------------------------------------------- |
925 | |
926 | static void ImGui_ImplDX12_CreateWindow(ImGuiViewport* viewport) |
927 | { |
928 | ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData(); |
929 | ImGui_ImplDX12_ViewportData* vd = IM_NEW(ImGui_ImplDX12_ViewportData)(bd->numFramesInFlight); |
930 | viewport->RendererUserData = vd; |
931 | |
932 | // PlatformHandleRaw should always be a HWND, whereas PlatformHandle might be a higher-level handle (e.g. GLFWWindow*, SDL's WindowID). |
933 | // Some backends will leave PlatformHandleRaw == 0, in which case we assume PlatformHandle will contain the HWND. |
934 | HWND hwnd = viewport->PlatformHandleRaw ? (HWND)viewport->PlatformHandleRaw : (HWND)viewport->PlatformHandle; |
935 | IM_ASSERT(hwnd != 0); |
936 | |
937 | vd->FrameIndex = UINT_MAX; |
938 | |
939 | // Create command queue. |
940 | D3D12_COMMAND_QUEUE_DESC queue_desc = {}; |
941 | queue_desc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; |
942 | queue_desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; |
943 | |
944 | HRESULT res = S_OK; |
945 | res = bd->pd3dDevice->CreateCommandQueue(&queue_desc, IID_PPV_ARGS(&vd->CommandQueue)); |
946 | IM_ASSERT(res == S_OK); |
947 | |
948 | // Create command allocator. |
949 | for (UINT i = 0; i < bd->numFramesInFlight; ++i) |
950 | { |
951 | res = bd->pd3dDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&vd->FrameCtx[i].CommandAllocator)); |
952 | IM_ASSERT(res == S_OK); |
953 | } |
954 | |
955 | // Create command list. |
956 | res = bd->pd3dDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, vd->FrameCtx[0].CommandAllocator, nullptr, IID_PPV_ARGS(&vd->CommandList)); |
957 | IM_ASSERT(res == S_OK); |
958 | vd->CommandList->Close(); |
959 | |
960 | // Create fence. |
961 | res = bd->pd3dDevice->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&vd->Fence)); |
962 | IM_ASSERT(res == S_OK); |
963 | |
964 | vd->FenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr); |
965 | IM_ASSERT(vd->FenceEvent != nullptr); |
966 | |
967 | // Create swap chain |
968 | // FIXME-VIEWPORT: May want to copy/inherit swap chain settings from the user/application. |
969 | DXGI_SWAP_CHAIN_DESC1 sd1; |
970 | ZeroMemory(&sd1, sizeof(sd1)); |
971 | sd1.BufferCount = bd->numFramesInFlight; |
972 | sd1.Width = (UINT)viewport->Size.x; |
973 | sd1.Height = (UINT)viewport->Size.y; |
974 | sd1.Format = bd->RTVFormat; |
975 | sd1.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; |
976 | sd1.SampleDesc.Count = 1; |
977 | sd1.SampleDesc.Quality = 0; |
978 | sd1.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; |
979 | sd1.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED; |
980 | sd1.Scaling = DXGI_SCALING_NONE; |
981 | sd1.Stereo = FALSE; |
982 | |
983 | IDXGIFactory4* dxgi_factory = nullptr; |
984 | res = ::CreateDXGIFactory1(IID_PPV_ARGS(&dxgi_factory)); |
985 | IM_ASSERT(res == S_OK); |
986 | |
987 | IDXGISwapChain1* swap_chain = nullptr; |
988 | res = dxgi_factory->CreateSwapChainForHwnd(vd->CommandQueue, hwnd, &sd1, nullptr, nullptr, &swap_chain); |
989 | IM_ASSERT(res == S_OK); |
990 | |
991 | dxgi_factory->Release(); |
992 | |
993 | // Or swapChain.As(&mSwapChain) |
994 | IM_ASSERT(vd->SwapChain == nullptr); |
995 | swap_chain->QueryInterface(IID_PPV_ARGS(&vd->SwapChain)); |
996 | swap_chain->Release(); |
997 | |
998 | // Create the render targets |
999 | if (vd->SwapChain) |
1000 | { |
1001 | D3D12_DESCRIPTOR_HEAP_DESC desc = {}; |
1002 | desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; |
1003 | desc.NumDescriptors = bd->numFramesInFlight; |
1004 | desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; |
1005 | desc.NodeMask = 1; |
1006 | |
1007 | HRESULT hr = bd->pd3dDevice->CreateDescriptorHeap(&desc, IID_PPV_ARGS(&vd->RtvDescHeap)); |
1008 | IM_ASSERT(hr == S_OK); |
1009 | |
1010 | SIZE_T rtv_descriptor_size = bd->pd3dDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); |
1011 | D3D12_CPU_DESCRIPTOR_HANDLE rtv_handle = vd->RtvDescHeap->GetCPUDescriptorHandleForHeapStart(); |
1012 | for (UINT i = 0; i < bd->numFramesInFlight; i++) |
1013 | { |
1014 | vd->FrameCtx[i].RenderTargetCpuDescriptors = rtv_handle; |
1015 | rtv_handle.ptr += rtv_descriptor_size; |
1016 | } |
1017 | |
1018 | ID3D12Resource* back_buffer; |
1019 | for (UINT i = 0; i < bd->numFramesInFlight; i++) |
1020 | { |
1021 | IM_ASSERT(vd->FrameCtx[i].RenderTarget == nullptr); |
1022 | vd->SwapChain->GetBuffer(i, IID_PPV_ARGS(&back_buffer)); |
1023 | bd->pd3dDevice->CreateRenderTargetView(back_buffer, nullptr, vd->FrameCtx[i].RenderTargetCpuDescriptors); |
1024 | vd->FrameCtx[i].RenderTarget = back_buffer; |
1025 | } |
1026 | } |
1027 | |
1028 | for (UINT i = 0; i < bd->numFramesInFlight; i++) |
1029 | ImGui_ImplDX12_DestroyRenderBuffers(&vd->FrameRenderBuffers[i]); |
1030 | } |
1031 | |
1032 | static void ImGui_WaitForPendingOperations(ImGui_ImplDX12_ViewportData* vd) |
1033 | { |
1034 | HRESULT hr = S_FALSE; |
1035 | if (vd && vd->CommandQueue && vd->Fence && vd->FenceEvent) |
1036 | { |
1037 | hr = vd->CommandQueue->Signal(vd->Fence, ++vd->FenceSignaledValue); |
1038 | IM_ASSERT(hr == S_OK); |
1039 | ::WaitForSingleObject(vd->FenceEvent, 0); // Reset any forgotten waits |
1040 | hr = vd->Fence->SetEventOnCompletion(vd->FenceSignaledValue, vd->FenceEvent); |
1041 | IM_ASSERT(hr == S_OK); |
1042 | ::WaitForSingleObject(vd->FenceEvent, INFINITE); |
1043 | } |
1044 | } |
1045 | |
1046 | static void ImGui_ImplDX12_DestroyWindow(ImGuiViewport* viewport) |
1047 | { |
1048 | // The main viewport (owned by the application) will always have RendererUserData == 0 since we didn't create the data for it. |
1049 | ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData(); |
1050 | if (ImGui_ImplDX12_ViewportData* vd = (ImGui_ImplDX12_ViewportData*)viewport->RendererUserData) |
1051 | { |
1052 | ImGui_WaitForPendingOperations(vd); |
1053 | |
1054 | SafeRelease(res&: vd->CommandQueue); |
1055 | SafeRelease(res&: vd->CommandList); |
1056 | SafeRelease(res&: vd->SwapChain); |
1057 | SafeRelease(res&: vd->RtvDescHeap); |
1058 | SafeRelease(res&: vd->Fence); |
1059 | ::CloseHandle(vd->FenceEvent); |
1060 | vd->FenceEvent = nullptr; |
1061 | |
1062 | for (UINT i = 0; i < bd->numFramesInFlight; i++) |
1063 | { |
1064 | SafeRelease(vd->FrameCtx[i].RenderTarget); |
1065 | SafeRelease(vd->FrameCtx[i].CommandAllocator); |
1066 | ImGui_ImplDX12_DestroyRenderBuffers(&vd->FrameRenderBuffers[i]); |
1067 | } |
1068 | IM_DELETE(p: vd); |
1069 | } |
1070 | viewport->RendererUserData = nullptr; |
1071 | } |
1072 | |
1073 | static void ImGui_ImplDX12_SetWindowSize(ImGuiViewport* viewport, ImVec2 size) |
1074 | { |
1075 | ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData(); |
1076 | ImGui_ImplDX12_ViewportData* vd = (ImGui_ImplDX12_ViewportData*)viewport->RendererUserData; |
1077 | |
1078 | ImGui_WaitForPendingOperations(vd); |
1079 | |
1080 | for (UINT i = 0; i < bd->numFramesInFlight; i++) |
1081 | SafeRelease(vd->FrameCtx[i].RenderTarget); |
1082 | |
1083 | if (vd->SwapChain) |
1084 | { |
1085 | ID3D12Resource* back_buffer = nullptr; |
1086 | vd->SwapChain->ResizeBuffers(0, (UINT)size.x, (UINT)size.y, DXGI_FORMAT_UNKNOWN, 0); |
1087 | for (UINT i = 0; i < bd->numFramesInFlight; i++) |
1088 | { |
1089 | vd->SwapChain->GetBuffer(i, IID_PPV_ARGS(&back_buffer)); |
1090 | bd->pd3dDevice->CreateRenderTargetView(back_buffer, nullptr, vd->FrameCtx[i].RenderTargetCpuDescriptors); |
1091 | vd->FrameCtx[i].RenderTarget = back_buffer; |
1092 | } |
1093 | } |
1094 | } |
1095 | |
1096 | static void ImGui_ImplDX12_RenderWindow(ImGuiViewport* viewport, void*) |
1097 | { |
1098 | ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData(); |
1099 | ImGui_ImplDX12_ViewportData* vd = (ImGui_ImplDX12_ViewportData*)viewport->RendererUserData; |
1100 | |
1101 | ImGui_ImplDX12_FrameContext* frame_context = &vd->FrameCtx[vd->FrameIndex % bd->numFramesInFlight]; |
1102 | UINT back_buffer_idx = vd->SwapChain->GetCurrentBackBufferIndex(); |
1103 | |
1104 | const ImVec4 clear_color = ImVec4(0.0f, 0.0f, 0.0f, 1.0f); |
1105 | D3D12_RESOURCE_BARRIER barrier = {}; |
1106 | barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; |
1107 | barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; |
1108 | barrier.Transition.pResource = vd->FrameCtx[back_buffer_idx].RenderTarget; |
1109 | barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; |
1110 | barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT; |
1111 | barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET; |
1112 | |
1113 | // Draw |
1114 | ID3D12GraphicsCommandList* cmd_list = vd->CommandList; |
1115 | |
1116 | frame_context->CommandAllocator->Reset(); |
1117 | cmd_list->Reset(frame_context->CommandAllocator, nullptr); |
1118 | cmd_list->ResourceBarrier(1, &barrier); |
1119 | cmd_list->OMSetRenderTargets(1, &vd->FrameCtx[back_buffer_idx].RenderTargetCpuDescriptors, FALSE, nullptr); |
1120 | if (!(viewport->Flags & ImGuiViewportFlags_NoRendererClear)) |
1121 | cmd_list->ClearRenderTargetView(vd->FrameCtx[back_buffer_idx].RenderTargetCpuDescriptors, (float*)&clear_color, 0, nullptr); |
1122 | cmd_list->SetDescriptorHeaps(1, &bd->pd3dSrvDescHeap); |
1123 | |
1124 | ImGui_ImplDX12_RenderDrawData(draw_data: viewport->DrawData, command_list: cmd_list); |
1125 | |
1126 | barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET; |
1127 | barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT; |
1128 | cmd_list->ResourceBarrier(1, &barrier); |
1129 | cmd_list->Close(); |
1130 | |
1131 | vd->CommandQueue->Wait(vd->Fence, vd->FenceSignaledValue); |
1132 | vd->CommandQueue->ExecuteCommandLists(1, (ID3D12CommandList* const*)&cmd_list); |
1133 | vd->CommandQueue->Signal(vd->Fence, ++vd->FenceSignaledValue); |
1134 | } |
1135 | |
1136 | static void ImGui_ImplDX12_SwapBuffers(ImGuiViewport* viewport, void*) |
1137 | { |
1138 | ImGui_ImplDX12_ViewportData* vd = (ImGui_ImplDX12_ViewportData*)viewport->RendererUserData; |
1139 | |
1140 | vd->SwapChain->Present(0, 0); |
1141 | while (vd->Fence->GetCompletedValue() < vd->FenceSignaledValue) |
1142 | ::SwitchToThread(); |
1143 | } |
1144 | |
1145 | void ImGui_ImplDX12_InitPlatformInterface() |
1146 | { |
1147 | ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); |
1148 | platform_io.Renderer_CreateWindow = ImGui_ImplDX12_CreateWindow; |
1149 | platform_io.Renderer_DestroyWindow = ImGui_ImplDX12_DestroyWindow; |
1150 | platform_io.Renderer_SetWindowSize = ImGui_ImplDX12_SetWindowSize; |
1151 | platform_io.Renderer_RenderWindow = ImGui_ImplDX12_RenderWindow; |
1152 | platform_io.Renderer_SwapBuffers = ImGui_ImplDX12_SwapBuffers; |
1153 | } |
1154 | |
1155 | void ImGui_ImplDX12_ShutdownPlatformInterface() |
1156 | { |
1157 | ImGui::DestroyPlatformWindows(); |
1158 | } |
1159 | |
1160 | //----------------------------------------------------------------------------- |
1161 | |
1162 | #endif // #ifndef IMGUI_DISABLE |
1163 |
Definitions
- ImGui_ImplDX12_Texture
- ImGui_ImplDX12_Texture
- ImGui_ImplDX12_Data
- ImGui_ImplDX12_Data
- ImGui_ImplDX12_GetBackendData
- ImGui_ImplDX12_RenderBuffers
- ImGui_ImplDX12_FrameContext
- ImGui_ImplDX12_ViewportData
- ImGui_ImplDX12_ViewportData
- ~ImGui_ImplDX12_ViewportData
- VERTEX_CONSTANT_BUFFER_DX12
- ImGui_ImplDX12_SetupRenderState
- SafeRelease
- ImGui_ImplDX12_RenderDrawData
- ImGui_ImplDX12_CreateFontsTexture
- ImGui_ImplDX12_CreateDeviceObjects
- ImGui_ImplDX12_DestroyRenderBuffers
- ImGui_ImplDX12_InvalidateDeviceObjects
- ImGui_ImplDX12_Init
- ImGui_ImplDX12_Init
- ImGui_ImplDX12_Shutdown
- ImGui_ImplDX12_NewFrame
- ImGui_ImplDX12_CreateWindow
- ImGui_WaitForPendingOperations
- ImGui_ImplDX12_DestroyWindow
- ImGui_ImplDX12_SetWindowSize
- ImGui_ImplDX12_RenderWindow
- ImGui_ImplDX12_SwapBuffers
- ImGui_ImplDX12_InitPlatformInterface
Improve your Profiling and Debugging skills
Find out more