-
-
Notifications
You must be signed in to change notification settings - Fork 10.3k
Integrating with Vulkan
Vulkan is a modern low level graphics api. With vulkan there are changes that is different from OpenGL and DirectX.
This wiki page is inspired by the article from (François Guthmann)[https://frguthmann.github.io/posts/vulkan_imgui/]
This is no way a Vulkan tutorial. To get an idea of the Vulkan API please follow the (vulkan-tutorial)[https://vulkan-tutorial.com/]
Note: I am using Vulkan-HPP headers, but you can certainly use the vulkan.h headers.
imconfig.h
imgui.h
imgui_internal.h
imstb_rectpack.h
imstb_textedit.h
imstb_truetype.h
The ImGUI source files you're going to need is.
imgui.cpp
-
imgui_demo.cpp
(optional) imgui_draw.cpp
imgui_tables.cpp
imgui_widgets.cpp
VkInstance
VkPhysicalDevice
VkDevice
VkQueueFamily
VkQueue
VkDescriptorPool
VkCommandPool
VkCommandBuffer
VkRenderPass
VkFramebuffer
First we need to initialize Vulkan. You should already have done so if you're following the (vulkan-tutorial)[https://vulkan-tutorial.com/]. After getting Vulkan running, we can start an ImGui context. It's recommended to create a seperate VkDescriptorPool
, VkRenderPass
, VkCommandBuffer
, and VkFramebuffer
.
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO(); (void)io;
ImGui_Impl{platform}_InitForVulkan(window, true);
After starting an ImGui context, we give ImGui some of the application Vulkan bindings through an ImGui_ImplVulkan_InitInfo
struct. We then call ImGui_ImplVulkan_Init()
passing in a pointer to the ImGui_ImplVulkan_InitInfo
and a VkRenderPass
. This will initalize Vulkan for ImGui.
We then upload font textures to the GPU.
// Allocate a command buffer
// Record our command buffer
cb.begin({vk::CommandBufferUsageFlagBits::eOneTimeSubmit});
ImGui_ImplVulkan_CreateFontsTexture(cb);
cb.end();
// Submit to the GPU
vk::SubmitInfo si;
si.commandBufferCount = cb.size();
si.pCommandBuffers = cb.data();
vk::Result res = device->getGraphicsQueue().submit(1, &si, {});
device->getGraphicsQueue().waitIdle(); // Wait for cb is complete
We need to call the following every frame.
ImGui_ImplVulkan_NewFrame();
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
When we end the frame, we want to build the model so we can render this to the screen.
ImGuiIO& io = ::ImGui::GetIO();
ImGui::Render();
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable){
ImGui::UpdatePlatformWindows();
ImGui::RenderPlatformWindowsDefault();
}
Once we have the model we can finally submit the draw call.
vk::ClearValue clearValue;
clearValue.color = vk::ClearColorValue(std::array<float, 4>({0.0f, 0.0f, 0.0f, 1.0f}));
cb.begin({vk::CommandBufferUsageFlags()});
cb.beginRenderPass({
imguiRenderPass,
imguiFramebuffers[swapchainCurrentImage],
{{0,0}, swapchainExtent},
1, &clearValue
}, vk::SubpassContents::eInline);
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cb);
cb.endRenderPass();
cb.end();
vk::SubmitInfo si;
si.commandBufferCount = 1;
si.pCommandBuffers = &cb;
graphicsQueue->submit(si);
When the window viewport resizes, we must create a new VkFramebuffer
and VkRenderPass
At the end of the application life-cycle, we must destroy our ImGui context.
ImGui_ImplVulkan_Shutdown()
ImGui_ImplGlfw_Shutdown()
ImGui::DestroyContext()
In our application life cycle we should have
while(true){
updateWindow();
rendererBeginFrame(); // Acquire images
imguiBeginFrame();
ImGui::ShowDemoWindow(); // Issue ImGui commands
imguiEndFrame();
imguiRender(); // Submit Command buffers to screen
rendererPresent(); // Present to the screen
}