# ImTextureID and ImTextureRef in Dear ImGui: A Complete Guide to Displaying Custom Images

> Understand ImTextureID and ImTextureRef in Dear ImGui for displaying custom images. Learn how these handles simplify texture integration in your GUI applications.

- Repository: [omar/imgui](https://github.com/ocornut/imgui)
- Tags: deep-dive
- Published: 2026-07-29

---

**Dear ImGui uses `ImTextureID` as a low-level, backend-specific handle for GPU textures, while `ImTextureRef` is a higher-level wrapper (introduced in v1.92) that accepts either an `ImTextureID` or an `ImTextureData` pointer, serving as the standard input for `ImGui::Image` and related drawing functions.**

Dear ImGui (ocornut/imgui) provides a renderer-agnostic way to display custom images in your UI through two distinct texture identifier types. Understanding the relationship between `ImTextureID` and `ImTextureRef` is essential for correctly binding OpenGL textures, Vulkan descriptor sets, or DirectX resources to your interface elements.

## Understanding the Two Texture Types

### What Is ImTextureID?

`ImTextureID` is the low-level primitive that represents a backend-specific texture handle already uploaded to the GPU. According to the source code in [`imgui.h`](https://github.com/ocornut/imgui/blob/main/imgui.h) (lines 321-381), it is defined by default as:

```cpp
typedef ImU64 ImTextureID;

```

This 64-bit unsigned integer accommodates various backend types: `GLuint` for OpenGL, `ID3D11ShaderResourceView*` for DirectX 11, `VkDescriptorSet` for Vulkan, or `SDL_Texture*` for SDL2. Backends may redefine this type in [`imconfig.h`](https://github.com/ocornut/imgui/blob/main/imconfig.h) (for example, `#define ImTextureID MyTextureType*`) if a pointer type is more appropriate than an integer handle.

### What Is ImTextureRef?

`ImTextureRef` is a structured wrapper introduced to unify the public API. As implemented in [`imgui.h`](https://github.com/ocornut/imgui/blob/main/imgui.h) (lines 321-381), it contains two mutually exclusive members:

```cpp
struct ImTextureRef {
    ImTextureData* _TexData;    // Pointer to internal atlas data
    ImTextureID    _TexID;      // Direct backend handle
};

```

Since v1.92, high-level functions like `ImGui::Image()` accept `ImTextureRef` rather than raw `ImTextureID`. This allows the API to handle both user-created textures and internal `ImTextureData` objects (such as font atlas entries) through a single interface.

### Comparison of Identifier Types

| Identifier | Purpose | Typical Backend Type | Storage |
|------------|---------|---------------------|---------|
| **`ImTextureID`** | Low-level GPU handle | `GLuint`, `VkDescriptorSet`, `ID3D11ShaderResourceView*` | `ImU64` (or redefined pointer) |
| **`ImTextureRef`** | High-level API wrapper | Forwards to `ImTextureID` | Struct with `_TexData` and `_TexID` fields |

## How Dear ImGui Processes Texture References

When you call `ImGui::Image(ImTextureRef tex, ...)`, the rendering pipeline handles the abstraction as follows:

1. **Command Recording**: The `ImTextureRef` is stored in an `ImDrawCmd` structure within the draw list.
2. **Backend Resolution**: During `RenderDrawData`, the backend extracts the actual `ImTextureID` using the logic: `tex_ref._TexData ? tex_ref._TexData->TexID : tex_ref._TexID`.
3. **Native Binding**: The backend binds the texture using its native API (e.g., `glBindTexture` for OpenGL or `vkCmdBindDescriptorSets` for Vulkan).

This resolution occurs in the internal rendering functions referenced in [`imgui_internal.h`](https://github.com/ocornut/imgui/blob/main/imgui_internal.h) (lines 3748-3755), ensuring that font atlas textures and user textures follow the same code path.

## Backend-Specific Implementation Examples

### OpenGL: Casting GLuint to ImTextureID

For OpenGL backends, `ImTextureID` represents a `GLuint` texture name. As noted in [`imgui_impl_opengl3.h`](https://github.com/ocornut/imgui/blob/main/imgui_impl_opengl3.h) (line 7), you can safely cast your OpenGL texture to the ImGui type:

```cpp
// Create and upload an OpenGL texture
GLuint gl_tex;
glGenTextures(1, &gl_tex);
glBindTexture(GL_TEXTURE_2D, gl_tex);
// ... upload pixel data with glTexImage2D ...

// Cast to ImTextureID (safe on both 32- and 64-bit platforms)
ImTextureID tex_id = static_cast<ImTextureID>(gl_tex);

// Display the image
ImGui::Image(tex_id, ImVec2(128.0f, 128.0f));

```

### Vulkan: Registering Descriptor Sets

The Vulkan backend requires descriptor set management. As documented in [`imgui_impl_vulkan.h`](https://github.com/ocornut/imgui/blob/main/imgui_impl_vulkan.h) (line 5), use `ImGui_ImplVulkan_AddTexture` to register your image view and sampler:

```cpp
VkSampler sampler = /* your sampler */;
VkImageView image_view = /* your image view */;

// Register with ImGui's descriptor pool
ImTextureID tex_id = ImGui_ImplVulkan_AddTexture(
    sampler, 
    image_view, 
    VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
);

// Use in UI
ImGui::Image(tex_id, ImVec2(256.0f, 256.0f));

```

### Modern API Using ImTextureRef (v1.92+)

To use the preferred modern interface, convert your `ImTextureID` to an `ImTextureRef` using the helper defined in [`imgui.h`](https://github.com/ocornut/imgui/blob/main/imgui.h) (lines 363-366):

```cpp
// Assuming you have a valid ImTextureID from any backend
ImTextureID tex_id = /* your backend handle */;

// Convert to ImTextureRef
ImTextureRef tex_ref;
tex_ref._TexData = nullptr;  // Not using internal atlas data
tex_ref._TexID = tex_id;

// Alternative: use the inline helper function
inline ImTextureRef ImTextureRefFromID(ImTextureID id) {
    ImTextureRef ref = { ._TexData = nullptr, ._TexID = id };
    return ref;
}

ImTextureRef my_ref = ImTextureRefFromID(tex_id);
ImGui::Image(my_ref, ImVec2(64.0f, 64.0f));

```

### SDL2 Renderer: Using SDL_Texture*

The SDL2 backend treats `SDL_Texture*` pointers directly as `ImTextureID`, as indicated in [`imgui_impl_sdlrenderer2.h`](https://github.com/ocornut/imgui/blob/main/imgui_impl_sdlrenderer2.h) (line 13):

```cpp
SDL_Texture* sdl_tex = IMG_LoadTexture(renderer, "image.png");
if (sdl_tex) {
    ImTextureID tex_id = reinterpret_cast<ImTextureID>(sdl_tex);
    ImGui::Image(tex_id, ImVec2(200.0f, 150.0f));
}

```

## Summary

- **`ImTextureID`** is a backend-specific GPU handle (defaulting to `ImU64`) representing textures already uploaded to the graphics driver.
- **`ImTextureRef`** is a wrapper struct containing either an `ImTextureID` or an `ImTextureData` pointer, used by the public API since v1.92 to support both user textures and internal atlas data.
- **Casting**: OpenGL uses `static_cast<ImTextureID>(GLuint)`, Vulkan requires `ImGui_ImplVulkan_AddTexture`, and SDL2 uses `reinterpret_cast` from `SDL_Texture*`.
- **Resolution**: During rendering, backends extract the raw `ImTextureID` from `ImTextureRef` via the `_TexData ? _TexData->TexID : _TexID` pattern.

## Frequently Asked Questions

### What is the difference between ImTextureID and ImTextureRef?

`ImTextureID` is the low-level primitive (typically a 64-bit integer or pointer) that directly represents a GPU texture handle. `ImTextureRef` is a higher-level C++ struct introduced in v1.92 that can hold either an `ImTextureID` or a pointer to `ImTextureData` (used for font atlases). The public drawing functions like `ImGui::Image()` accept `ImTextureRef` to provide flexibility while maintaining a simple API surface.

### How do I convert my graphics API handle to ImTextureID safely?

For OpenGL, use `static_cast<ImTextureID>(your_gluint)`. For Vulkan, call `ImGui_ImplVulkan_AddTexture()` to obtain a valid `ImTextureID`. For DirectX, cast your shader resource view pointer directly. For SDL2, use `reinterpret_cast<ImTextureID>(your_sdl_texture)`. Always ensure the texture remains valid (not deleted) for the duration of the frame where you submit draw commands referencing it.

### Can ImTextureRef reference the built-in font atlas?

Yes. When you want to draw using the default font atlas, you can create an `ImTextureRef` pointing to the atlas's `ImTextureData` structure (accessible via `ImGui::GetIO().Fonts->TexData`). Set `_TexData` to the atlas pointer and leave `_TexID` as zero; the renderer will resolve it to the actual GPU texture during the draw command processing.

### Why does my texture appear white or black in ImGui?

A white or black square typically indicates that the `ImTextureID` passed to ImGui does not resolve to a valid GPU resource in your backend. Verify that: (1) The texture handle is valid and not zero, (2) For Vulkan, you registered the descriptor set using `ImGui_ImplVulkan_AddTexture`, (3) The texture remains bound and not deleted during `RenderDrawData`, and (4) Your pixel data upload completed successfully before the ImGui draw call.