|
@@ -35,6 +35,11 @@
|
|
|
// CHANGELOG
|
|
|
// (minor and older changes stripped away, please see git history for details)
|
|
|
// 2023-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
|
|
|
+// 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.
|
|
@@ -134,8 +139,8 @@ struct ImGui_ImplVulkan_Data
|
|
|
VkImage FontImage;
|
|
|
VkImageView FontView;
|
|
|
VkDescriptorSet FontDescriptorSet;
|
|
|
- VkDeviceMemory UploadBufferMemory;
|
|
|
- VkBuffer UploadBuffer;
|
|
|
+ VkCommandPool FontCommandPool;
|
|
|
+ VkCommandBuffer FontCommandBuffer;
|
|
|
|
|
|
// Render buffers for main window
|
|
|
ImGui_ImplVulkanH_WindowRenderBuffers MainWindowRenderBuffers;
|
|
@@ -619,19 +624,55 @@ 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)
|
|
|
+ {
|
|
|
+ vkQueueWaitIdle(v->Queue);
|
|
|
+ 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 = {};
|
|
@@ -680,40 +721,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->UploadBuffer);
|
|
|
+ err = vkCreateBuffer(v->Device, &buffer_info, v->Allocator, &upload_buffer);
|
|
|
check_vk_result(err);
|
|
|
VkMemoryRequirements req;
|
|
|
- vkGetBufferMemoryRequirements(v->Device, bd->UploadBuffer, &req);
|
|
|
+ vkGetBufferMemoryRequirements(v->Device, upload_buffer, &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->UploadBufferMemory);
|
|
|
+ err = vkAllocateMemory(v->Device, &alloc_info, v->Allocator, &upload_buffer_memory);
|
|
|
check_vk_result(err);
|
|
|
- err = vkBindBufferMemory(v->Device, bd->UploadBuffer, bd->UploadBufferMemory, 0);
|
|
|
+ err = vkBindBufferMemory(v->Device, upload_buffer, upload_buffer_memory, 0);
|
|
|
check_vk_result(err);
|
|
|
}
|
|
|
|
|
|
// Upload to Buffer:
|
|
|
{
|
|
|
char* map = nullptr;
|
|
|
- err = vkMapMemory(v->Device, bd->UploadBufferMemory, 0, upload_size, 0, (void**)(&map));
|
|
|
+ err = vkMapMemory(v->Device, upload_buffer_memory, 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->UploadBufferMemory;
|
|
|
+ range[0].memory = upload_buffer_memory;
|
|
|
range[0].size = upload_size;
|
|
|
err = vkFlushMappedMemoryRanges(v->Device, 1, range);
|
|
|
check_vk_result(err);
|
|
|
- vkUnmapMemory(v->Device, bd->UploadBufferMemory);
|
|
|
+ vkUnmapMemory(v->Device, upload_buffer_memory);
|
|
|
}
|
|
|
|
|
|
// Copy to Image:
|
|
@@ -729,7 +772,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_buffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, copy_barrier);
|
|
|
+ vkCmdPipelineBarrier(bd->FontCommandBuffer, 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;
|
|
@@ -737,7 +780,7 @@ bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer)
|
|
|
region.imageExtent.width = width;
|
|
|
region.imageExtent.height = height;
|
|
|
region.imageExtent.depth = 1;
|
|
|
- vkCmdCopyBufferToImage(command_buffer, bd->UploadBuffer, bd->FontImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion);
|
|
|
+ vkCmdCopyBufferToImage(bd->FontCommandBuffer, upload_buffer, bd->FontImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion);
|
|
|
|
|
|
VkImageMemoryBarrier use_barrier[1] = {};
|
|
|
use_barrier[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
|
@@ -751,15 +794,50 @@ 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_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, use_barrier);
|
|
|
+ vkCmdPipelineBarrier(bd->FontCommandBuffer, 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();
|
|
|
+ ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
|
|
|
+ ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo;
|
|
|
+
|
|
|
+ if (bd->FontDescriptorSet)
|
|
|
+ {
|
|
|
+ ImGui_ImplVulkan_RemoveTexture(bd->FontDescriptorSet);
|
|
|
+ bd->FontDescriptorSet = VK_NULL_HANDLE;
|
|
|
+ io.Fonts->SetTexID(0);
|
|
|
+ }
|
|
|
+
|
|
|
+ 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; }
|
|
|
+}
|
|
|
+
|
|
|
static void ImGui_ImplVulkan_CreateShaderModules(VkDevice device, const VkAllocationCallbacks* allocator)
|
|
|
{
|
|
|
// Create the shader modules
|
|
@@ -807,15 +885,15 @@ static void ImGui_ImplVulkan_CreatePipeline(VkDevice device, const VkAllocationC
|
|
|
attribute_desc[0].location = 0;
|
|
|
attribute_desc[0].binding = binding_desc[0].binding;
|
|
|
attribute_desc[0].format = VK_FORMAT_R32G32_SFLOAT;
|
|
|
- attribute_desc[0].offset = IM_OFFSETOF(ImDrawVert, pos);
|
|
|
+ attribute_desc[0].offset = offsetof(ImDrawVert, pos);
|
|
|
attribute_desc[1].location = 1;
|
|
|
attribute_desc[1].binding = binding_desc[0].binding;
|
|
|
attribute_desc[1].format = VK_FORMAT_R32G32_SFLOAT;
|
|
|
- attribute_desc[1].offset = IM_OFFSETOF(ImDrawVert, uv);
|
|
|
+ attribute_desc[1].offset = offsetof(ImDrawVert, uv);
|
|
|
attribute_desc[2].location = 2;
|
|
|
attribute_desc[2].binding = binding_desc[0].binding;
|
|
|
attribute_desc[2].format = VK_FORMAT_R8G8B8A8_UNORM;
|
|
|
- attribute_desc[2].offset = IM_OFFSETOF(ImDrawVert, col);
|
|
|
+ attribute_desc[2].offset = offsetof(ImDrawVert, col);
|
|
|
|
|
|
VkPipelineVertexInputStateCreateInfo vertex_info = {};
|
|
|
vertex_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
|
|
@@ -962,34 +1040,16 @@ 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_DestroyAllViewportsRenderBuffers(v->Device, 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->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; }
|
|
|
if (bd->FontSampler) { vkDestroySampler(v->Device, bd->FontSampler, v->Allocator); bd->FontSampler = VK_NULL_HANDLE; }
|
|
|
if (bd->DescriptorSetLayout) { vkDestroyDescriptorSetLayout(v->Device, bd->DescriptorSetLayout, v->Allocator); bd->DescriptorSetLayout = VK_NULL_HANDLE; }
|
|
|
if (bd->PipelineLayout) { vkDestroyPipelineLayout(v->Device, bd->PipelineLayout, v->Allocator); bd->PipelineLayout = VK_NULL_HANDLE; }
|
|
@@ -1106,7 +1166,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)
|