# How to Integrate Dear ImGui with Vulkan, DirectX 12, and Metal: A Complete Backend Guide

> Integrate Dear ImGui with Vulkan, DirectX 12, and Metal using the backend guide. Learn how to initialize renderers and render frames efficiently for cross-API compatibility.

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

---

**To integrate Dear ImGui with Vulkan, DirectX 12, or Metal, include the matching renderer backend files from the `backends/` directory, populate the API-specific initialization structure with your graphics device and swap-chain objects, and call the per-frame `NewFrame` and `RenderDrawData` functions inside your main loop.**

Dear ImGui (imgui) uses a split architecture that separates **platform backends** (windowing and input) from **renderer backends** (GPU command generation). According to the `ocornut/imgui` source code, you can pair any platform backend—GLFW, SDL, or Win32—with any graphics API backend by simply including the correct headers and source files from the repository’s `backends/` folder.

## Understanding the Backend Architecture

ImGui never creates GPU resources like swap chains, depth buffers, or framebuffers. Instead, the library expects your application to own these objects and pass them via initialization structures. Each renderer backend exposes a consistent lifecycle: `Init`, `NewFrame`, `RenderDrawData`, and `Shutdown`. This design lets you drop the backend files into your project unchanged while your engine retains full control over the graphics pipeline.

## Vulkan Integration

The Vulkan backend lives in [`backends/imgui_impl_vulkan.h`](https://github.com/ocornut/imgui/blob/main/backends/imgui_impl_vulkan.h) and [`backends/imgui_impl_vulkan.cpp`](https://github.com/ocornut/imgui/blob/main/backends/imgui_impl_vulkan.cpp). It supports both traditional render passes and dynamic rendering (Vulkan 1.3+).

### Initialization Setup

Populate an `ImGui_ImplVulkan_InitInfo` structure with your Vulkan instance, logical device, graphics queue, and descriptor pool. According to [`imgui_impl_vulkan.h`](https://github.com/ocornut/imgui/blob/main/imgui_impl_vulkan.h) (lines 96–140), you must provide:

- `Instance`, `PhysicalDevice`, `Device`, and `Queue`
- `DescriptorPool` (or set `DescriptorPoolSize` > 0 to let ImGui allocate internally)
- `MinImageCount` and `ImageCount` for swap-chain buffering
- `PipelineInfoMain.RenderPass` or enable dynamic rendering via `UseDynamicRendering`

Call `ImGui_ImplVulkan_Init(&init_info)` after creating the ImGui context but before your first frame.

```cpp
ImGui_ImplVulkan_InitInfo init_info = {};
init_info.Instance = vkInstance;
init_info.PhysicalDevice = vkPhysicalDevice;
init_info.Device = vkDevice;
init_info.QueueFamily = graphicsQueueFamily;
init_info.Queue = graphicsQueue;
init_info.DescriptorPool = vkDescriptorPool;
init_info.MinImageCount = 2;
init_info.ImageCount = swapChainImageCount;
init_info.PipelineInfoMain.RenderPass = renderPass;

ImGui_ImplVulkan_Init(&init_info);

```

### Per-Frame Rendering Cycle

Each frame, call `ImGui_ImplVulkan_NewFrame()` (declared at lines 44–45) before `ImGui::NewFrame()`. After building your UI, invoke `ImGui_ImplVulkan_RenderDrawData(draw_data, command_buffer)` to encode draw commands into your primary command buffer.

```cpp
// Inside main loop
ImGui_ImplVulkan_NewFrame();
ImGui::NewFrame();

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

ImGui::Render();
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), commandBuffer);

```

### Texture Registration

To display images within ImGui windows, register your `VkImageView` with `ImGui_ImplVulkan_AddTexture(image_view, image_layout)` (lines 56–58). This returns an `ImTextureID` you can pass to `ImGui::Image()`.

```cpp
VkImageView myView = /* your texture view */;
VkImageLayout layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
ImTextureID texID = ImGui_ImplVulkan_AddTexture(myView, layout);
ImGui::Image(texID, ImVec2(256, 256));

```

## DirectX 12 Integration

The DirectX 12 backend is implemented in [`backends/imgui_impl_dx12.h`](https://github.com/ocornut/imgui/blob/main/backends/imgui_impl_dx12.h) and [`backends/imgui_impl_dx12.cpp`](https://github.com/ocornut/imgui/blob/main/backends/imgui_impl_dx12.cpp). It requires explicit management of SRV (Shader Resource View) descriptors.

### Initialization and Descriptor Management

Create an `ImGui_ImplDX12_InitInfo` struct (lines 33–53) containing your `ID3D12Device`, command queue, and render-target formats. You must provide callbacks (`SrvDescriptorAllocFn` and `SrvDescriptorFreeFn`) to allocate descriptors for font textures, or use the legacy single-descessor fields for simple scenarios.

Call `ImGui_ImplDX12_Init(&init_info)` (lines 56–58) to establish the backend.

### Rendering Workflow

Each frame follows the same pattern: `ImGui_ImplDX12_NewFrame()` before `ImGui::NewFrame()`, and `ImGui_ImplDX12_RenderDrawData(draw_data, command_list)` (lines 60–61) after `ImGui::Render()`. The backend writes draw commands into your supplied `ID3D12GraphicsCommandList`.

```cpp
ImGui_ImplDX12_NewFrame();
ImGui::NewFrame();
// ... UI code ...
ImGui::Render();
ImGui_ImplDX12_RenderDrawData(ImGui::GetDrawData(), commandList);

```

### Texture Handling

Use `ImGui_ImplDX12_AddTexture` to create SRV descriptors for your textures. Like the Vulkan backend, this returns an `ImTextureID` suitable for `ImGui::Image()`.

## Metal Integration

The Metal backend resides in [`backends/imgui_impl_metal.h`](https://github.com/ocornut/imgui/blob/main/backends/imgui_impl_metal.h) and `backends/imgui_impl_metal.mm`. It requires Objective-C++ compilation for the implementation file.

### Device and Render Pass Setup

Initialize with `ImGui_ImplMetal_Init(&init_info)` (lines 45–46), supplying a `MTLDevice`, `MTLCommandQueue`, and optionally a `CAMetalLayer`. You must create and manage the `MTLRenderPassDescriptor` yourself—ImGui does not own the render targets.

### Frame Submission

Call `ImGui_ImplMetal_NewFrame()` (lines 46–48) before the ImGui frame, and `ImGui_ImplMetal_RenderDrawData(draw_data, command_buffer, render_pass_descriptor)` (lines 48–50) to encode draw calls. The render pass descriptor tells Metal which color and depth attachments to use.

```cpp
ImGui_ImplMetal_NewFrame();
ImGui::NewFrame();
// ... UI construction ...
ImGui::Render();
ImGui_ImplMetal_RenderDrawData(
    ImGui::GetDrawData(), 
    commandBuffer, 
    currentRenderPassDescriptor
);

```

### Image Registration

Register Metal textures with `ImGui_ImplMetal_AddTexture(MTLTexture *texture)` (lines 51–53) to obtain an `ImTextureID` for use in your UI.

## Complete Integration Example

Below is a minimal, API-agnostic integration pattern. Replace the Vulkan-specific calls with their DX12 or Metal equivalents as needed.

```cpp
// 1. Create context
ImGui::CreateContext();

// 2. Initialize renderer (Vulkan example)
ImGui_ImplVulkan_InitInfo info = {};
// ... fill info with device, queue, etc. ...
ImGui_ImplVulkan_Init(&info);

// 3. Main loop
while (running) {
    // Platform event polling (GLFW/SDL/etc.)
    
    // Start frame
    ImGui_ImplVulkan_NewFrame();
    ImGui::NewFrame();
    
    // Build UI
    static bool show_demo = true;
    ImGui::ShowDemoWindow(&show_demo);
    
    // Render
    ImGui::Render();
    ImGui_ImplVulkan_RenderDrawData(
        ImGui::GetDrawData(), 
        commandBuffer
    );
    
    // Present swap chain
}

```

## Summary

- **Backend Location:** All renderer backends live under `backends/`—`imgui_impl_vulkan.*`, `imgui_impl_dx12.*`, and `imgui_impl_metal.*`.
- **Initialization:** Populate the API-specific `InitInfo` struct with your device, queue, and render targets, then call the corresponding `Init` function.
- **Frame Lifecycle:** Every frame requires `NewFrame` before `ImGui::NewFrame()` and `RenderDrawData` after `ImGui::Render()`.
- **Resource Ownership:** Your application retains ownership of swap chains, command buffers, and render passes; ImGui only writes geometry and draw commands.
- **Textures:** Use `AddTexture` APIs to register GPU images and receive `ImTextureID` handles for UI rendering.

## Frequently Asked Questions

### Do I need to modify the backend source files to integrate with my engine?

No. According to the `ocornut/imgui` repository, you can copy the backend files directly into your project and compile them unchanged. The backends expose initialization structures and function pointers that allow you to inject your graphics objects without editing the implementation.

### Can I use the Vulkan backend with dynamic rendering instead of legacy render passes?

Yes. Set `UseDynamicRendering = true` in your `ImGui_ImplVulkan_InitInfo` and fill `PipelineInfoMain.PipelineRenderingCreateInfo` with your color attachment formats. This enables Vulkan 1.3’s `VK_KHR_dynamic_rendering` path, eliminating the need for a `VkRenderPass` object.

### How does the DirectX 12 backend handle texture descriptors?

The DX12 backend allocates one SRV descriptor per texture. You must provide `SrvDescriptorAllocFn` and `SrvDescriptorFreeFn` callbacks in `ImGui_ImplDX12_InitInfo` so ImGui can reserve slots in your descriptor heap, or use the legacy fields for single-descriptor setups.

### Is Metal support limited to macOS and iOS?

Yes. The Metal backend (`imgui_impl_metal.mm`) targets Apple platforms exclusively. It requires Objective-C++ compilation and expects you to manage the `CAMetalLayer` and `MTLRenderPassDescriptor` from your application’s view or layer setup.