This is a fork of hoffstadt/DearPyGui that adds zero-copy texture interop with external GPU APIs (Vulkan, slangpy, etc.) on the Linux/OpenGL backend.
Stock DearPyGui's only public texture API is add_raw_texture, which uploads
a CPU buffer (numpy array) to GL each frame. That's a bandwidth ceiling: a
1024² RGBA32F frame is 16 MB CPU→GPU per frame, plus a GPU→CPU readback if
the producer is also on the GPU.
This fork lets you skip the round-trip. A producer (e.g. slangpy) allocates a
Vulkan image with VK_KHR_external_memory_fd and exports an opaque fd; you
hand that fd to add_raw_texture(..., external_memory_fd=...) and DPG
imports it via GL_EXT_memory_object_fd. The GL texture and the Vulkan
storage image are now the same physical GPU allocation — the producer
writes, ImGui samples, no copies.
mvRawTextureaccepts two new keyword args:external_memory_fd(int) andexternal_memory_size(int, bytes). Whenexternal_memory_fd >= 0, the GL texture is created once viaglImportMemoryFdEXT+glTexStorageMem2DEXTand the per-frame CPU upload path is skipped entirely.- New utility
LoadTextureFromExternalMemoryFdinmvUtilities_linux.cpp. - Stubs on Windows/macOS (return
ImTextureID_Invalid). The same idea ports to D3D11 (OpenSharedHandle) and Metal (IOSurface); patches welcome.
Everything else is unchanged — existing add_raw_texture calls keep their
old behavior.
- Linux with
GL_EXT_memory_objectandGL_EXT_memory_object_fd(Mesa, recent NVIDIA). - A producer that exports opaque-fd handles (slangpy ≥ 0.41, raw Vulkan,
CUDA's
cudaExternalMemory, etc.).
import dearpygui.dearpygui as dpg
import slangpy as spy
W, H = 1024, 1024
# 1. slangpy makes a Vulkan storage image marked as exportable.
device = spy.create_device(type=spy.DeviceType.vulkan, include_paths=["shaders"])
texture = device.create_texture(
format=spy.Format.rgba8_unorm,
width=W, height=H,
usage=(spy.TextureUsage.unordered_access
| spy.TextureUsage.shader_resource
| spy.TextureUsage.shared),
)
fd = int(texture.shared_handle.value) # opaque-fd from VK_KHR_external_memory_fd
size_bytes = int(texture.memory_usage.device) # driver-reported allocation size
# 2. DPG imports the same memory as a GL texture.
dpg.create_context(); dpg.create_viewport(width=W+32, height=H+80); dpg.setup_dearpygui()
with dpg.texture_registry():
dpg.add_raw_texture(W, H, (), # default_value ignored
format=dpg.mvFormat_Float_rgba,
external_memory_fd=fd,
external_memory_size=size_bytes,
tag="shared_tex")
with dpg.window(label="zero-copy", tag="w"):
dpg.add_image("shared_tex")
dpg.set_primary_window("w", True); dpg.show_viewport()
# 3. slangpy writes; DPG samples. Same memory.
kernel = device.create_compute_kernel(device.load_program("render", ["main"]))
import time; t0 = time.perf_counter()
while dpg.is_dearpygui_running():
kernel.dispatch(thread_count=spy.uint3(W, H, 1),
vars={"output": texture, "uniforms": {"resolution": spy.uint2(W, H),
"time": time.perf_counter() - t0}})
device.wait_for_idle() # CPU sync; replace with VK<->GL semaphores for max speed
dpg.render_dearpygui_frame()
dpg.destroy_context()The companion render.slang here can be any compute shader writing
RWTexture2D<float4> — see the spy-imgui/ example repo.
git clone --recursive <this fork>
cd DearPyGui
mkdir cmake-build-local && cd cmake-build-local
cmake .. -DMVDIST_ONLY=True -DMVDPG_VERSION=2.3 -DMV_PY_VERSION=3.12 -DCMAKE_BUILD_TYPE=Release
cmake --build . -j$(nproc)
# drop the resulting _dearpygui.so over the one in your venv:
cp DearPyGui/_dearpygui.so /path/to/venv/lib/python3.12/site-packages/dearpygui/- Sync is the user's job. The example above CPU-syncs with
device.wait_for_idle(). For real performance use external semaphores — slangpy exposesFence.shared_handle, GL hasglGenSemaphoresEXT/glWaitSemaphoreEXT. Without that, the Vulkan queue stalls each frame. - Pass the driver-reported allocation size, not
W*H*bpp. Tiled images get padded for alignment. With slangpy usetexture.memory_usage.device(Vulkan reports the same number viaVkMemoryRequirements.size). If you hitGL_INVALID_VALUE(0x501) fromglTexStorageMem2DEXT, that's what's wrong. - Format must match exactly. The fork imports as
GL_RGBA8(orGL_RGB8for 3-component). Other formats need to be added toLoadTextureFromExternalMemoryFd. - Linux/OpenGL only. Windows and macOS fall back to a no-op stub.
MIT, same as upstream.