Historical recipe — not current setup guidance. Measurements and implementation links below belong to their original workload and revision. Deployment labels and defaults may be obsolete. Use the reviewed performance recipes; browse historical evidence.
AVPlumber · Mixer optimization cookbook
Unused GPU contexts
Implementation links are pinned to develop at c20464a5 (2026-10-09). The mixer has changed since; this page was checked against develop at 8fa15c92 on 2026-10-13. Measurements retain their original workload and scope. Watch the current 192-input L4 demo.
Current scope. Unused context removal remains in place. The custom v210 uploader was replaced by FFmpeg; it is no longer a CUDAState flag reader. Memory figures below are historical estimates, not a new VRAM measurement.
Two GPU contexts held device memory but drew nothing: an OpenGL context in every browser importer, and a CUDA context created at process start. The mixer image removes both and runs live on the test host. A code audit of the other apps that use avplumber found nothing that relied on either context.
Status: Implemented1. The GL context in each browser importer
Each browser page has its own drm_prime_to_cuda node. The setup allows up to 40 browser pages at every frame rate (five browser workers of eight windows); the memory figures on this page were estimated for 32. Importing a page frame needs only an EGL display: eglCreateImage already takes EGL_NO_CONTEXT, and CUDA registers the EGL image directly. The node still created an OpenGL context and a 2×2 pbuffer, and made it current before every import. Nothing drew with it. Both importers, drm_prime_to_cuda and drm_prime_to_egl_image, now share one display-only setup, EglDmabufDisplay.
2. The global CUDA context
A constructor in src/cuda.cpp ran at process start and created a CUDA context on device 0. Every CUDA node runs in the context of its hwaccel device instead. The only thing other code read was the has_errors flag, which does not need a context. A later cleanup also dropped CUDAState::device, which nothing read once the context was gone: start-up now only counts devices, and CUDAState holds just has_errors.
cuDeviceGet(0) step has since gone too.At a glance
- What
drm_prime_to_cudakeeps only an initialized EGL display: no GL context, no pbuffer, noeglMakeCurrentper import.init_global_cudastops callingcuCtxCreate; it only counts devices and sets the error flag, andCUDAStateno longer has adevicefield. - WhyNeither context drew anything, but each held device memory. The importer's context existed once per browser page: 32 times in the show it was estimated for, up to 40 in the setup's 110-input shows.
drm_prime_to_egl_imagealready imports the same DMA-BUFs without a GL context. - Latency0 frames on program and on command-to-screen: neither context sat on the frame path. Each new DMA-BUF import (a cache miss, not every frame) skips one
eglMakeCurrentcall on the CPU; not measured. - Side effectsLess VRAM held per process, so more headroom for browser pages and compositors. No thread has a CUDA context current at start any more: code that called CUDA without binding its hwaccel context would now fail instead of running on the hidden global one. The start-up error log reads "failed to find a CUDA device".
- Cost0 nodes, 0 queues, 0 threads. Net −84 lines (13 added, 97 removed). Frees an estimated ~150 MB (100–250 MB, unmeasured) across 32 importers, about 190 MB for 40 if it scales in proportion (also an estimate), plus 60–100 MB (estimate) for the global context. For scale: a CUDA context with no nodes on it measured 186 MiB in a mixer process on an L4 on 2026-10-14; the removed context itself was never measured. One fewer
eglMakeCurrentper import on the CPU; GPU work unchanged. - RiskBoth files are shared avplumber code that other apps use. The code audit of those apps (below) found nothing that relied on the global context being current on the loading thread, and no GL call remains in the importer, including the
zero_copypath. A downstream smoke script is in the tree (tests/downstream/); whether it has run against a build with these removals is not recorded. - Switch it offThere is no runtime flag; the code is deleted. Reverting means restoring the removed lines and rebuilding. If a downstream smoke run finds a behaviour change, the removals get gated behind an option or dropped.
Where in the code
- src/nodes/hwaccel/EglDmabufDisplay.hpp: the display-only setup both importers share; the comment explains why.
- src/nodes/hwaccel/drm_prime_to_cuda.cpp:
ensureEGLopens it. - drm_prime_to_cuda.cpp:
eglCreateImagewithEGL_NO_CONTEXT; source registers the image with CUDA in the hwaccel context. - drm_prime_to_cuda.cpp: the destructor; the display is process-global and never terminated.
- The other importer: src/nodes/hwaccel/drm_prime_to_egl_image.cpp and source, the same display-only import.
- src/cuda.cpp: no context and no device handle at start, only
cuDeviceGetCountandhas_errors; src/cuda.hpp:CUDAStateholds onlyhas_errors. - Current flag readers: cuda_to_egl_image.cpp, nvof_fruc.cpp.
- Docs: NODES.md · drm_prime_to_cuda; the browser window counts are in capacity.md · Mixer demo capacity; docker-compose/mixer/compose.yaml sets 40 windows, eight per worker (Source limits by mode and frame rate).
Historical deployment note. Compatibility audit (2026-10-01): two downstream applications pin avplumber as a submodule, their CUDA nodes make their own hwaccel context current before any CUDA call, none reads the removed global_cuda fields, and their runtime Python runs no CUDA of its own. Whether a smoke run of both was made after they took the change is not recorded. Source links above identify the reviewed revision.