-
-
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
This is no way a Vulkan tutorial. To get an idea of the Vulkan API please follow the vulkan-tutorial
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 source files you're going to need are:
imgui.cpp
imgui_demo.cpp
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. After getting Vulkan running, we can start an Dear 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 its context, we give Dear 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 Dear 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
}