Skip to content

Commit 8478cc6

Browse files
committed
[Vulkan] Add internal descriptor set management
* Pool allocates linearly and resets each frame. * If pool limit is reached a new pool will be allocated at double the size up to 1024 then it increments in steps of 1024 * Add usage of SetTextureFn, otherwise assumes TextureId is a VkImageView * Users of SetTextureFn can set textures using ImGui_ImplVulkan_SetTexture
1 parent 1a7f9ff commit 8478cc6

File tree

2 files changed

+111
-31
lines changed

2 files changed

+111
-31
lines changed

examples/imgui_impl_vulkan.cpp

+110-30
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,14 @@ static VkDeviceSize g_BufferMemoryAlignment = 256;
7676
static VkPipelineCreateFlags g_PipelineCreateFlags = 0x00;
7777
static VkDescriptorSetLayout g_DescriptorSetLayout = VK_NULL_HANDLE;
7878
static VkPipelineLayout g_PipelineLayout = VK_NULL_HANDLE;
79-
static VkDescriptorSet g_DescriptorSet = VK_NULL_HANDLE;
8079
static VkPipeline g_Pipeline = VK_NULL_HANDLE;
80+
static ImTextureID g_hLastTextureSet = NULL;
81+
82+
// Default Descriptor management
83+
static uint32_t g_DescriptorPoolSize = 32; // will create and double on first frame
84+
static uint32_t g_DescriptorsAllocated = 32;
85+
static VkDescriptorPool g_DescriptorPool = VK_NULL_HANDLE;
86+
ImVector<VkDescriptorPool> g_DescriptorPoolToDelete;
8187

8288
// Font data
8389
static VkSampler g_FontSampler = VK_NULL_HANDLE;
@@ -269,8 +275,6 @@ static void ImGui_ImplVulkan_SetupRenderState(ImDrawData* draw_data, VkCommandBu
269275
// Bind pipeline and descriptor sets:
270276
{
271277
vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, g_Pipeline);
272-
VkDescriptorSet desc_set[1] = { g_DescriptorSet };
273-
vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, g_PipelineLayout, 0, 1, desc_set, 0, NULL);
274278
}
275279

276280
// Bind Vertex And Index Buffer:
@@ -305,6 +309,8 @@ static void ImGui_ImplVulkan_SetupRenderState(ImDrawData* draw_data, VkCommandBu
305309
vkCmdPushConstants(command_buffer, g_PipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, sizeof(float) * 0, sizeof(float) * 2, scale);
306310
vkCmdPushConstants(command_buffer, g_PipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, sizeof(float) * 2, sizeof(float) * 2, translate);
307311
}
312+
313+
g_hLastTextureSet = NULL;
308314
}
309315

310316
// Render function
@@ -317,6 +323,7 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm
317323
if (fb_width <= 0 || fb_height <= 0 || draw_data->TotalVtxCount == 0)
318324
return;
319325

326+
ImGuiIO& io = ImGui::GetIO();
320327
ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
321328

322329
// Allocate array to store enough vertex/index buffers
@@ -371,6 +378,25 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm
371378
vkUnmapMemory(v->Device, rb->IndexBufferMemory);
372379
}
373380

381+
// Reset descriptor pool once per draw
382+
if (g_DescriptorPool)
383+
{
384+
err = vkResetDescriptorPool(v->Device, g_DescriptorPool, 0);
385+
check_vk_result(err);
386+
387+
g_DescriptorsAllocated = 0;
388+
389+
// destroy old pools
390+
if (!g_DescriptorPoolToDelete.empty())
391+
{
392+
for (int i = 0; i < g_DescriptorPoolToDelete.size(); i++)
393+
{
394+
vkDestroyDescriptorPool(v->Device, g_DescriptorPoolToDelete[i], v->Allocator);
395+
}
396+
g_DescriptorPoolToDelete.resize(0);
397+
}
398+
}
399+
374400
// Setup desired Vulkan state
375401
ImGui_ImplVulkan_SetupRenderState(draw_data, command_buffer, rb, fb_width, fb_height);
376402

@@ -399,6 +425,16 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm
399425
}
400426
else
401427
{
428+
if (g_hLastTextureSet != pcmd->TextureId)
429+
{
430+
g_hLastTextureSet = pcmd->TextureId;
431+
if (io.SetTextureFn)
432+
io.SetTextureFn(pcmd->TextureId);
433+
else
434+
{
435+
ImGui_ImplVulkan_SetTexture((VkImageView)pcmd->TextureId, command_buffer);
436+
}
437+
}
402438
// Project scissor/clipping rectangles into framebuffer space
403439
ImVec4 clip_rect;
404440
clip_rect.x = (pcmd->ClipRect.x - clip_off.x) * clip_scale.x;
@@ -432,6 +468,66 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm
432468
}
433469
}
434470

471+
void ImGui_ImplVulkan_SetTexture(VkImageView image_view, VkCommandBuffer command_buffer)
472+
{
473+
ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
474+
475+
// Out of descriptors, add a new bigger pool and mark the old one to be freed next frame
476+
if (g_DescriptorsAllocated == g_DescriptorPoolSize)
477+
{
478+
if (g_DescriptorsAllocated < 1024)
479+
g_DescriptorPoolSize *= 2;
480+
else
481+
g_DescriptorPoolSize += 1024;
482+
483+
if (g_DescriptorPool)
484+
g_DescriptorPoolToDelete.push_back(g_DescriptorPool);
485+
486+
g_DescriptorsAllocated = 0;
487+
488+
VkDescriptorPoolSize poolSizes[1] =
489+
{
490+
{ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, g_DescriptorPoolSize },
491+
};
492+
493+
VkDescriptorPoolCreateInfo descriptor_pool_info = {};
494+
descriptor_pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
495+
descriptor_pool_info.poolSizeCount = 1;
496+
descriptor_pool_info.pPoolSizes = poolSizes;
497+
descriptor_pool_info.maxSets = g_DescriptorPoolSize;
498+
499+
VkResult err = vkCreateDescriptorPool(v->Device, &descriptor_pool_info, v->Allocator, &g_DescriptorPool);
500+
check_vk_result(err);
501+
}
502+
503+
VkDescriptorSet desc_set;
504+
505+
// Create and update new set
506+
VkDescriptorSetAllocateInfo allocate_info = {};
507+
allocate_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
508+
allocate_info.descriptorPool = g_DescriptorPool;
509+
allocate_info.descriptorSetCount = 1;
510+
allocate_info.pSetLayouts = &g_DescriptorSetLayout;
511+
VkResult err = vkAllocateDescriptorSets(v->Device, &allocate_info, &desc_set);
512+
check_vk_result(err);
513+
514+
VkDescriptorImageInfo desc_image = {};
515+
desc_image.imageView = image_view;
516+
desc_image.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
517+
518+
VkWriteDescriptorSet write_desc[1] = {};
519+
write_desc[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
520+
write_desc[0].dstSet = desc_set;
521+
write_desc[0].descriptorCount = 1;
522+
write_desc[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
523+
write_desc[0].pImageInfo = &desc_image;
524+
vkUpdateDescriptorSets(v->Device, 1, write_desc, 0, NULL);
525+
526+
vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, g_PipelineLayout, 0, 1, &desc_set, 0, NULL);
527+
528+
++g_DescriptorsAllocated;
529+
}
530+
435531
bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer)
436532
{
437533
ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
@@ -488,20 +584,6 @@ bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer)
488584
check_vk_result(err);
489585
}
490586

491-
// Update the Descriptor Set:
492-
{
493-
VkDescriptorImageInfo desc_image[1] = {};
494-
desc_image[0].sampler = g_FontSampler;
495-
desc_image[0].imageView = g_FontView;
496-
desc_image[0].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
497-
VkWriteDescriptorSet write_desc[1] = {};
498-
write_desc[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
499-
write_desc[0].dstSet = g_DescriptorSet;
500-
write_desc[0].descriptorCount = 1;
501-
write_desc[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
502-
write_desc[0].pImageInfo = desc_image;
503-
vkUpdateDescriptorSets(v->Device, 1, write_desc, 0, NULL);
504-
}
505587

506588
// Create the Upload Buffer:
507589
{
@@ -578,8 +660,10 @@ bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer)
578660
vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, use_barrier);
579661
}
580662

663+
// Update the descriptor set
664+
581665
// Store our identifier
582-
io.Fonts->TexID = (ImTextureID)(intptr_t)g_FontImage;
666+
io.Fonts->TexID = (ImTextureID)(intptr_t)g_FontView;
583667

584668
return true;
585669
}
@@ -640,17 +724,6 @@ bool ImGui_ImplVulkan_CreateDeviceObjects()
640724
check_vk_result(err);
641725
}
642726

643-
// Create Descriptor Set:
644-
{
645-
VkDescriptorSetAllocateInfo alloc_info = {};
646-
alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
647-
alloc_info.descriptorPool = v->DescriptorPool;
648-
alloc_info.descriptorSetCount = 1;
649-
alloc_info.pSetLayouts = &g_DescriptorSetLayout;
650-
err = vkAllocateDescriptorSets(v->Device, &alloc_info, &g_DescriptorSet);
651-
check_vk_result(err);
652-
}
653-
654727
if (!g_PipelineLayout)
655728
{
656729
// Constants: we are using 'vec2 offset' and 'vec2 scale' instead of a full 3d projection matrix
@@ -796,10 +869,18 @@ void ImGui_ImplVulkan_DestroyDeviceObjects()
796869
ImGui_ImplVulkanH_DestroyWindowRenderBuffers(v->Device, &g_MainWindowRenderBuffers, v->Allocator);
797870
ImGui_ImplVulkan_DestroyFontUploadObjects();
798871

872+
for (int i = 0; i < g_DescriptorPoolToDelete.size(); i++)
873+
{
874+
vkDestroyDescriptorPool(v->Device, g_DescriptorPoolToDelete[i], v->Allocator);
875+
}
876+
g_DescriptorPoolToDelete.clear();
877+
g_DescriptorPoolSize = g_DescriptorsAllocated = 32;
878+
799879
if (g_FontView) { vkDestroyImageView(v->Device, g_FontView, v->Allocator); g_FontView = VK_NULL_HANDLE; }
800880
if (g_FontImage) { vkDestroyImage(v->Device, g_FontImage, v->Allocator); g_FontImage = VK_NULL_HANDLE; }
801881
if (g_FontMemory) { vkFreeMemory(v->Device, g_FontMemory, v->Allocator); g_FontMemory = VK_NULL_HANDLE; }
802882
if (g_FontSampler) { vkDestroySampler(v->Device, g_FontSampler, v->Allocator); g_FontSampler = VK_NULL_HANDLE; }
883+
if (g_DescriptorPool) { vkDestroyDescriptorPool(v->Device, g_DescriptorPool, v->Allocator); g_DescriptorPool = VK_NULL_HANDLE; }
803884
if (g_DescriptorSetLayout) { vkDestroyDescriptorSetLayout(v->Device, g_DescriptorSetLayout, v->Allocator); g_DescriptorSetLayout = VK_NULL_HANDLE; }
804885
if (g_PipelineLayout) { vkDestroyPipelineLayout(v->Device, g_PipelineLayout, v->Allocator); g_PipelineLayout = VK_NULL_HANDLE; }
805886
if (g_Pipeline) { vkDestroyPipeline(v->Device, g_Pipeline, v->Allocator); g_Pipeline = VK_NULL_HANDLE; }
@@ -816,7 +897,6 @@ bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info, VkRenderPass rend
816897
IM_ASSERT(info->PhysicalDevice != VK_NULL_HANDLE);
817898
IM_ASSERT(info->Device != VK_NULL_HANDLE);
818899
IM_ASSERT(info->Queue != VK_NULL_HANDLE);
819-
IM_ASSERT(info->DescriptorPool != VK_NULL_HANDLE);
820900
IM_ASSERT(info->MinImageCount >= 2);
821901
IM_ASSERT(info->ImageCount >= info->MinImageCount);
822902
IM_ASSERT(render_pass != VK_NULL_HANDLE);

examples/imgui_impl_vulkan.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ struct ImGui_ImplVulkan_InitInfo
3434
uint32_t QueueFamily;
3535
VkQueue Queue;
3636
VkPipelineCache PipelineCache;
37-
VkDescriptorPool DescriptorPool;
3837
uint32_t MinImageCount; // >= 2
3938
uint32_t ImageCount; // >= MinImageCount
4039
VkSampleCountFlagBits MSAASamples; // >= VK_SAMPLE_COUNT_1_BIT
@@ -47,6 +46,7 @@ IMGUI_IMPL_API bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info, V
4746
IMGUI_IMPL_API void ImGui_ImplVulkan_Shutdown();
4847
IMGUI_IMPL_API void ImGui_ImplVulkan_NewFrame();
4948
IMGUI_IMPL_API void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer command_buffer);
49+
IMGUI_IMPL_API void ImGui_ImplVulkan_SetTexture(VkImageView image_view, VkCommandBuffer command_buffer);
5050
IMGUI_IMPL_API bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer);
5151
IMGUI_IMPL_API void ImGui_ImplVulkan_DestroyFontUploadObjects();
5252
IMGUI_IMPL_API void ImGui_ImplVulkan_SetMinImageCount(uint32_t min_image_count); // To override MinImageCount after initialization (e.g. if swap chain is recreated)

0 commit comments

Comments
 (0)