How to Integrate Dear ImGui with Vulkan: Complete Backend Setup Guide

Integrate Dear ImGui with Vulkan by initializing the imgui_impl_vulkan backend using an ImGui_ImplVulkan_InitInfo structure containing your device, queue, and render pass, then call ImGui_ImplVulkan_RenderDrawData() each frame inside your command buffer to render the UI.

Dear ImGui ships with an official Vulkan renderer backend in the ocornut/imgui repository that manages vertex buffers, descriptor pools, and pipeline state automatically. To integrate Dear ImGui with Vulkan, you include backends/imgui_impl_vulkan.h, populate the initialization structure with your existing Vulkan context handles, and execute the per-frame functions within your rendering loop. This backend supports both traditional render passes and the VK_KHR_dynamic_rendering extension.

Required Vulkan Context

Before initializing ImGui, your application must create and own a functional Vulkan context. The backend does not create these objects for you—it only consumes them.

You must provide:

  • VkInstance – Created with necessary surface extensions.
  • VkPhysicalDevice – Selected GPU supporting required queue families.
  • VkDevice – Logical device with graphics queue capabilities.
  • VkQueue – Graphics queue for command submission.
  • VkRenderPass – Render pass used for your swap chain, or dynamic rendering configuration.
  • VkDescriptorPool (optional) – Either create one yourself or set DescriptorPoolSize > 0 to let ImGui create it internally.
  • VkPipelineCache (optional) – For pipeline creation caching.

These handles populate the ImGui_ImplVulkan_InitInfo structure defined in backends/imgui_impl_vulkan.h.

Initializing the Vulkan Backend

Include Headers

Add the ImGui core header and the Vulkan backend files. You also need a platform backend (GLFW, SDL, Win32) initialized before the renderer.

#include "imgui.h"
#include "imgui_impl_vulkan.h"
#include "imgui_impl_glfw.h"   // Replace with your platform backend

Configure ImGui_ImplVulkan_InitInfo

Fill the initialization structure with your Vulkan handles. Since version 2025-09-26, render pass parameters moved into the PipelineInfoMain sub-structure.

ImGui_ImplVulkan_InitInfo init_info = {};
init_info.Instance       = g_Instance;          // Your VkInstance
init_info.PhysicalDevice = g_PhysicalDevice;    // Your VkPhysicalDevice
init_info.Device         = g_Device;            // Your VkDevice
init_info.QueueFamily    = g_QueueFamily;       // Graphics queue family index
init_info.Queue          = g_Queue;             // Your VkQueue
init_info.PipelineCache  = g_PipelineCache;     // Optional: VK_NULL_HANDLE allowed
init_info.DescriptorPool = g_DescriptorPool;    // Optional: set 0 to auto-create
init_info.MinImageCount  = g_MinImageCount;     // >= 2 (match your swap chain)
init_info.ImageCount     = wd->ImageCount;      // Swap chain image count
init_info.Allocator      = g_Allocator;         // Optional: custom VkAllocationCallbacks

// Render pass configuration (required)
init_info.PipelineInfoMain.RenderPass    = wd->RenderPass;
init_info.PipelineInfoMain.Subpass       = 0;
init_info.PipelineInfoMain.MSAASamples   = VK_SAMPLE_COUNT_1_BIT;

// Optional: custom shader modules (leave zeroed for built-in shaders)
init_info.CustomShaderVertCreateInfo = {};
init_info.CustomShaderFragCreateInfo = {};

// Optional: error callback
init_info.CheckVkResultFn = [](VkResult err){ /* handle error */ };

Initialize Backends

Initialize your platform backend first, then the Vulkan renderer. The font texture uploads automatically during the first ImGui_ImplVulkan_NewFrame() call.

// Platform backend must come first
ImGui_ImplGlfw_InitForVulkan(window, true);

// Initialize Vulkan backend
ImGui_ImplVulkan_Init(&init_info);

Per-Frame Rendering Loop

Each frame, synchronize ImGui with your Vulkan command buffer recording.

// 1. Start frame
ImGui_ImplVulkan_NewFrame();
ImGui_ImplGlfw_NewFrame();   // Your platform backend
ImGui::NewFrame();

// 2. Build UI
ImGui::Begin("Vulkan Example");
ImGui::Text("Hello from Vulkan!");
ImGui::End();

// 3. Render
ImGui::Render();
ImDrawData* draw_data = ImGui::GetDrawData();

// Skip if minimized
if (draw_data->DisplaySize.x > 0.0f && draw_data->DisplaySize.y > 0.0f)
{
    VkCommandBuffer cmd = ...;  // Your acquired command buffer
    
    // Render to command buffer (pipeline arg optional)
    ImGui_ImplVulkan_RenderDrawData(draw_data, cmd, VK_NULL_HANDLE);
    
    // ... submit command buffer and present
}

Managing Custom Textures

The backend identifies textures via VkDescriptorSet cast to ImTextureID. Register your images using the provided helper functions in backends/imgui_impl_vulkan.cpp.

// Register texture
VkDescriptorSet tex_desc = ImGui_ImplVulkan_AddTexture(
    myImageView, 
    VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
);
ImTextureID my_tex = (ImTextureID)tex_desc;

// Use in UI
ImGui::Image(my_tex, ImVec2(100, 100));

// Cleanup when done
ImGui_ImplVulkan_RemoveTexture(tex_desc);

The backend automatically creates linear and nearest samplers (SamplerLinearDS and SamplerNearestDS) accessible through draw callbacks around lines 340-350 in imgui_impl_vulkan.cpp.

Cleanup and Shutdown

Ensure device idle before destroying ImGui objects to prevent in-flight resource deletion.

vkDeviceWaitIdle(g_Device);
ImGui_ImplVulkan_Shutdown();   // Destroys internal Vulkan objects
ImGui_ImplGlfw_Shutdown();     // Platform shutdown
ImGui::DestroyContext();

Key Source Files

Reference these files in the ocornut/imgui repository for implementation details:

Summary

  • Prepare Vulkan context before initialization: instance, device, queue, and render pass.
  • Fill ImGui_ImplVulkan_InitInfo carefully, noting that RenderPass, Subpass, and MSAASamples reside in the PipelineInfoMain sub-structure.
  • Initialize platform backend first, then call ImGui_ImplVulkan_Init().
  • Each frame: call ImGui_ImplVulkan_NewFrame(), build UI, ImGui::Render(), then ImGui_ImplVulkan_RenderDrawData() with your command buffer.
  • Manage textures via ImGui_ImplVulkan_AddTexture() and ImGui_ImplVulkan_RemoveTexture().
  • Shutdown with ImGui_ImplVulkan_Shutdown() after ensuring vkDeviceWaitIdle().

Frequently Asked Questions

Do I need to create a descriptor pool for ImGui?

No. While you can provide your own VkDescriptorPool via ImGui_ImplVulkan_InitInfo::DescriptorPool, you may instead set DescriptorPoolSize to a value greater than zero and leave DescriptorPool as VK_NULL_HANDLE. The backend will create and manage an internal descriptor pool automatically, sized according to your specified DescriptorPoolSize.

How do I use Dear ImGui with Vulkan dynamic rendering?

The backend supports VK_KHR_dynamic_rendering. Instead of providing a VkRenderPass in PipelineInfoMain.RenderPass, configure the dynamic rendering parameters in the initialization structure. Check the comments in imgui_impl_vulkan.h for the specific fields related to dynamic rendering attachments and pipeline flags.

Can I use custom shaders with the Vulkan backend?

Yes. Populate ImGui_ImplVulkan_InitInfo::CustomShaderVertCreateInfo and CustomShaderFragCreateInfo with your VkShaderModuleCreateInfo structures before calling ImGui_ImplVulkan_Init(). If you leave these fields zeroed, the backend uses its built-in vertex and fragment shaders compiled from imgui_impl_vulkan.cpp.

How do I display my own images in ImGui with Vulkan?

Call ImGui_ImplVulkan_AddTexture() with your VkImageView and desired image layout (typically VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL). This returns a VkDescriptorSet that you cast to ImTextureID and pass to ImGui::Image(). Call ImGui_ImplVulkan_RemoveTexture() before destroying the underlying image view to prevent descriptor set leaks.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →