diff --git a/src/font.cpp b/src/font.cpp index ff51de87..e8866659 100644 --- a/src/font.cpp +++ b/src/font.cpp @@ -5,6 +5,7 @@ void create_fonts(const overlay_params& params, ImFont*& small_font, ImFont*& text_font) { auto& io = ImGui::GetIO(); + io.Fonts->Clear(); ImGui::GetIO().FontGlobalScale = params.font_scale; // set here too so ImGui::CalcTextSize is correct float font_size = params.font_size; if (font_size < FLT_EPSILON) @@ -40,16 +41,15 @@ void create_fonts(const overlay_params& params, ImFont*& small_font, ImFont*& te if (params.font_glyph_ranges & FG_VIETNAMESE) builder.AddRanges(io.Fonts->GetGlyphRangesVietnamese()); if (params.font_glyph_ranges & FG_LATIN_EXT_A) { - static const ImWchar latin_ext_a[] { 0x0100, 0x017F, 0 }; + constexpr ImWchar latin_ext_a[] { 0x0100, 0x017F, 0 }; builder.AddRanges(latin_ext_a); } if (params.font_glyph_ranges & FG_LATIN_EXT_B) { - static const ImWchar latin_ext_b[] { 0x0180, 0x024F, 0 }; + constexpr ImWchar latin_ext_b[] { 0x0180, 0x024F, 0 }; builder.AddRanges(latin_ext_b); } builder.BuildRanges(&glyph_ranges); - // If both font_file and text_font_file are the same then just use "default" font bool same_font = (params.font_file == params.font_file_text || params.font_file_text.empty()); bool same_size = (font_size == font_size_text); @@ -79,4 +79,4 @@ void create_fonts(const overlay_params& params, ImFont*& small_font, ImFont*& te text_font = io.Fonts->Fonts[0]; io.Fonts->Build(); -} \ No newline at end of file +} diff --git a/src/gl/imgui_hud.cpp b/src/gl/imgui_hud.cpp index c6a4ac43..a62396d0 100644 --- a/src/gl/imgui_hud.cpp +++ b/src/gl/imgui_hud.cpp @@ -133,6 +133,7 @@ void imgui_create(void *ctx) glGetIntegerv(GL_TEXTURE_BINDING_2D, ¤t_texture); create_fonts(params, sw_stats.font1, sw_stats.font_text); + sw_stats.font_params_hash = params.font_params_hash; // Restore global context or ours might clash with apps that use Dear ImGui ImGui::SetCurrentContext(saved_ctx); @@ -178,6 +179,13 @@ void imgui_render(unsigned int width, unsigned int height) if (HUDElements.colors.update) HUDElements.convert_colors(params); + if (sw_stats.font_params_hash != params.font_params_hash) + { + sw_stats.font_params_hash = params.font_params_hash; + create_fonts(params, sw_stats.font1, sw_stats.font_text); + ImGui_ImplOpenGL3_CreateFontsTexture(); + } + ImGui_ImplOpenGL3_NewFrame(); ImGui::NewFrame(); { diff --git a/src/gl/imgui_impl_opengl3.cpp b/src/gl/imgui_impl_opengl3.cpp index e44ba290..9375e608 100644 --- a/src/gl/imgui_impl_opengl3.cpp +++ b/src/gl/imgui_impl_opengl3.cpp @@ -105,7 +105,7 @@ static void ImGui_ImplOpenGL3_DestroyFontsTexture() } } -static bool ImGui_ImplOpenGL3_CreateFontsTexture() +bool ImGui_ImplOpenGL3_CreateFontsTexture() { ImGui_ImplOpenGL3_DestroyFontsTexture(); // Build texture atlas diff --git a/src/gl/imgui_impl_opengl3.h b/src/gl/imgui_impl_opengl3.h index 4d9d373a..01609368 100644 --- a/src/gl/imgui_impl_opengl3.h +++ b/src/gl/imgui_impl_opengl3.h @@ -34,6 +34,7 @@ IMGUI_IMPL_API bool ImGui_ImplOpenGL3_Init(const char* glsl_version = nullpt IMGUI_IMPL_API void ImGui_ImplOpenGL3_Shutdown(); IMGUI_IMPL_API void ImGui_ImplOpenGL3_NewFrame(); IMGUI_IMPL_API void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data); +IMGUI_IMPL_API bool ImGui_ImplOpenGL3_CreateFontsTexture(); // (Optional) Called by Init/NewFrame/Shutdown //IMGUI_IMPL_API bool ImGui_ImplOpenGL3_CreateFontsTexture(); diff --git a/src/overlay.h b/src/overlay.h index f927f933..09299f83 100644 --- a/src/overlay.h +++ b/src/overlay.h @@ -30,6 +30,7 @@ struct swapchain_stats { ImFont* font1 = nullptr; ImFont* font_text = nullptr; + size_t font_params_hash = 0; std::string time; double fps; struct iostats io; diff --git a/src/overlay_params.cpp b/src/overlay_params.cpp index b339a49a..1eff9cc7 100644 --- a/src/overlay_params.cpp +++ b/src/overlay_params.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include "overlay_params.h" #include "overlay.h" @@ -33,6 +34,25 @@ #include "dbus_info.h" #endif +// C++17 has `if constexpr` so this won't be needed then +template +size_t get_hash() +{ + return 0; +} + +template +size_t get_hash(T const& first, Ts const&... rest) +{ + size_t hash = std::hash{}(first); +#if __cplusplus >= 201703L + if constexpr (sizeof...(rest) > 0) +#endif + hash ^= get_hash(rest...) << 1; + + return hash; +} + static enum overlay_param_position parse_position(const char *str) { @@ -677,6 +697,14 @@ parse_overlay_config(struct overlay_params *params, params->width += 7 * params->font_size * params->font_scale; } + params->font_params_hash = get_hash(params->font_size, + params->font_size_text, + params->no_small_font, + params->font_file, + params->font_file_text, + params->font_glyph_ranges + ); + // set frametime limit using namespace std::chrono; if (params->fps_limit.size() > 0 && params->fps_limit[0] > 0) diff --git a/src/overlay_params.h b/src/overlay_params.h index b2e325b6..b3f34d22 100644 --- a/src/overlay_params.h +++ b/src/overlay_params.h @@ -209,6 +209,8 @@ struct overlay_params { std::string config_file_path; std::unordered_map options; int permit_upload; + + size_t font_params_hash; }; const extern char *overlay_param_names[]; diff --git a/src/vulkan.cpp b/src/vulkan.cpp index 0dbe195c..a7d78652 100644 --- a/src/vulkan.cpp +++ b/src/vulkan.cpp @@ -220,6 +220,8 @@ static void unmap_object(uint64_t obj) #define CHAR_CELSIUS "\xe2\x84\x83" #define CHAR_FAHRENHEIT "\xe2\x84\x89" +static void shutdown_swapchain_font(struct swapchain_data*); + static VkLayerInstanceCreateInfo *get_instance_chain_info(const VkInstanceCreateInfo *pCreateInfo, VkLayerFunction func) { @@ -835,13 +837,14 @@ static void upload_image_data(struct device_data *device_data, 1, use_barrier); } -static VkDescriptorSet create_image_with_desc(struct swapchain_data *data, - uint32_t width, - uint32_t height, - VkFormat format, - VkImage& image, - VkDeviceMemory& image_mem, - VkImageView& image_view) +static void create_image(struct swapchain_data *data, + VkDescriptorSet descriptor_set, + uint32_t width, + uint32_t height, + VkFormat format, + VkImage& image, + VkDeviceMemory& image_mem, + VkImageView& image_view) { struct device_data *device_data = data->device; @@ -888,9 +891,22 @@ static VkDescriptorSet create_image_with_desc(struct swapchain_data *data, VK_CHECK(device_data->vtable.CreateImageView(device_data->device, &view_info, NULL, &image_view)); - VkDescriptorSet descriptor_set; + update_image_descriptor(data, image_view, descriptor_set); +} - VkDescriptorSetAllocateInfo alloc_info = {}; +static VkDescriptorSet create_image_with_desc(struct swapchain_data *data, + uint32_t width, + uint32_t height, + VkFormat format, + VkImage& image, + VkDeviceMemory& image_mem, + VkImageView& image_view) +{ + struct device_data *device_data = data->device; + + VkDescriptorSet descriptor_set {}; + + VkDescriptorSetAllocateInfo alloc_info {}; alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; alloc_info.descriptorPool = data->descriptor_pool; alloc_info.descriptorSetCount = 1; @@ -899,14 +915,54 @@ static VkDescriptorSet create_image_with_desc(struct swapchain_data *data, &alloc_info, &descriptor_set)); - update_image_descriptor(data, image_view, descriptor_set); + create_image(data, descriptor_set, width, height, format, image, image_mem, image_view); return descriptor_set; } +static void check_fonts(struct swapchain_data* data) +{ + struct device_data *device_data = data->device; + struct instance_data *instance_data = device_data->instance; + auto& params = instance_data->params; + ImGuiIO& io = ImGui::GetIO(); + + if (params.font_params_hash != data->sw_stats.font_params_hash) + { + std::cerr << "MANGOHUD: recreating font image\n"; + VkDescriptorSet desc_set = (VkDescriptorSet)io.Fonts->TexID; + create_fonts(instance_data->params, data->sw_stats.font1, data->sw_stats.font_text); + unsigned char* pixels; + int width, height; + io.Fonts->GetTexDataAsAlpha8(&pixels, &width, &height); + + // wait for rendering to complete, if any + device_data->vtable.DeviceWaitIdle(device_data->device); + shutdown_swapchain_font(data); + + if (desc_set) + create_image(data, desc_set, width, height, VK_FORMAT_R8_UNORM, data->font_image, data->font_mem, data->font_image_view); + else + desc_set = create_image_with_desc(data, width, height, VK_FORMAT_R8_UNORM, data->font_image, data->font_mem, data->font_image_view); + + io.Fonts->TexID = (ImTextureID) desc_set; + + data->font_uploaded = false; + data->sw_stats.font_params_hash = params.font_params_hash; + +#ifndef NDEBUG + std::cerr << "MANGOHUD: Default font tex size: " << width << "x" << height << "px (" << (width*height*1) << " bytes)" << "\n"; +#endif + + } +} + static void ensure_swapchain_fonts(struct swapchain_data *data, VkCommandBuffer command_buffer) { struct device_data *device_data = data->device; + + check_fonts(data); + if (data->font_uploaded) return; @@ -1411,18 +1467,7 @@ static void setup_swapchain_data_pipeline(struct swapchain_data *data) device_data->vtable.DestroyShaderModule(device_data->device, vert_module, NULL); device_data->vtable.DestroyShaderModule(device_data->device, frag_module, NULL); - create_fonts(device_data->instance->params, data->sw_stats.font1, data->sw_stats.font_text); - - ImGuiIO& io = ImGui::GetIO(); - unsigned char* pixels; - int width, height; - - // upload default font to VkImage - io.Fonts->GetTexDataAsAlpha8(&pixels, &width, &height); - io.Fonts->TexID = (ImTextureID)create_image_with_desc(data, width, height, VK_FORMAT_R8_UNORM, data->font_image, data->font_mem, data->font_image_view); -#ifndef NDEBUG - std::cerr << "MANGOHUD: Default font tex size: " << width << "x" << height << "px (" << (width*height*1) << " bytes)" << "\n"; -#endif + check_fonts(data); // if (data->descriptor_set) // update_image_descriptor(data, data->font_image_view[0], data->descriptor_set); @@ -1593,6 +1638,18 @@ static void setup_swapchain_data(struct swapchain_data *data, NULL, &data->command_pool)); } +static void shutdown_swapchain_font(struct swapchain_data *data) +{ + struct device_data *device_data = data->device; + + device_data->vtable.DestroyImageView(device_data->device, data->font_image_view, NULL); + device_data->vtable.DestroyImage(device_data->device, data->font_image, NULL); + device_data->vtable.FreeMemory(device_data->device, data->font_mem, NULL); + + device_data->vtable.DestroyBuffer(device_data->device, data->upload_font_buffer, NULL); + device_data->vtable.FreeMemory(device_data->device, data->upload_font_buffer_mem, NULL); +} + static void shutdown_swapchain_data(struct swapchain_data *data) { struct device_data *device_data = data->device; @@ -1626,12 +1683,7 @@ static void shutdown_swapchain_data(struct swapchain_data *data) data->descriptor_layout, NULL); device_data->vtable.DestroySampler(device_data->device, data->font_sampler, NULL); - device_data->vtable.DestroyImageView(device_data->device, data->font_image_view, NULL); - device_data->vtable.DestroyImage(device_data->device, data->font_image, NULL); - device_data->vtable.FreeMemory(device_data->device, data->font_mem, NULL); - - device_data->vtable.DestroyBuffer(device_data->device, data->upload_font_buffer, NULL); - device_data->vtable.FreeMemory(device_data->device, data->upload_font_buffer_mem, NULL); + shutdown_swapchain_font(data); ImGui::DestroyContext(data->imgui_context); }