Skip to content

Commit eefe5d5

Browse files
committed
Backends: DirectX12: added ImGuiBackendFlags_RendererHasTextures support.
# Conflicts: # backends/imgui_impl_dx12.cpp
1 parent 2d2b1bc commit eefe5d5

File tree

2 files changed

+163
-72
lines changed

2 files changed

+163
-72
lines changed

backends/imgui_impl_dx12.cpp

Lines changed: 158 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22
// This needs to be used along with a Platform Backend (e.g. Win32)
33

44
// Implemented features:
5-
// [X] Renderer: User texture binding. Use 'D3D12_GPU_DESCRIPTOR_HANDLE' as ImTextureID. Read the FAQ about ImTextureID!
5+
// [X] Renderer: User texture binding. Use 'D3D12_GPU_DESCRIPTOR_HANDLE' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef!
66
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
7+
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
78
// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'.
89

910
// The aim of imgui_impl_dx12.h/.cpp is to be usable in your engine without any modification.
@@ -19,6 +20,7 @@
1920

2021
// CHANGELOG
2122
// (minor and older changes stripped away, please see git history for details)
23+
// 2025-06-11: DirectX12: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas.
2224
// 2025-05-07: DirectX12: Honor draw_data->FramebufferScale to allow for custom backends and experiment using it (consistently with other renderer backends, even though in normal condition it is not set under Windows).
2325
// 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)
2426
// 2025-01-15: DirectX12: Texture upload use the command queue provided in ImGui_ImplDX12_InitInfo instead of creating its own.
@@ -184,6 +186,13 @@ void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandL
184186
if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f)
185187
return;
186188

189+
// Catch up with texture updates. Most of the times, the list will have 1 element with an OK status, aka nothing to do.
190+
// (This almost always points to ImGui::GetPlatformIO().Textures[] but is part of ImDrawData to allow overriding or disabling texture updates).
191+
if (draw_data->Textures != nullptr)
192+
for (ImTextureData* tex : *draw_data->Textures)
193+
if (tex->Status != ImTextureStatus_OK)
194+
ImGui_ImplDX12_UpdateTexture(tex);
195+
187196
// FIXME: We are assuming that this only gets called once per frame!
188197
ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
189198
bd->frameIndex = bd->frameIndex + 1;
@@ -316,18 +325,39 @@ void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandL
316325
platform_io.Renderer_RenderState = nullptr;
317326
}
318327

319-
static void ImGui_ImplDX12_CreateFontsTexture()
328+
static void ImGui_ImplDX12_DestroyTexture(ImTextureData* tex)
329+
{
330+
ImGui_ImplDX12_Texture* backend_tex = (ImGui_ImplDX12_Texture*)tex->BackendUserData;
331+
if (backend_tex == nullptr)
332+
return;
333+
IM_ASSERT(backend_tex->hFontSrvGpuDescHandle.ptr == (UINT64)tex->TexID);
334+
ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
335+
bd->InitInfo.SrvDescriptorFreeFn(&bd->InitInfo, backend_tex->hFontSrvCpuDescHandle, backend_tex->hFontSrvGpuDescHandle);
336+
SafeRelease(backend_tex->pTextureResource);
337+
backend_tex->hFontSrvCpuDescHandle.ptr = 0;
338+
backend_tex->hFontSrvGpuDescHandle.ptr = 0;
339+
IM_DELETE(backend_tex);
340+
341+
// Clear identifiers and mark as destroyed (in order to allow e.g. calling InvalidateDeviceObjects while running)
342+
tex->SetTexID(ImTextureID_Invalid);
343+
tex->SetStatus(ImTextureStatus_Destroyed);
344+
tex->BackendUserData = nullptr;
345+
}
346+
347+
void ImGui_ImplDX12_UpdateTexture(ImTextureData* tex)
320348
{
321-
// Build texture atlas
322-
ImGuiIO& io = ImGui::GetIO();
323349
ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
324-
unsigned char* pixels;
325-
int width, height;
326-
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
350+
bool need_barrier_before_copy = true; // Do we need a resource barrier before we copy new data in?
327351

328-
// Upload texture to graphics system
329-
ImGui_ImplDX12_Texture* font_tex = &bd->FontTexture;
352+
if (tex->Status == ImTextureStatus_WantCreate)
330353
{
354+
// Create and upload new texture to graphics system
355+
//IMGUI_DEBUG_LOG("UpdateTexture #%03d: WantCreate %dx%d\n", tex->UniqueID, tex->Width, tex->Height);
356+
IM_ASSERT(tex->TexID == ImTextureID_Invalid && tex->BackendUserData == nullptr);
357+
IM_ASSERT(tex->Format == ImTextureFormat_RGBA32);
358+
ImGui_ImplDX12_Texture* backend_tex = IM_NEW(ImGui_ImplDX12_Texture)();
359+
bd->InitInfo.SrvDescriptorAllocFn(&bd->InitInfo, &backend_tex->hFontSrvCpuDescHandle, &backend_tex->hFontSrvGpuDescHandle); // Allocate a desctriptor handle
360+
331361
D3D12_HEAP_PROPERTIES props = {};
332362
props.Type = D3D12_HEAP_TYPE_DEFAULT;
333363
props.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
@@ -337,8 +367,8 @@ static void ImGui_ImplDX12_CreateFontsTexture()
337367
ZeroMemory(&desc, sizeof(desc));
338368
desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
339369
desc.Alignment = 0;
340-
desc.Width = width;
341-
desc.Height = height;
370+
desc.Width = tex->Width;
371+
desc.Height = tex->Height;
342372
desc.DepthOrArraySize = 1;
343373
desc.MipLevels = 1;
344374
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
@@ -351,8 +381,47 @@ static void ImGui_ImplDX12_CreateFontsTexture()
351381
bd->pd3dDevice->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc,
352382
D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&pTexture));
353383

354-
UINT upload_pitch = (width * 4 + D3D12_TEXTURE_DATA_PITCH_ALIGNMENT - 1u) & ~(D3D12_TEXTURE_DATA_PITCH_ALIGNMENT - 1u);
355-
UINT upload_size = height * upload_pitch;
384+
// Create SRV
385+
D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc;
386+
ZeroMemory(&srvDesc, sizeof(srvDesc));
387+
srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
388+
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
389+
srvDesc.Texture2D.MipLevels = desc.MipLevels;
390+
srvDesc.Texture2D.MostDetailedMip = 0;
391+
srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
392+
bd->pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, backend_tex->hFontSrvCpuDescHandle);
393+
SafeRelease(backend_tex->pTextureResource);
394+
backend_tex->pTextureResource = pTexture;
395+
396+
// Store identifiers
397+
tex->SetTexID((ImTextureID)backend_tex->hFontSrvGpuDescHandle.ptr);
398+
tex->BackendUserData = backend_tex;
399+
need_barrier_before_copy = false; // Because this is a newly-created texture it will be in D3D12_RESOURCE_STATE_COMMON and thus we don't need a barrier
400+
// We don't set tex->Status to ImTextureStatus_OK to let the code fallthrough below.
401+
}
402+
403+
if (tex->Status == ImTextureStatus_WantCreate || tex->Status == ImTextureStatus_WantUpdates)
404+
{
405+
ImGui_ImplDX12_Texture* backend_tex = (ImGui_ImplDX12_Texture*)tex->BackendUserData;
406+
IM_ASSERT(tex->Format == ImTextureFormat_RGBA32);
407+
408+
// We could use the smaller rect on _WantCreate but using the full rect allows us to clear the texture.
409+
// FIXME-OPT: Uploading single box even when using ImTextureStatus_WantUpdates. Could use tex->Updates[]
410+
// - Copy all blocks contiguously in upload buffer.
411+
// - Barrier before copy, submit all CopyTextureRegion(), barrier after copy.
412+
const int upload_x = (tex->Status == ImTextureStatus_WantCreate) ? 0 : tex->UpdateRect.x;
413+
const int upload_y = (tex->Status == ImTextureStatus_WantCreate) ? 0 : tex->UpdateRect.y;
414+
const int upload_w = (tex->Status == ImTextureStatus_WantCreate) ? tex->Width : tex->UpdateRect.w;
415+
const int upload_h = (tex->Status == ImTextureStatus_WantCreate) ? tex->Height : tex->UpdateRect.h;
416+
417+
// Update full texture or selected blocks. We only ever write to textures regions which have never been used before!
418+
// This backend choose to use tex->UpdateRect but you can use tex->Updates[] to upload individual regions.
419+
UINT upload_pitch_src = upload_w * tex->BytesPerPixel;
420+
UINT upload_pitch_dst = (upload_pitch_src + D3D12_TEXTURE_DATA_PITCH_ALIGNMENT - 1u) & ~(D3D12_TEXTURE_DATA_PITCH_ALIGNMENT - 1u);
421+
UINT upload_size = upload_pitch_dst * upload_h;
422+
423+
D3D12_RESOURCE_DESC desc;
424+
ZeroMemory(&desc, sizeof(desc));
356425
desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
357426
desc.Alignment = 0;
358427
desc.Width = upload_size;
@@ -365,64 +434,83 @@ static void ImGui_ImplDX12_CreateFontsTexture()
365434
desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
366435
desc.Flags = D3D12_RESOURCE_FLAG_NONE;
367436

437+
D3D12_HEAP_PROPERTIES props;
438+
memset(&props, 0, sizeof(D3D12_HEAP_PROPERTIES));
368439
props.Type = D3D12_HEAP_TYPE_UPLOAD;
369440
props.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
370441
props.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
371442

443+
// FIXME-OPT: Can upload buffer be reused?
372444
ID3D12Resource* uploadBuffer = nullptr;
373445
HRESULT hr = bd->pd3dDevice->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc,
374446
D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&uploadBuffer));
375447
IM_ASSERT(SUCCEEDED(hr));
376448

449+
// Create temporary command list and execute immediately
450+
ID3D12Fence* fence = nullptr;
451+
hr = bd->pd3dDevice->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&fence));
452+
IM_ASSERT(SUCCEEDED(hr));
453+
454+
HANDLE event = ::CreateEvent(0, 0, 0, 0);
455+
IM_ASSERT(event != nullptr);
456+
457+
// FIXME-OPT: Create once and reuse?
458+
ID3D12CommandAllocator* cmdAlloc = nullptr;
459+
hr = bd->pd3dDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&cmdAlloc));
460+
IM_ASSERT(SUCCEEDED(hr));
461+
462+
// FIXME-OPT: Can be use the one from user? (pass ID3D12GraphicsCommandList* to ImGui_ImplDX12_UpdateTextures)
463+
ID3D12GraphicsCommandList* cmdList = nullptr;
464+
hr = bd->pd3dDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, cmdAlloc, nullptr, IID_PPV_ARGS(&cmdList));
465+
IM_ASSERT(SUCCEEDED(hr));
466+
467+
// Copy to upload buffer
377468
void* mapped = nullptr;
378469
D3D12_RANGE range = { 0, upload_size };
379470
hr = uploadBuffer->Map(0, &range, &mapped);
380471
IM_ASSERT(SUCCEEDED(hr));
381-
for (int y = 0; y < height; y++)
382-
memcpy((void*) ((uintptr_t) mapped + y * upload_pitch), pixels + y * width * 4, width * 4);
472+
for (int y = 0; y < upload_h; y++)
473+
memcpy((void*)((uintptr_t)mapped + y * upload_pitch_dst), tex->GetPixelsAt(upload_x, upload_y + y), upload_pitch_src);
383474
uploadBuffer->Unmap(0, &range);
384475

476+
if (need_barrier_before_copy)
477+
{
478+
D3D12_RESOURCE_BARRIER barrier = {};
479+
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
480+
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
481+
barrier.Transition.pResource = backend_tex->pTextureResource;
482+
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
483+
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
484+
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_DEST;
485+
cmdList->ResourceBarrier(1, &barrier);
486+
}
487+
385488
D3D12_TEXTURE_COPY_LOCATION srcLocation = {};
386489
D3D12_TEXTURE_COPY_LOCATION dstLocation = {};
387490
{
388491
srcLocation.pResource = uploadBuffer;
389492
srcLocation.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
390493
srcLocation.PlacedFootprint.Footprint.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
391-
srcLocation.PlacedFootprint.Footprint.Width = width;
392-
srcLocation.PlacedFootprint.Footprint.Height = height;
494+
srcLocation.PlacedFootprint.Footprint.Width = upload_w;
495+
srcLocation.PlacedFootprint.Footprint.Height = upload_h;
393496
srcLocation.PlacedFootprint.Footprint.Depth = 1;
394-
srcLocation.PlacedFootprint.Footprint.RowPitch = upload_pitch;
395-
396-
dstLocation.pResource = pTexture;
497+
srcLocation.PlacedFootprint.Footprint.RowPitch = upload_pitch_dst;
498+
dstLocation.pResource = backend_tex->pTextureResource;
397499
dstLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
398500
dstLocation.SubresourceIndex = 0;
399501
}
502+
cmdList->CopyTextureRegion(&dstLocation, upload_x, upload_y, 0, &srcLocation, nullptr);
400503

401-
D3D12_RESOURCE_BARRIER barrier = {};
402-
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
403-
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
404-
barrier.Transition.pResource = pTexture;
405-
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
406-
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
407-
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
408-
409-
ID3D12Fence* fence = nullptr;
410-
hr = bd->pd3dDevice->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&fence));
411-
IM_ASSERT(SUCCEEDED(hr));
412-
413-
HANDLE event = ::CreateEvent(0, 0, 0, 0);
414-
IM_ASSERT(event != nullptr);
415-
416-
ID3D12CommandAllocator* cmdAlloc = nullptr;
417-
hr = bd->pd3dDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&cmdAlloc));
418-
IM_ASSERT(SUCCEEDED(hr));
419-
420-
ID3D12GraphicsCommandList* cmdList = nullptr;
421-
hr = bd->pd3dDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, cmdAlloc, nullptr, IID_PPV_ARGS(&cmdList));
422-
IM_ASSERT(SUCCEEDED(hr));
423-
424-
cmdList->CopyTextureRegion(&dstLocation, 0, 0, 0, &srcLocation, nullptr);
425-
cmdList->ResourceBarrier(1, &barrier);
504+
{
505+
D3D12_RESOURCE_BARRIER barrier = {};
506+
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
507+
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
508+
barrier.Transition.pResource = backend_tex->pTextureResource;
509+
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
510+
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
511+
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
512+
cmdList->ResourceBarrier(1, &barrier);
513+
}
426514

427515
hr = cmdList->Close();
428516
IM_ASSERT(SUCCEEDED(hr));
@@ -432,6 +520,10 @@ static void ImGui_ImplDX12_CreateFontsTexture()
432520
hr = cmdQueue->Signal(fence, 1);
433521
IM_ASSERT(SUCCEEDED(hr));
434522

523+
// FIXME-OPT: Suboptimal?
524+
// - To remove this may need to create NumFramesInFlight x ImGui_ImplDX12_FrameContext in backend data (mimick docking version)
525+
// - Store per-frame in flight: upload buffer?
526+
// - Where do cmdList and cmdAlloc fit?
435527
fence->SetEventOnCompletion(1, event);
436528
::WaitForSingleObject(event, INFINITE);
437529

@@ -440,22 +532,11 @@ static void ImGui_ImplDX12_CreateFontsTexture()
440532
::CloseHandle(event);
441533
fence->Release();
442534
uploadBuffer->Release();
443-
444-
// Create texture view
445-
D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc;
446-
ZeroMemory(&srvDesc, sizeof(srvDesc));
447-
srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
448-
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
449-
srvDesc.Texture2D.MipLevels = desc.MipLevels;
450-
srvDesc.Texture2D.MostDetailedMip = 0;
451-
srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
452-
bd->pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, font_tex->hFontSrvCpuDescHandle);
453-
SafeRelease(font_tex->pTextureResource);
454-
font_tex->pTextureResource = pTexture;
535+
tex->SetStatus(ImTextureStatus_OK);
455536
}
456537

457-
// Store our identifier
458-
io.Fonts->SetTexID((ImTextureID)font_tex->hFontSrvGpuDescHandle.ptr);
538+
if (tex->Status == ImTextureStatus_WantDestroy && tex->UnusedFrames >= (int)bd->numFramesInFlight)
539+
ImGui_ImplDX12_DestroyTexture(tex);
459540
}
460541

461542
bool ImGui_ImplDX12_CreateDeviceObjects()
@@ -687,8 +768,6 @@ bool ImGui_ImplDX12_CreateDeviceObjects()
687768
if (result_pipeline_state != S_OK)
688769
return false;
689770

690-
ImGui_ImplDX12_CreateFontsTexture();
691-
692771
return true;
693772
}
694773

@@ -704,12 +783,10 @@ void ImGui_ImplDX12_InvalidateDeviceObjects()
704783
SafeRelease(bd->pRootSignature);
705784
SafeRelease(bd->pPipelineState);
706785

707-
// Free SRV descriptor used by texture
708-
ImGuiIO& io = ImGui::GetIO();
709-
ImGui_ImplDX12_Texture* font_tex = &bd->FontTexture;
710-
bd->InitInfo.SrvDescriptorFreeFn(&bd->InitInfo, font_tex->hFontSrvCpuDescHandle, font_tex->hFontSrvGpuDescHandle);
711-
SafeRelease(font_tex->pTextureResource);
712-
io.Fonts->SetTexID(0); // We copied bd->hFontSrvGpuDescHandle to io.Fonts->TexID so let's clear that as well.
786+
// Destroy all textures
787+
for (ImTextureData* tex : ImGui::GetPlatformIO().Textures)
788+
if (tex->RefCount == 1)
789+
ImGui_ImplDX12_DestroyTexture(tex);
713790

714791
for (UINT i = 0; i < bd->numFramesInFlight; i++)
715792
{
@@ -741,6 +818,16 @@ bool ImGui_ImplDX12_Init(ImGui_ImplDX12_InitInfo* init_info)
741818
io.BackendRendererUserData = (void*)bd;
742819
io.BackendRendererName = "imgui_impl_dx12";
743820
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
821+
io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render.
822+
823+
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
824+
ImGui_ImplDX12_InitPlatformInterface();
825+
826+
// Create a dummy ImGui_ImplDX12_ViewportData holder for the main viewport,
827+
// Since this is created and managed by the application, we will only use the ->Resources[] fields.
828+
ImGuiViewport* main_viewport = ImGui::GetMainViewport();
829+
main_viewport->RendererUserData = IM_NEW(ImGui_ImplDX12_ViewportData)(bd->numFramesInFlight);
830+
>>>>>>> dda12fbd9a (Backends: DirectX12: added ImGuiBackendFlags_RendererHasTextures support.)
744831

745832
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
746833
if (init_info->SrvDescriptorAllocFn == nullptr)
@@ -763,10 +850,7 @@ bool ImGui_ImplDX12_Init(ImGui_ImplDX12_InitInfo* init_info)
763850
};
764851
}
765852
#endif
766-
767-
// Allocate 1 SRV descriptor for the font texture
768853
IM_ASSERT(init_info->SrvDescriptorAllocFn != nullptr && init_info->SrvDescriptorFreeFn != nullptr);
769-
init_info->SrvDescriptorAllocFn(&bd->InitInfo, &bd->FontTexture.hFontSrvCpuDescHandle, &bd->FontTexture.hFontSrvGpuDescHandle);
770854

771855
// Create buffers with a default size (they will later be grown as needed)
772856
bd->frameIndex = UINT_MAX;
@@ -806,6 +890,9 @@ bool ImGui_ImplDX12_Init(ID3D12Device* device, int num_frames_in_flight, DXGI_FO
806890
bool ret = ImGui_ImplDX12_Init(&init_info);
807891
ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
808892
bd->commandQueueOwned = true;
893+
ImGuiIO& io = ImGui::GetIO();
894+
io.BackendFlags &= ~ImGuiBackendFlags_RendererHasTextures; // Using legacy ImGui_ImplDX12_Init() call with 1 SRV descriptor we cannot support multiple textures.
895+
809896
return ret;
810897
}
811898
#endif
@@ -822,7 +909,7 @@ void ImGui_ImplDX12_Shutdown()
822909

823910
io.BackendRendererName = nullptr;
824911
io.BackendRendererUserData = nullptr;
825-
io.BackendFlags &= ~ImGuiBackendFlags_RendererHasVtxOffset;
912+
io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures);
826913
IM_DELETE(bd);
827914
}
828915

0 commit comments

Comments
 (0)