@ -33,6 +33,11 @@
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2023-11-10: *BREAKING CHANGE*: Removed parameter from ImGui_ImplVulkan_CreateFontsTexture(): backend now creates its own command-buffer to upload fonts.
// *BREAKING CHANGE*: Removed ImGui_ImplVulkan_DestroyFontUploadObjects() which is now unecessary as we create and destroy those objects in the backend.
// ImGui_ImplVulkan_CreateFontsTexture() is automatically called by NewFrame() the first time.
// You can call ImGui_ImplVulkan_CreateFontsTexture() again to recreate the font atlas texture.
// Added ImGui_ImplVulkan_DestroyFontsTexture() but you probably never need to call this.
// 2023-07-04: Vulkan: Added optional support for VK_KHR_dynamic_rendering. User needs to set init_info->UseDynamicRendering = true and init_info->ColorAttachmentFormat.
// 2023-01-02: Vulkan: Fixed sampler passed to ImGui_ImplVulkan_AddTexture() not being honored + removed a bunch of duplicate code.
// 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11.
@ -120,8 +125,8 @@ struct ImGui_ImplVulkan_Data
VkImage FontImage ;
VkImageView FontView ;
VkDescriptorSet FontDescriptorSet ;
VkDeviceMemory UploadBufferMemory ;
VkBuffer Uploa dBuffer ;
VkCommandPool FontCommandPool ;
VkCommandBuffer FontComman dBuffer ;
// Render buffers for main window
ImGui_ImplVulkanH_WindowRenderBuffers MainWindowRenderBuffers ;
@ -587,11 +592,12 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm
vkCmdSetScissor ( command_buffer , 0 , 1 , & scissor ) ;
}
bool ImGui_ImplVulkan_CreateFontsTexture ( VkCommandBuffer command_buffer )
bool ImGui_ImplVulkan_CreateFontsTexture ( )
{
ImGuiIO & io = ImGui : : GetIO ( ) ;
ImGui_ImplVulkan_Data * bd = ImGui_ImplVulkan_GetBackendData ( ) ;
ImGui_ImplVulkan_InitInfo * v = & bd - > VulkanInitInfo ;
VkResult err ;
// Destroy existing texture (if any)
if ( bd - > FontView | | bd - > FontImage | | bd - > FontMemory | | bd - > FontDescriptorSet )
@ -600,13 +606,41 @@ bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer)
ImGui_ImplVulkan_DestroyFontsTexture ( ) ;
}
// Create command pool/buffer
if ( bd - > FontCommandPool = = VK_NULL_HANDLE )
{
VkCommandPoolCreateInfo info = { } ;
info . sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO ;
info . flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT ;
info . queueFamilyIndex = v - > QueueFamily ;
vkCreateCommandPool ( v - > Device , & info , nullptr , & bd - > FontCommandPool ) ;
}
if ( bd - > FontCommandBuffer = = VK_NULL_HANDLE )
{
VkCommandBufferAllocateInfo info = { } ;
info . sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO ;
info . commandPool = bd - > FontCommandPool ;
info . commandBufferCount = 1 ;
err = vkAllocateCommandBuffers ( v - > Device , & info , & bd - > FontCommandBuffer ) ;
check_vk_result ( err ) ;
}
// Start command buffer
{
err = vkResetCommandPool ( v - > Device , bd - > FontCommandPool , 0 ) ;
check_vk_result ( err ) ;
VkCommandBufferBeginInfo begin_info = { } ;
begin_info . sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO ;
begin_info . flags | = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT ;
err = vkBeginCommandBuffer ( bd - > FontCommandBuffer , & begin_info ) ;
check_vk_result ( err ) ;
}
unsigned char * pixels ;
int width , height ;
io . Fonts - > GetTexDataAsRGBA32 ( & pixels , & width , & height ) ;
size_t upload_size = width * height * 4 * sizeof ( char ) ;
VkResult err ;
// Create the Image:
{
VkImageCreateInfo info = { } ;
@ -655,40 +689,42 @@ bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer)
bd - > FontDescriptorSet = ( VkDescriptorSet ) ImGui_ImplVulkan_AddTexture ( bd - > FontSampler , bd - > FontView , VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL ) ;
// Create the Upload Buffer:
VkDeviceMemory upload_buffer_memory ;
VkBuffer upload_buffer ;
{
VkBufferCreateInfo buffer_info = { } ;
buffer_info . sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO ;
buffer_info . size = upload_size ;
buffer_info . usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT ;
buffer_info . sharingMode = VK_SHARING_MODE_EXCLUSIVE ;
err = vkCreateBuffer ( v - > Device , & buffer_info , v - > Allocator , & bd - > UploadB uffer) ;
err = vkCreateBuffer ( v - > Device , & buffer_info , v - > Allocator , & upload_b uffer) ;
check_vk_result ( err ) ;
VkMemoryRequirements req ;
vkGetBufferMemoryRequirements ( v - > Device , bd - > UploadB uffer, & req ) ;
vkGetBufferMemoryRequirements ( v - > Device , upload_b uffer, & req ) ;
bd - > BufferMemoryAlignment = ( bd - > BufferMemoryAlignment > req . alignment ) ? bd - > BufferMemoryAlignment : req . alignment ;
VkMemoryAllocateInfo alloc_info = { } ;
alloc_info . sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO ;
alloc_info . allocationSize = req . size ;
alloc_info . memoryTypeIndex = ImGui_ImplVulkan_MemoryType ( VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT , req . memoryTypeBits ) ;
err = vkAllocateMemory ( v - > Device , & alloc_info , v - > Allocator , & bd - > UploadBufferM emory) ;
err = vkAllocateMemory ( v - > Device , & alloc_info , v - > Allocator , & upload_buffer_m emory) ;
check_vk_result ( err ) ;
err = vkBindBufferMemory ( v - > Device , bd - > UploadBuffer , bd - > UploadBufferM emory, 0 ) ;
err = vkBindBufferMemory ( v - > Device , upload_buffer , upload_buffer_m emory, 0 ) ;
check_vk_result ( err ) ;
}
// Upload to Buffer:
{
char * map = nullptr ;
err = vkMapMemory ( v - > Device , bd - > UploadBufferM emory, 0 , upload_size , 0 , ( void * * ) ( & map ) ) ;
err = vkMapMemory ( v - > Device , upload_buffer_m emory, 0 , upload_size , 0 , ( void * * ) ( & map ) ) ;
check_vk_result ( err ) ;
memcpy ( map , pixels , upload_size ) ;
VkMappedMemoryRange range [ 1 ] = { } ;
range [ 0 ] . sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE ;
range [ 0 ] . memory = bd - > UploadBufferM emory;
range [ 0 ] . memory = upload_buffer_m emory;
range [ 0 ] . size = upload_size ;
err = vkFlushMappedMemoryRanges ( v - > Device , 1 , range ) ;
check_vk_result ( err ) ;
vkUnmapMemory ( v - > Device , bd - > UploadBufferM emory) ;
vkUnmapMemory ( v - > Device , upload_buffer_m emory) ;
}
// Copy to Image:
@ -704,7 +740,7 @@ bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer)
copy_barrier [ 0 ] . subresourceRange . aspectMask = VK_IMAGE_ASPECT_COLOR_BIT ;
copy_barrier [ 0 ] . subresourceRange . levelCount = 1 ;
copy_barrier [ 0 ] . subresourceRange . layerCount = 1 ;
vkCmdPipelineBarrier ( command_b uffer, VK_PIPELINE_STAGE_HOST_BIT , VK_PIPELINE_STAGE_TRANSFER_BIT , 0 , 0 , nullptr , 0 , nullptr , 1 , copy_barrier ) ;
vkCmdPipelineBarrier ( bd - > FontCommandB uffer, VK_PIPELINE_STAGE_HOST_BIT , VK_PIPELINE_STAGE_TRANSFER_BIT , 0 , 0 , nullptr , 0 , nullptr , 1 , copy_barrier ) ;
VkBufferImageCopy region = { } ;
region . imageSubresource . aspectMask = VK_IMAGE_ASPECT_COLOR_BIT ;
@ -712,7 +748,7 @@ bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer)
region . imageExtent . width = width ;
region . imageExtent . height = height ;
region . imageExtent . depth = 1 ;
vkCmdCopyBufferToImage ( command_buffer , bd - > UploadB uffer, bd - > FontImage , VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL , 1 , & region ) ;
vkCmdCopyBufferToImage ( bd - > FontCommandBuffer , upload_b uffer, bd - > FontImage , VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL , 1 , & region ) ;
VkImageMemoryBarrier use_barrier [ 1 ] = { } ;
use_barrier [ 0 ] . sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER ;
@ -726,15 +762,32 @@ bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer)
use_barrier [ 0 ] . subresourceRange . aspectMask = VK_IMAGE_ASPECT_COLOR_BIT ;
use_barrier [ 0 ] . subresourceRange . levelCount = 1 ;
use_barrier [ 0 ] . subresourceRange . layerCount = 1 ;
vkCmdPipelineBarrier ( command_b uffer, VK_PIPELINE_STAGE_TRANSFER_BIT , VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT , 0 , 0 , nullptr , 0 , nullptr , 1 , use_barrier ) ;
vkCmdPipelineBarrier ( bd - > FontCommandB uffer, VK_PIPELINE_STAGE_TRANSFER_BIT , VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT , 0 , 0 , nullptr , 0 , nullptr , 1 , use_barrier ) ;
}
// Store our identifier
io . Fonts - > SetTexID ( ( ImTextureID ) bd - > FontDescriptorSet ) ;
// End command buffer
VkSubmitInfo end_info = { } ;
end_info . sType = VK_STRUCTURE_TYPE_SUBMIT_INFO ;
end_info . commandBufferCount = 1 ;
end_info . pCommandBuffers = & bd - > FontCommandBuffer ;
err = vkEndCommandBuffer ( bd - > FontCommandBuffer ) ;
check_vk_result ( err ) ;
err = vkQueueSubmit ( v - > Queue , 1 , & end_info , VK_NULL_HANDLE ) ;
check_vk_result ( err ) ;
err = vkDeviceWaitIdle ( v - > Device ) ;
check_vk_result ( err ) ;
vkDestroyBuffer ( v - > Device , upload_buffer , v - > Allocator ) ;
vkFreeMemory ( v - > Device , upload_buffer_memory , v - > Allocator ) ;
return true ;
}
// You probably never need to call this, as it is called by ImGui_ImplVulkan_CreateFontsTexture() and ImGui_ImplVulkan_Shutdown().
void ImGui_ImplVulkan_DestroyFontsTexture ( )
{
ImGuiIO & io = ImGui : : GetIO ( ) ;
@ -751,7 +804,6 @@ void ImGui_ImplVulkan_DestroyFontsTexture()
if ( bd - > FontView ) { vkDestroyImageView ( v - > Device , bd - > FontView , v - > Allocator ) ; bd - > FontView = VK_NULL_HANDLE ; }
if ( bd - > FontImage ) { vkDestroyImage ( v - > Device , bd - > FontImage , v - > Allocator ) ; bd - > FontImage = VK_NULL_HANDLE ; }
if ( bd - > FontMemory ) { vkFreeMemory ( v - > Device , bd - > FontMemory , v - > Allocator ) ; bd - > FontMemory = VK_NULL_HANDLE ; }
ImGui_ImplVulkan_DestroyFontUploadObjects ( ) ;
}
static void ImGui_ImplVulkan_CreateShaderModules ( VkDevice device , const VkAllocationCallbacks * allocator )
@ -956,30 +1008,14 @@ bool ImGui_ImplVulkan_CreateDeviceObjects()
return true ;
}
void ImGui_ImplVulkan_DestroyFontUploadObjects ( )
{
ImGui_ImplVulkan_Data * bd = ImGui_ImplVulkan_GetBackendData ( ) ;
ImGui_ImplVulkan_InitInfo * v = & bd - > VulkanInitInfo ;
if ( bd - > UploadBuffer )
{
vkDestroyBuffer ( v - > Device , bd - > UploadBuffer , v - > Allocator ) ;
bd - > UploadBuffer = VK_NULL_HANDLE ;
}
if ( bd - > UploadBufferMemory )
{
vkFreeMemory ( v - > Device , bd - > UploadBufferMemory , v - > Allocator ) ;
bd - > UploadBufferMemory = VK_NULL_HANDLE ;
}
}
void ImGui_ImplVulkan_DestroyDeviceObjects ( )
{
ImGui_ImplVulkan_Data * bd = ImGui_ImplVulkan_GetBackendData ( ) ;
ImGui_ImplVulkan_InitInfo * v = & bd - > VulkanInitInfo ;
ImGui_ImplVulkanH_DestroyWindowRenderBuffers ( v - > Device , & bd - > MainWindowRenderBuffers , v - > Allocator ) ;
ImGui_ImplVulkan_DestroyFontUploadObjects ( ) ;
ImGui_ImplVulkan_DestroyFontsTexture ( ) ;
if ( bd - > FontCommandPool ) { vkDestroyCommandPool ( v - > Device , bd - > FontCommandPool , v - > Allocator ) ; bd - > FontCommandPool = VK_NULL_HANDLE ; }
if ( bd - > ShaderModuleVert ) { vkDestroyShaderModule ( v - > Device , bd - > ShaderModuleVert , v - > Allocator ) ; bd - > ShaderModuleVert = VK_NULL_HANDLE ; }
if ( bd - > ShaderModuleFrag ) { vkDestroyShaderModule ( v - > Device , bd - > ShaderModuleFrag , v - > Allocator ) ; bd - > ShaderModuleFrag = VK_NULL_HANDLE ; }
if ( bd - > FontSampler ) { vkDestroySampler ( v - > Device , bd - > FontSampler , v - > Allocator ) ; bd - > FontSampler = VK_NULL_HANDLE ; }
@ -1079,7 +1115,9 @@ void ImGui_ImplVulkan_NewFrame()
{
ImGui_ImplVulkan_Data * bd = ImGui_ImplVulkan_GetBackendData ( ) ;
IM_ASSERT ( bd ! = nullptr & & " Did you call ImGui_ImplVulkan_Init()? " ) ;
IM_UNUSED ( bd ) ;
if ( ! bd - > FontDescriptorSet )
ImGui_ImplVulkan_CreateFontsTexture ( ) ;
}
void ImGui_ImplVulkan_SetMinImageCount ( uint32_t min_image_count )