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

Fonts become white rectangles after upgrading to most recent ImGui/SDL3/Vulkan versions #7602

Open
NostraMagister opened this issue May 18, 2024 · 4 comments

Comments

@NostraMagister
Copy link

NostraMagister commented May 18, 2024

Version/Branch of Dear ImGui:
Version 1.90.6

Back-ends:
imgui_impl_sdl3.cpp + imgui_impl_vulkan.cpp

Compiler, OS:
Windows 10 + MSVC 2022

Full config/build information:
No response

Details:

I initially used ImGui 1.89.6 with SDL3 3.0.0 and Vulkan 1.3.250 for building a test application using the ImGui window system to display 4 simultaneous webcams (captured with FFmpeg) as textures. This included ImGui sub-windows inside the main SDL3 window to select web-cams and make some selections such as video display size. It worked 100% correctly.

I upgraded ImGui 1.89.6 to 1.90.6, SDL3 3.0.0 to 3.1.2 and Vulkan 1.3.250 to 1.3.283 and fixed the ABI changes.
Everything still works 100% correct EXCEPT that I have a problem with ImGui fonts loading. All text characters became white square blocks BUT they can still be used (e.g. clicked to select web-cams from a list box) and the code continues to work correctly and behave as expected. Vulkan can be removed from the trouble shooting because I ran the code after upgrading ONLY Vulkan and the fonts where still there. SDL3/ImGui had to be upgraded together due to ABI changes in both.

I ignored the following ImGui wiki comment and excluded its solutions as the possible problem because the default font loaded and worked fine before upgrading and I only use the default font. Hence there cannot be a size problem IMO.

(4) Font atlas texture fails to upload to GPU.

This is often of byproduct of point 3. If you have large number of glyphs or multiple fonts, the texture may become too big for your graphics API. The typical result of failing to upload a texture is if every glyph or everything appears as empty black or white rectangle. Mind the fact that some graphics drivers have texture size limitation. If you are building a PC application, mind the fact that your users may use hardware with lower limitations than yours.

After upgrading ImGui/SDL3/Vulkan, based on the following ImGui change log comment, I made some changes:

Backends: Vulkan: Removed parameter from ImGui_ImplVulkan_CreateFontsTexture(): backend now creates its own
command-buffer to upload fonts. Removed ImGui_ImplVulkan_DestroyFontUploadObjects() which is now unnecessary.
No need to call ImGui_ImplVulkan_CreateFontsTexture() as it is done automatically in ImGui_ImplVulkan_NewFrame().
You can call ImGui_ImplVulkan_CreateFontsTexture() manually if you need to reload the font atlas texture.
(#6943, #6715, #6327, #3743, #4618)

I had the following code below BEFORE the upgrade. The UploadVulkanFonts() method below was called WITHOUT first calling ImGui's io.Fonts->AddFontDefault() or io.Fonts->AddFontFromFileTTF(...) because as I said I only use the default font. I assumed that the default font was present in the ImGui Font Altas by default, which is confirmed in the wiki. So the following code worked perfectly WITHOUT any .ttf file in my project/directories.

// Upload Vulkan backend Fonts into the GPU
void MainWindow::UploadVulkanFonts()
{
VkResult err = VK_SUCCESS;

// Use any command queue and reset it so that we can start a new command buffer sequence
VkCommandPool command_pool=this->gui_MainWindowData.Frames[this->gui_MainWindowData.FrameIndex].CommandPool;
VkCommandBuffer command_buffer=this->gui_MainWindowData.Frames[this->gui_MainWindowData.FrameIndex].CommandBuffer;

Check_VkResult(vkResetCommandPool(this->sdl.vulkan.vul_Device, command_pool, 0));

// Start a new command buffer
VkCommandBufferBeginInfo begin_info = {};
begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
begin_info.flags |= VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
Check_VkResult(vkBeginCommandBuffer(command_buffer, &begin_info));

// Let ImGui add commands to the command buffer to create the font textures for loaded fonts.
ImGui_ImplVulkan_CreateFontsTexture(command_buffer);

// Finish the command buffer 
VkSubmitInfo end_info = {};
end_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
end_info.commandBufferCount = 1;
end_info.pCommandBuffers = &command_buffer;
Check_VkResult(vkEndCommandBuffer(command_buffer));

// Submit the command buffer and wait until all commands were processed. So we are sure not 
// to start using fonts that are still being loaded to the GPU.
Check_VkResult(vkQueueSubmit(this->sdl.vulkan.vul_Queue, 1, &end_info, VK_NULL_HANDLE));
Check_VkResult(this->sdl.vulkan.DeviceWaitIdel());

// Let ImGui clean-up all objects/structures it used internally and that needed to exist while the command buffer
// was processed (because they were referenced in commands).
ImGui_ImplVulkan_DestroyFontUploadObjects();
}

After the upgrade, ImGui_ImplVulkan_CreateFontsTexture() does not need to be called anymore
according the change log and ImGui_ImplVulkan_DestroyFontUploadObjects() doesn't exist anymore.
As a consequence, the REST/REMAINDER of the above code makes no sense anymore because there is
nothing in the command_buffer anymore. Previously the command buffer was filled by ImGui through the
ImGui_ImplVulkan_CreateFontsTexture(command_buffer) call.

So I simply changed the above function with a no-op (and I eventually will remove the UploadVulkanFonts() completely):

void MainWindow::UploadVulkanFonts(){return;}

While everything else keeps working 100% the characters are white cubes. Although I didn't call ImGui's io.Fonts->AddFontDefault() BEFORE the upgrade, I added it to the code as part of trying to solve this problem. The function DOES return a font handle as expected but the white cubes remain. I do NEVER push/pop fonts anywhere in my code (not before and not after the upgrade) based on the wiki examples that show that when one does NOT push/pop the default font is always used. So I still don't have any .ttf file in my project.

I assumed, based on the change log sited above, that ImGui_ImplVulkan_NewFrame() would load the default font automatically and I seem to remember that this default font is imbedded in the ImGui code or header files.

On a personal note, as far as I understood, this approach of automatically loading the fonts in ImGui_ImplVulkan_NewFrame() was discussed in an SDL2 context. Could it be that some extra implementation is needed to make this work with SDL3 too?

I have explored everything I could (I think) and posted this first in the discussion, but I have made an issue from it after re-reading the wiki Fonts page and running out of solutions to try to solve this myself.

Thanks for any reaction.

@ocornut
Copy link
Owner

ocornut commented May 27, 2024

Thanks for researching this and writing down detailed info.
I don't think SDL2 vs SDL3 would make a difference here, nor the Vulkan version.
I would say it is likely a bug in your code but might as well be a bug in our Vulkan backend.

It's hard to say what's wrong, tho I only had time to skim your issue. I think you could step in the debugger into ImGui_ImplVulkan_NewFrame() and perhaps use a graphics debugger such as RenderDoc. Try to confirm if the texture itself is correct in memory (it could be that the texture is incorrect vs it could be that it's not correctly bound or rendered).

You might want to update to Nov 9 version of imgui repo, confirm that it works, then update to Nov 15 version, that to confirm that it is this precise change that affected you.

@ocornut ocornut changed the title #7595 turned into an issue related to fonts loading problem after upgrade (ImGui/SDL3/Vulkan) Fonts become white rectangles after upgrading to most recent ImGui/SDL3/Vulkan versions May 27, 2024
@ocornut
Copy link
Owner

ocornut commented May 27, 2024

(I tweaked subject line and adding link to #7595 here just in case, but I believe all the info are already in this thread)

@NostraMagister
Copy link
Author

Thank you for the reply.

For clarity the following:

If my OP lead to believe that it was specifically the upgrade to ImGui Version 1.90.6 that (possibly) introduced this problem, then I need to emphasize that I cannot know that. I noticed it with Version 1.90.6 after upgrading from ImGui 1.89.6. So I have no solid ground to claim that it was introduced by version 1.90.6. It might have been already there in an older ImGui version after 1.89.6 or not at all be an ImGui problem and be in my code. If I find what it is then it will be easy to find from what version it came.

If it is in my code I only changed 8 lines to fix ABI changes (ImGui/SDL3), merely 2 related to fonts, with this upgrade and all are code remarks of function arguments that no longer exist or functions that are not needed anymore or also no longer exist. I will revisit them all again to be sure.

I will investigate AddFontDefault() for starters because it returns a font handle (as mentioned in OP), which if there were problems with finding the font to add it to the Font Atlas it would probably not return an handle. Next I will look into ImGui_ImplVulkan_NewFrame() as you suggested. I figure the default font is loaded there on the first pass that notices a font in the atlas has not been loaded yet. I can then see if all Vulkan variables that are used to load the command buffer to the GPU are correctly set and if there are could be sync. problems. This code sequence should be quite comparable to the Vulkan code I posted in OP.

The big ImGui concept difference between the mentioned ImGui versions is that:
Before, when one loaded the fonts textures themselves, fonts were traditionally loaded before the main loop started. With the new ImGui approach where ImGui loads the fonts in ImGui_ImplVulkan_NewFrame() they are loaded during the main loop. In my code they are then in competition with other asynchronous Vulkan code threads that load the camera textures in the Vulkan buffers (for performance reasons). Maybe ImGui_ImplVulkan_NewFrame() can therefore not load the font command buffer due to some device availability or synchronization problem.

I will look further into all this and communicate results here if I find something.
Thank you for your help.

@ocornut
Copy link
Owner

ocornut commented May 28, 2024

I will investigate AddFontDefault() for starters because it returns a font handle

I don't think you need to investigate this. The core Dear ImGui side of things in terms of fonts won't have any issue especially as you are not calling particular font function. At the time of calling AddFontDefault() or Build(), there are no interactions with the graphics system. The issue is either in the backend either in your interaction with the backend or vulkan, and lies in the texture upload or binding.

Again my suggestion are:

  • Use RenderDoc to inspect the texture data or texture calls.
  • Trying to narrow dear imgui versions a little bit would be helpful.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants