Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ImGui_ImplVulkan_DestroyFontsTexture function #6327

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 38 additions & 3 deletions backends/imgui_impl_vulkan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ struct ImGui_ImplVulkan_Data
// Forward Declarations
bool ImGui_ImplVulkan_CreateDeviceObjects();
void ImGui_ImplVulkan_DestroyDeviceObjects();
void ImGui_ImplVulkan_DestroyFontObjects();
void ImGui_ImplVulkanH_DestroyFrame(VkDevice device, ImGui_ImplVulkanH_Frame* fd, const VkAllocationCallbacks* allocator);
void ImGui_ImplVulkanH_DestroyFrameSemaphores(VkDevice device, ImGui_ImplVulkanH_FrameSemaphores* fsd, const VkAllocationCallbacks* allocator);
void ImGui_ImplVulkanH_DestroyFrameRenderBuffers(VkDevice device, ImGui_ImplVulkanH_FrameRenderBuffers* buffers, const VkAllocationCallbacks* allocator);
Expand Down Expand Up @@ -581,6 +582,13 @@ bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer)
ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo;

// Check for existing font resources that we have to destroy
if (bd->FontView || bd->FontImage || bd->FontMemory || bd->FontDescriptorSet) {
// Wait to ensure that the font descriptor set is not used in any pending command buffers
vkQueueWaitIdle(v->Queue);
ImGui_ImplVulkan_DestroyFontsTexture();
}

unsigned char* pixels;
int width, height;
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
Expand Down Expand Up @@ -716,6 +724,23 @@ bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer)
return true;
}

// This function assumes that the caller has ensured that the font descriptor set is not
// referenced from an active command buffer.
void ImGui_ImplVulkan_DestroyFontsTexture()
{
ImGuiIO& io = ImGui::GetIO();
ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();

if (bd->FontDescriptorSet) {
ImGui_ImplVulkan_RemoveTexture(bd->FontDescriptorSet);
bd->FontDescriptorSet = VK_NULL_HANDLE;
}

ImGui_ImplVulkan_DestroyFontObjects();

io.Fonts->SetTexID(nullptr);
}

static void ImGui_ImplVulkan_CreateShaderModules(VkDevice device, const VkAllocationCallbacks* allocator)
{
// Create the shader modules
Expand Down Expand Up @@ -905,6 +930,7 @@ bool ImGui_ImplVulkan_CreateDeviceObjects()
return true;
}

// Destroys and clears the UploadBuffer and UploadBufferMemory
void ImGui_ImplVulkan_DestroyFontUploadObjects()
{
ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
Expand All @@ -921,18 +947,27 @@ void ImGui_ImplVulkan_DestroyFontUploadObjects()
}
}

// Destroys and clears the FontView, FontImage, and FontMemory (but not the sampler!)
void ImGui_ImplVulkan_DestroyFontObjects()
{
ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo;

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; }
}

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_DestroyFontObjects();

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; }
Expand Down
1 change: 1 addition & 0 deletions backends/imgui_impl_vulkan.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ IMGUI_IMPL_API void ImGui_ImplVulkan_Shutdown();
IMGUI_IMPL_API void ImGui_ImplVulkan_NewFrame();
IMGUI_IMPL_API void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer command_buffer, VkPipeline pipeline = VK_NULL_HANDLE);
IMGUI_IMPL_API bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer);
IMGUI_IMPL_API void ImGui_ImplVulkan_DestroyFontsTexture();
IMGUI_IMPL_API void ImGui_ImplVulkan_DestroyFontUploadObjects();
IMGUI_IMPL_API void ImGui_ImplVulkan_SetMinImageCount(uint32_t min_image_count); // To override MinImageCount after initialization (e.g. if swap chain is recreated)

Expand Down
45 changes: 45 additions & 0 deletions examples/example_sdl2_vulkan/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
cmake_minimum_required(VERSION 2.8)

project(imgui_example_sdl2_vulkan C CXX)

set(CMAKE_CXX_STANDARD 11)

find_package(Vulkan REQUIRED)
find_package(SDL2 REQUIRED)

set(IMGUI_DIR "${PROJECT_SOURCE_DIR}/../..")

add_executable(example_sdl2_vulkan
"${IMGUI_DIR}/imconfig.h"
"${IMGUI_DIR}/imgui.cpp"
"${IMGUI_DIR}/imgui.h"
"${IMGUI_DIR}/imgui_demo.cpp"
"${IMGUI_DIR}/imgui_draw.cpp"
"${IMGUI_DIR}/imgui_internal.h"
"${IMGUI_DIR}/imgui_tables.cpp"
"${IMGUI_DIR}/imgui_widgets.cpp"
"${IMGUI_DIR}/imstb_rectpack.h"
"${IMGUI_DIR}/imstb_textedit.h"
"${IMGUI_DIR}/imstb_truetype.h"

"${IMGUI_DIR}/backends/imgui_impl_sdl2.cpp"
"${IMGUI_DIR}/backends/imgui_impl_sdl2.h"
"${IMGUI_DIR}/backends/imgui_impl_vulkan.cpp"
"${IMGUI_DIR}/backends/imgui_impl_vulkan.h"

main.cpp)

target_include_directories(example_sdl2_vulkan
PRIVATE
${IMGUI_DIR}
"${IMGUI_DIR}/backends"

SYSTEM PRIVATE
${SDL2_INCLUDE_DIRS}
)

target_link_libraries(example_sdl2_vulkan
PRIVATE
Vulkan::Vulkan
${SDL2_LIBRARIES}
)
116 changes: 111 additions & 5 deletions examples/example_sdl2_vulkan/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,57 @@ static void check_vk_result(VkResult err)
abort();
}

typedef void (*CommandBufferCallback)(VkCommandBuffer);

// Creates a temporary command buffer, records commands using a callback, and waits for it to be executed
static void ExecuteImmediately(VkCommandPool command_pool, CommandBufferCallback callback)
{
VkResult result = {};

// Allocate a command buffer from the pool
VkCommandBufferAllocateInfo command_buffer_allocate_info = {};
command_buffer_allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
command_buffer_allocate_info.commandPool = command_pool;
command_buffer_allocate_info.commandBufferCount = 1;
command_buffer_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;

VkCommandBuffer command_buffer = VK_NULL_HANDLE;
result = vkAllocateCommandBuffers(g_Device, &command_buffer_allocate_info, &command_buffer);
check_vk_result(result);

// Begin the single use command buffer
{
VkCommandBufferBeginInfo command_buffer_begin_info = {};
command_buffer_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
command_buffer_begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;

result = vkBeginCommandBuffer(command_buffer, &command_buffer_begin_info);
check_vk_result(result);
}

// Invoke the user callback, and subsequently end the command buffer recording
callback(command_buffer);

result = vkEndCommandBuffer(command_buffer);
check_vk_result(result);

// Submit command buffer and wait for it to finish executing
{
VkSubmitInfo submit_info = {};
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submit_info.commandBufferCount = 1;
submit_info.pCommandBuffers = &command_buffer;

result = vkQueueSubmit(g_Queue, 1, &submit_info, VK_NULL_HANDLE);
check_vk_result(result);

result = vkQueueWaitIdle(g_Queue);
check_vk_result(result);
}

vkFreeCommandBuffers(g_Device, command_pool, 1, &command_buffer);
}

#ifdef IMGUI_VULKAN_DEBUG_REPORT
static VKAPI_ATTR VkBool32 VKAPI_CALL debug_report(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t location, int32_t messageCode, const char* pLayerPrefix, const char* pMessage, void* pUserData)
{
Expand Down Expand Up @@ -87,7 +138,8 @@ static VkPhysicalDevice SetupVulkan_SelectPhysicalDevice()
if (properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU)
return device;
}
return VK_NULL_HANDLE;

return gpus[0];
}

static void SetupVulkan(ImVector<const char*> instance_extensions)
Expand All @@ -96,8 +148,17 @@ static void SetupVulkan(ImVector<const char*> instance_extensions)

// Create Vulkan Instance
{
VkApplicationInfo application_info = {};
application_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
application_info.pApplicationName = "ImGui SDL2/Vulkan example";
application_info.applicationVersion = VK_MAKE_VERSION(0, 1, 0);
application_info.pEngineName = "None";
application_info.engineVersion = VK_MAKE_VERSION(0, 1, 0);
application_info.apiVersion = VK_API_VERSION_1_2;

VkInstanceCreateInfo create_info = {};
create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
create_info.pApplicationInfo = &application_info;

// Enumerate available extensions
uint32_t properties_count;
Expand Down Expand Up @@ -176,10 +237,10 @@ static void SetupVulkan(ImVector<const char*> instance_extensions)
vkEnumerateDeviceExtensionProperties(g_PhysicalDevice, nullptr, &properties_count, nullptr);
properties.resize(properties_count);
vkEnumerateDeviceExtensionProperties(g_PhysicalDevice, nullptr, &properties_count, properties.Data);
#ifdef VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME
if (IsExtensionAvailable(properties, VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME))
device_extensions.push_back(VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME);
#endif

const char* portability_subset_extension = "VK_KHR_portability_subset";
if (IsExtensionAvailable(properties, portability_subset_extension))
device_extensions.push_back(portability_subset_extension);

const float queue_priority[] = { 1.0f };
VkDeviceQueueCreateInfo queue_info[1] = {};
Expand Down Expand Up @@ -367,6 +428,37 @@ static void FramePresent(ImGui_ImplVulkanH_Window* wd)
wd->SemaphoreIndex = (wd->SemaphoreIndex + 1) % wd->ImageCount; // Now we can use the next set of semaphores
}

static void ReloadFonts()
{
// printf("Reloading fonts...\n");

ImGui_ImplVulkanH_Window* wd = &g_MainWindowData;
ImGuiIO& io = ImGui::GetIO();

io.Fonts->Clear();
io.Fonts->AddFontDefault();

// Uncomment the following line for proper font scaling, but the default font might end up too small on Retina screens
// io.FontGlobalScale = 1.0f / io.DisplayFramebufferScale.x;

io.Fonts->Build();

// It is actually not necessary to explicitly destroy the fonts texture before
// calling ImGui_ImplVulkan_CreateFontsTexture. But if you do, make sure to wait for the queue
// to finish executing commands that may reference the font descriptor set.
vkQueueWaitIdle(g_Queue);
ImGui_ImplVulkan_DestroyFontsTexture();

VkCommandPool command_pool = wd->Frames[wd->FrameIndex].CommandPool;
ExecuteImmediately(command_pool, [](VkCommandBuffer command_buffer) {
ImGui_ImplVulkan_CreateFontsTexture(command_buffer);
});

ImGui_ImplVulkan_DestroyFontUploadObjects();

ImGui::GetStyle().ScaleAllSizes(1.0f);
}

// Main code
int main(int, char**)
{
Expand Down Expand Up @@ -486,7 +578,9 @@ int main(int, char**)
// Our state
bool show_demo_window = true;
bool show_another_window = false;
bool reload_fonts = false;
ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);
ImVec2 last_framebuffer_scale = ImVec2(0, 0);

// Main loop
bool done = false;
Expand Down Expand Up @@ -549,6 +643,9 @@ int main(int, char**)
ImGui::SameLine();
ImGui::Text("counter = %d", counter);

if (ImGui::Button("Reload fonts"))
reload_fonts = true;

ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate);
ImGui::End();
}
Expand Down Expand Up @@ -576,6 +673,15 @@ int main(int, char**)
FrameRender(wd, draw_data);
FramePresent(wd);
}

if (last_framebuffer_scale.x != io.DisplayFramebufferScale.x ||
last_framebuffer_scale.y != io.DisplayFramebufferScale.y ||
reload_fonts) {
ReloadFonts();

last_framebuffer_scale = io.DisplayFramebufferScale;
reload_fonts = false;
}
}

// Cleanup
Expand Down