Use separate font atlas for vulkan

vkCreateSwapchainKHR and vkQueuePresentKHR may share the same ImGui context accidentally and
vkCreateSwapchainKHR might (re)create font image and destroy old font atlas while vkQueuePresentKHR is still rendering :(
pull/811/head
jackun 2 years ago
parent 14dcd153ae
commit 85007fe0bd
No known key found for this signature in database
GPG Key ID: 119DB3F1D05A9ED3

@ -267,7 +267,7 @@ int main(int, char**)
// Setup Platform/Renderer backends
int control_client = -1;
parse_overlay_config(&params, getenv("MANGOHUD_CONFIG"));
create_fonts(params, sw_stats.font1, sw_stats.font_text);
create_fonts(nullptr, params, sw_stats.font1, sw_stats.font_text);
HUDElements.convert_colors(params);
init_cpu_stats(params);
notifier.params = &params;

@ -3,10 +3,14 @@
#include "font_default.h"
#include "IconsForkAwesome.h"
#include "forkawesome.h"
void create_fonts(const overlay_params& params, ImFont*& small_font, ImFont*& text_font)
void create_fonts(ImFontAtlas* font_atlas, const overlay_params& params, ImFont*& small_font, ImFont*& text_font)
{
auto& io = ImGui::GetIO();
io.Fonts->Clear();
if (!font_atlas)
font_atlas = io.Fonts;
font_atlas->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)
@ -31,21 +35,21 @@ void create_fonts(const overlay_params& params, ImFont*& small_font, ImFont*& te
ImVector<ImWchar> glyph_ranges;
ImFontGlyphRangesBuilder builder;
builder.AddRanges(io.Fonts->GetGlyphRangesDefault());
builder.AddRanges(font_atlas->GetGlyphRangesDefault());
if (params.font_glyph_ranges & FG_KOREAN)
builder.AddRanges(io.Fonts->GetGlyphRangesKorean());
builder.AddRanges(font_atlas->GetGlyphRangesKorean());
if (params.font_glyph_ranges & FG_CHINESE_FULL)
builder.AddRanges(io.Fonts->GetGlyphRangesChineseFull());
builder.AddRanges(font_atlas->GetGlyphRangesChineseFull());
if (params.font_glyph_ranges & FG_CHINESE_SIMPLIFIED)
builder.AddRanges(io.Fonts->GetGlyphRangesChineseSimplifiedCommon());
builder.AddRanges(font_atlas->GetGlyphRangesChineseSimplifiedCommon());
if (params.font_glyph_ranges & FG_JAPANESE)
builder.AddRanges(io.Fonts->GetGlyphRangesJapanese()); // Not exactly Shift JIS compatible?
builder.AddRanges(font_atlas->GetGlyphRangesJapanese()); // Not exactly Shift JIS compatible?
if (params.font_glyph_ranges & FG_CYRILLIC)
builder.AddRanges(io.Fonts->GetGlyphRangesCyrillic());
builder.AddRanges(font_atlas->GetGlyphRangesCyrillic());
if (params.font_glyph_ranges & FG_THAI)
builder.AddRanges(io.Fonts->GetGlyphRangesThai());
builder.AddRanges(font_atlas->GetGlyphRangesThai());
if (params.font_glyph_ranges & FG_VIETNAMESE)
builder.AddRanges(io.Fonts->GetGlyphRangesVietnamese());
builder.AddRanges(font_atlas->GetGlyphRangesVietnamese());
if (params.font_glyph_ranges & FG_LATIN_EXT_A) {
constexpr ImWchar latin_ext_a[] { 0x0100, 0x017F, 0 };
builder.AddRanges(latin_ext_a);
@ -61,23 +65,23 @@ void create_fonts(const overlay_params& params, ImFont*& small_font, ImFont*& te
// ImGui takes ownership of the data, no need to free it
if (!params.font_file.empty() && file_exists(params.font_file)) {
io.Fonts->AddFontFromFileTTF(params.font_file.c_str(), font_size, nullptr, same_font && same_size ? glyph_ranges.Data : default_range);
io.Fonts->AddFontFromMemoryCompressedBase85TTF(forkawesome_compressed_data_base85, font_size, &config, icon_ranges);
font_atlas->AddFontFromFileTTF(params.font_file.c_str(), font_size, nullptr, same_font && same_size ? glyph_ranges.Data : default_range);
font_atlas->AddFontFromMemoryCompressedBase85TTF(forkawesome_compressed_data_base85, font_size, &config, icon_ranges);
if (params.no_small_font)
small_font = io.Fonts->Fonts[0];
small_font = font_atlas->Fonts[0];
else {
small_font = io.Fonts->AddFontFromFileTTF(params.font_file.c_str(), font_size * 0.55f, nullptr, default_range);
io.Fonts->AddFontFromMemoryCompressedBase85TTF(forkawesome_compressed_data_base85, font_size * 0.55f, &config, icon_ranges);
small_font = font_atlas->AddFontFromFileTTF(params.font_file.c_str(), font_size * 0.55f, nullptr, default_range);
font_atlas->AddFontFromMemoryCompressedBase85TTF(forkawesome_compressed_data_base85, font_size * 0.55f, &config, icon_ranges);
}
} else {
const char* ttf_compressed_base85 = GetDefaultCompressedFontDataTTFBase85();
io.Fonts->AddFontFromMemoryCompressedBase85TTF(ttf_compressed_base85, font_size, nullptr, default_range);
io.Fonts->AddFontFromMemoryCompressedBase85TTF(forkawesome_compressed_data_base85, font_size, &config, icon_ranges);
font_atlas->AddFontFromMemoryCompressedBase85TTF(ttf_compressed_base85, font_size, nullptr, default_range);
font_atlas->AddFontFromMemoryCompressedBase85TTF(forkawesome_compressed_data_base85, font_size, &config, icon_ranges);
if (params.no_small_font)
small_font = io.Fonts->Fonts[0];
small_font = font_atlas->Fonts[0];
else {
small_font = io.Fonts->AddFontFromMemoryCompressedBase85TTF(ttf_compressed_base85, font_size * 0.55f, nullptr, default_range);
io.Fonts->AddFontFromMemoryCompressedBase85TTF(forkawesome_compressed_data_base85, font_size * 0.55f, &config, icon_ranges);
small_font = font_atlas->AddFontFromMemoryCompressedBase85TTF(ttf_compressed_base85, font_size * 0.55f, nullptr, default_range);
font_atlas->AddFontFromMemoryCompressedBase85TTF(forkawesome_compressed_data_base85, font_size * 0.55f, &config, icon_ranges);
}
}
@ -86,9 +90,9 @@ void create_fonts(const overlay_params& params, ImFont*& small_font, ImFont*& te
font_file_text = params.font_file;
if ((!same_font || !same_size) && file_exists(font_file_text))
text_font = io.Fonts->AddFontFromFileTTF(font_file_text.c_str(), font_size_text, nullptr, glyph_ranges.Data);
text_font = font_atlas->AddFontFromFileTTF(font_file_text.c_str(), font_size_text, nullptr, glyph_ranges.Data);
else
text_font = io.Fonts->Fonts[0];
text_font = font_atlas->Fonts[0];
io.Fonts->Build();
font_atlas->Build();
}

@ -161,7 +161,7 @@ void imgui_create(void *ctx)
ImGui_ImplOpenGL3_Init();
create_fonts(params, sw_stats.font1, sw_stats.font_text);
create_fonts(nullptr, 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
@ -209,7 +209,7 @@ void imgui_render(unsigned int width, unsigned int height)
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);
create_fonts(nullptr, params, sw_stats.font1, sw_stats.font_text);
ImGui_ImplOpenGL3_CreateFontsTexture();
}

@ -107,7 +107,7 @@ void check_keybinds(overlay_params& params, uint32_t vendorID);
void init_system_info(void);
void FpsLimiter(struct fps_limit& stats);
std::string get_device_name(uint32_t vendorID, uint32_t deviceID);
void create_fonts(const overlay_params& params, ImFont*& small_font, ImFont*& text_font);
void create_fonts(ImFontAtlas* font_atlas, const overlay_params& params, ImFont*& small_font, ImFont*& text_font);
void right_aligned_text(ImVec4& col, float off_x, const char *fmt, ...);
void center_text(const std::string& text);
ImVec4 change_on_load_temp(LOAD_DATA& data, unsigned current);

@ -165,6 +165,7 @@ struct swapchain_data {
/**/
ImGuiContext* imgui_context;
ImFontAtlas* font_atlas;
ImVec2 window_size;
struct swapchain_stats sw_stats;
@ -388,6 +389,7 @@ static struct swapchain_data *new_swapchain_data(VkSwapchainKHR swapchain,
data->device = device_data;
data->swapchain = swapchain;
data->window_size = ImVec2(instance_data->params.width, instance_data->params.height);
data->font_atlas = IM_NEW(ImFontAtlas);
map_object(HKEY(data->swapchain), data);
return data;
}
@ -702,16 +704,15 @@ 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)
{
SPDLOG_DEBUG("Recreating font image");
VkDescriptorSet desc_set = (VkDescriptorSet)io.Fonts->TexID;
create_fonts(instance_data->params, data->sw_stats.font1, data->sw_stats.font_text);
VkDescriptorSet desc_set = (VkDescriptorSet)data->font_atlas->TexID;
create_fonts(data->font_atlas, instance_data->params, data->sw_stats.font1, data->sw_stats.font_text);
unsigned char* pixels;
int width, height;
io.Fonts->GetTexDataAsAlpha8(&pixels, &width, &height);
data->font_atlas->GetTexDataAsAlpha8(&pixels, &width, &height);
// wait for rendering to complete, if any
device_data->vtable.DeviceWaitIdle(device_data->device);
@ -722,7 +723,7 @@ static void check_fonts(struct swapchain_data* data)
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->SetTexID((ImTextureID)desc_set);
data->font_atlas->SetTexID((ImTextureID)desc_set);
data->font_uploaded = false;
data->sw_stats.font_params_hash = params.font_params_hash;
SPDLOG_DEBUG("Default font tex size: {}x{}px", width, height);
@ -740,10 +741,9 @@ static void ensure_swapchain_fonts(struct swapchain_data *data,
return;
data->font_uploaded = true;
ImGuiIO& io = ImGui::GetIO();
unsigned char* pixels;
int width, height;
io.Fonts->GetTexDataAsAlpha8(&pixels, &width, &height);
data->font_atlas->GetTexDataAsAlpha8(&pixels, &width, &height);
size_t upload_size = width * height * 1 * sizeof(char);
upload_image_data(device_data, command_buffer, pixels, upload_size, width, height, data->upload_font_buffer, data->upload_font_buffer_mem, data->font_image);
}
@ -894,7 +894,7 @@ static struct overlay_draw *render_swapchain_display(struct swapchain_data *data
#if 1 // disable if using >1 font textures
VkDescriptorSet desc_set[1] = {
//data->descriptor_set
reinterpret_cast<VkDescriptorSet>(ImGui::GetIO().Fonts->Fonts[0]->ContainerAtlas->TexID)
reinterpret_cast<VkDescriptorSet>(data->font_atlas->TexID)
};
device_data->vtable.CmdBindDescriptorSets(draw->command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
data->pipeline_layout, 0, 1, desc_set, 0, NULL);
@ -1308,7 +1308,7 @@ static void setup_swapchain_data(struct swapchain_data *data,
data->height = pCreateInfo->imageExtent.height;
data->format = pCreateInfo->imageFormat;
data->imgui_context = ImGui::CreateContext();
data->imgui_context = ImGui::CreateContext(data->font_atlas);
ImGui::SetCurrentContext(data->imgui_context);
ImGui::GetIO().IniFilename = NULL;
@ -1465,6 +1465,7 @@ static void shutdown_swapchain_data(struct swapchain_data *data)
device_data->vtable.DestroySampler(device_data->device, data->font_sampler, NULL);
shutdown_swapchain_font(data);
IM_FREE(data->font_atlas);
ImGui::DestroyContext(data->imgui_context);
}

Loading…
Cancel
Save