ImTextureID and ImTextureRef in Dear ImGui: A Complete Guide to Displaying Custom Images
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 (lines 321-381), it is defined by default as:
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 (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 (lines 321-381), it contains two mutually exclusive members:
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:
- Command Recording: The
ImTextureRefis stored in anImDrawCmdstructure within the draw list. - Backend Resolution: During
RenderDrawData, the backend extracts the actualImTextureIDusing the logic:tex_ref._TexData ? tex_ref._TexData->TexID : tex_ref._TexID. - Native Binding: The backend binds the texture using its native API (e.g.,
glBindTexturefor OpenGL orvkCmdBindDescriptorSetsfor Vulkan).
This resolution occurs in the internal rendering functions referenced in 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 (line 7), you can safely cast your OpenGL texture to the ImGui type:
// 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 (line 5), use ImGui_ImplVulkan_AddTexture to register your image view and sampler:
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 (lines 363-366):
// 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 (line 13):
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
ImTextureIDis a backend-specific GPU handle (defaulting toImU64) representing textures already uploaded to the graphics driver.ImTextureRefis a wrapper struct containing either anImTextureIDor anImTextureDatapointer, 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 requiresImGui_ImplVulkan_AddTexture, and SDL2 usesreinterpret_castfromSDL_Texture*. - Resolution: During rendering, backends extract the raw
ImTextureIDfromImTextureRefvia the_TexData ? _TexData->TexID : _TexIDpattern.
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.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →