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

> Integrate Dear ImGui with Vulkan using the official backend. Learn to initialize ImGui Vulkan, set up render passes, and render draw data in your command buffer for a seamless UI integration.

- Repository: [omar/imgui](https://github.com/ocornut/imgui)
- Tags: how-to-guide
- Published: 2026-07-22

---

**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`](https://github.com/ocornut/imgui/blob/main/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`](https://github.com/ocornut/imgui/blob/main/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.

```cpp
#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.

```cpp
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.

```cpp
// 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.

```cpp
// 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`](https://github.com/ocornut/imgui/blob/main/backends/imgui_impl_vulkan.cpp).

```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`](https://github.com/ocornut/imgui/blob/main/imgui_impl_vulkan.cpp).

## Cleanup and Shutdown

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

```cpp
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:

- **[`backends/imgui_impl_vulkan.h`](https://github.com/ocornut/imgui/blob/main/backends/imgui_impl_vulkan.h)** – Public API declarations and `ImGui_ImplVulkan_InitInfo` structure.
- **[`backends/imgui_impl_vulkan.cpp`](https://github.com/ocornut/imgui/blob/main/backends/imgui_impl_vulkan.cpp)** – Backend implementation handling buffer uploads, descriptor management, and pipeline creation.
- **[`examples/example_glfw_vulkan/main.cpp`](https://github.com/ocornut/imgui/blob/main/examples/example_glfw_vulkan/main.cpp)** – Complete working example with swap chain management.
- **[`examples/example_sdl2_vulkan/main.cpp`](https://github.com/ocornut/imgui/blob/main/examples/example_sdl2_vulkan/main.cpp)** – SDL2 variant for cross-platform applications.
- **[`examples/example_win32_vulkan/main.cpp`](https://github.com/ocornut/imgui/blob/main/examples/example_win32_vulkan/main.cpp)** – Native Win32 platform backend without third-party libraries.

## 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`](https://github.com/ocornut/imgui/blob/main/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`](https://github.com/ocornut/imgui/blob/main/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.