228 lines
15 KiB
Markdown
228 lines
15 KiB
Markdown
# DaVinci Resolve image — design notes
|
|
|
|
Context for whoever (Claude) touches this Dockerfile next. Simon doesn't need
|
|
to read this — it's implementation reasoning, not usage docs (those are in
|
|
`README.md`).
|
|
|
|
**Update 2026-09-09: the `amd` and `nvidia` targets both build successfully**,
|
|
tested with a real `DaVinci_Resolve_21.1_Linux.run` on Docker Desktop/WSL2
|
|
(Windows host, no distrobox available there). See "Build test" below for
|
|
what was actually verified and how. What's still unverified: an actual
|
|
`distrobox create` + `davinci-run` GUI launch on real Linux/GPU hardware —
|
|
Windows can't test that part of the stack at all. Treat every "High" below
|
|
as "confirmed by an actual build", "Medium/Low" as still resting on prior
|
|
art alone.
|
|
|
|
## Prior art checked before writing this
|
|
|
|
- [zelikos/davincibox](https://github.com/zelikos/davincibox) — Fedora
|
|
toolbox base, actively maintained, tested by its maintainer against real
|
|
AMD/Intel GPUs (no NVIDIA hardware). This is where the base image,
|
|
`davinci-dependencies` package list, the silent-install invocation, and
|
|
the patchelf fix all come from, read as raw files from GitHub (not
|
|
paraphrased from search snippets).
|
|
- [fat-tire/resolve](https://github.com/fat-tire/resolve) — Rocky Linux
|
|
base, raw podman/docker (no distrobox), bakes Resolve into the image at
|
|
**build time** using the same `-i -a -y` installer flags. Cross-checking
|
|
this against davincibox's `setup-davinci` (which uses the same flags, at
|
|
container-runtime instead) is what gave confidence that `-i -a -y` is a
|
|
real, working non-interactive install path and not a guess — two
|
|
independent projects landed on the same flags.
|
|
- Universal Blue / openSUSE forum threads, Blackmagic forum thread: read for
|
|
context, not copied from directly.
|
|
|
|
## Why these choices
|
|
|
|
- **Fedora toolbox base, not Ubuntu (unlike Houdini).** Kept as-is from
|
|
davincibox rather than switched to Ubuntu for consistency with Houdini,
|
|
because it's the only base upstream has actually run real Resolve
|
|
installs against, and it already ships the sudo/user bootstrap distrobox
|
|
expects. The repo convention explicitly allows a different base per app.
|
|
- **Resolve baked in at build time, not via a post-`distrobox create` setup
|
|
script.** davincibox installs Resolve *after* the box exists
|
|
(`setup-davinci`), because it's meant to be a generic base image handed
|
|
out to many users with different Resolve versions. This repo's own
|
|
convention is the opposite: bake the actual software in and push a
|
|
ready-to-run image (see Houdini). Confirmed this is actually possible
|
|
(not just theoretically) by finding fat-tire/resolve, which does exactly
|
|
this — bakes Resolve into a Dockerfile `RUN` step with no display
|
|
attached, using the same installer flags.
|
|
- **`-i -a -y` install flags.** Not documented anywhere by Blackmagic
|
|
directly (as far as this research found) — the confidence here comes from
|
|
two independent community projects (davincibox, fat-tire/resolve) using
|
|
the exact same flags to drive the same `.run`/AppImage installer
|
|
non-interactively. `QT_QPA_PLATFORM=minimal` + `SKIP_PACKAGE_CHECK=1`
|
|
layered on top come from davincibox specifically
|
|
(zelikos/davincibox#35) — fat-tire/resolve doesn't set these, so it's
|
|
possible they're only needed in some environments; kept them since we're
|
|
building with no display at all, which is the case they're meant for.
|
|
- **patchelf fix, copied verbatim including the full library paths.**
|
|
davincibox's `setup-davinci` builds `--add-needed` arguments from full
|
|
paths (`/usr/lib64/libglib-2.0.so.0`, ...), not bare sonames. This looks
|
|
unusual — patchelf's `--add-needed` conventionally takes a soname — but
|
|
it's copied exactly as upstream has it working, rather than "corrected"
|
|
based on how patchelf is normally used elsewhere. If this turns out not to
|
|
work, that's the first thing to check against upstream's current version
|
|
of the script (it may have changed since this was written).
|
|
- **`amd` variant installs both ROCm and Intel's `intel-compute-runtime`.**
|
|
Matches davincibox's single `-opencl` variant, which is the same
|
|
reasoning Houdini's `Dockerfile` uses for "amd variant also works for
|
|
Intel" — no separate Intel target. `mesa-libOpenCL` (rusticl) is removed
|
|
first because it's confirmed (zelikos/davincibox#173) to break ROCm.
|
|
- **`nvidia` variant is untouched (no OpenCL packages added).** Matches
|
|
Houdini's NVIDIA variant shape (nothing baked in, host driver only) but
|
|
the actual runtime wiring differs — see the "NVIDIA gotcha" section in
|
|
`README.md`. davincibox's README documents needing the NVIDIA Container
|
|
Toolkit + CDI device injection (`--device nvidia.com/gpu=all`) rather
|
|
than distrobox's simpler `--nvidia` flag, for reasons not fully explained
|
|
in their docs (something about their toolbox target needing
|
|
`NVIDIA_VISIBLE_DEVICES`/`NVIDIA_DRIVER_CAPABILITIES` env vars set at the
|
|
container level, which `--nvidia`'s driver-file bind-mount alone doesn't
|
|
set up). Not resolved here; flagged as an open question for whoever tests
|
|
this first.
|
|
- **App menu entry uses Resolve's own shipped `.desktop`/icon files**
|
|
(`/opt/resolve/share`, `/opt/resolve/graphics`), unlike Houdini where one
|
|
had to be hand-written from scratch. This is a real difference in what
|
|
each app ships, not an inconsistency to "fix" — davincibox's
|
|
`add-davinci-launcher` script does the same `sed`-based adaptation,
|
|
simplified in the README here since we don't need its toolbox/distrobox
|
|
branching (this repo is distrobox-only) or its `remove` mode.
|
|
- **Not ported from davincibox:** `switcheroo-control` multi-GPU handling
|
|
(`list-gpus`/`switcherooctl launch` wrapping in `run-davinci`) and runtime
|
|
GPU auto-detection in the launcher (`lshw`-based, only needed because
|
|
davincibox ships one image covering all GPU vendors — this repo already
|
|
splits that at build time via `amd`/`nvidia` targets). Both are real
|
|
upstream features, deliberately left out here rather than overlooked —
|
|
add them back from davincibox's `run-davinci` if dual-GPU laptop
|
|
switching turns out to matter.
|
|
|
|
## Build test (2026-09-09)
|
|
|
|
Ran on Docker Desktop (WSL2 backend, Windows host) with the real
|
|
`DaVinci_Resolve_21.1_Linux.run` (free version) placed next to the
|
|
Dockerfile — `docker build --target amd` then `--target nvidia`. No
|
|
distrobox involved (Windows), so this only covers the image build itself,
|
|
not an actual GUI launch.
|
|
|
|
- **Dependency install (`base` stage, both variants): passed clean.** All
|
|
165 packages in `davinci-dependencies` resolved and installed on
|
|
`fedora-toolbox:44` with 0 errors — confirms the list still matches
|
|
current Fedora 44 repos.
|
|
- **Silent install (`-i -a -y`, `QT_QPA_PLATFORM=minimal`,
|
|
`SKIP_PACKAGE_CHECK=1`) actually works at Docker build time, no display
|
|
attached.** Installer output ended with `DaVinci Resolve installed to
|
|
/opt/resolve` / `Done`. Only benign warnings: missing `xdg-icon-resource`/
|
|
`xdg-mime`/`gtk-update-icon-cache` (desktop-integration helpers not
|
|
installed, not needed at build time) and a udev reload failure (no real
|
|
udev/sysfs in a build container — expected). No AppImage magic-byte issue
|
|
hit with this particular `.run` (that workaround, from fat-tire/resolve,
|
|
is still not ported — add it back if a future version's `.run` fails
|
|
`--appimage-extract`).
|
|
- **patchelf fix ran successfully.** `find /opt/resolve/bin -executable
|
|
-type f -exec patchelf ...` reported `patchelf: not an ELF executable`
|
|
for 3 files (non-ELF things under `bin/` with the executable bit set,
|
|
e.g. shell scripts) — harmless, and doesn't fail the build because `find
|
|
-exec cmd {} \;` (semicolon form) does not propagate `cmd`'s exit status
|
|
to `find`'s own. Verified with `patchelf --print-needed` that `resolve`
|
|
and its sibling binaries now carry all 4 `--add-needed` entries.
|
|
- **`ldd /opt/resolve/bin/resolve` (the actual entry point): zero missing
|
|
libraries.** This is the one that matters — confirms the dependency list
|
|
is sufficient for the main binary as actually invoked.
|
|
- **False alarm, worth remembering:** running `ldd` directly on individual
|
|
`.so` files under `/opt/resolve/libs/*.so` in isolation shows dozens of
|
|
"not found" (`libc++.so.1`, every bundled Qt5/OpenCV/Kaldi/OpenEXR lib,
|
|
etc.). This is **not a real problem** — `resolve`'s own RPATH is
|
|
`$ORIGIN/../libs/:$ORIGIN/../libs/Fusion:...` (old-style `DT_RPATH`,
|
|
padded with a long run of `x` characters so Blackmagic's own installer
|
|
can rewrite the real path post-install without changing the binary's
|
|
size — same trick as the `RESOLVE_INSTALL_LOCATION` placeholder in the
|
|
`.desktop` files). `DT_RPATH` on the main executable applies transitively
|
|
to the whole process's library resolution, not just its own direct
|
|
`NEEDED` entries — so at actual runtime, through `resolve`, all of these
|
|
resolve fine. Testing a `.so` file in isolation loses that context and
|
|
produces a misleading "missing" list. **Lesson for next time: to check
|
|
for real missing libraries in an RPATH-based bundle like this one, `ldd`
|
|
only the actual entry point binary, not the library files underneath
|
|
it** — scanning every `.so` individually (the approach that worked for
|
|
Houdini's Qt plugins, which don't use this RPATH trick) gives false
|
|
positives here.
|
|
- **The only genuinely missing library found:** `libcuda.so.1`, needed by
|
|
`libDecoderCUDA.so` (CUDA RAW decode path) — expected and correct, that
|
|
comes from the host NVIDIA driver, not from anything baked into the
|
|
image.
|
|
- **`nvidia` target builds instantly** (shares the cached `base` stage) and
|
|
carries `NVIDIA_VISIBLE_DEVICES=all`/`NVIDIA_DRIVER_CAPABILITIES=all` as
|
|
expected. Its actual GPU passthrough behavior (`--nvidia` vs CDI, see
|
|
README) is still unverified — no NVIDIA hardware available to test from
|
|
here either.
|
|
- Not exercised at all: actual GUI launch, license-free playback, OpenCL
|
|
compute on real AMD/Intel hardware, audio, the app-menu-entry steps,
|
|
Studio+dongle path. All of that needs a real Linux host with distrobox.
|
|
|
|
## Real GUI launch test (2026-09-09)
|
|
|
|
Simon ran `distrobox create` + `davinci-run` for real, `amd` target, on
|
|
actual Linux/GPU hardware (AMD Radeon 680M integrated GPU, `rocm-opencl` +
|
|
`intel-compute-runtime` both present as installed by the `amd` stage) —
|
|
the one thing the Docker Desktop/WSL2 build test above explicitly could not
|
|
cover. Result: **it works.** `davinci-run` launched `/opt/resolve/bin/resolve`,
|
|
which went through the v21 "what's new" popup → Project Manager → Create
|
|
New Project → a Transcode window, all mapped and focused normally under
|
|
Hyprland (XWayland, confirmed via `hyprctl clients`). This is the first
|
|
confirmation of the full stack (distrobox create → box → `davinci-run` →
|
|
real GPU) actually working end to end, not just the image build.
|
|
|
|
- **False alarm during my own debugging, worth recording so it isn't
|
|
re-chased:** my first few attempts ran `davinci-run | head -N` to inspect
|
|
output, which reproduced `Failed to create application support
|
|
directories` every time (plus `log4cxx: No appender could be found`).
|
|
This looked exactly like a real startup bug and cost real debugging time
|
|
(strace, permission checks, `getpwuid`/nsswitch checks, `QT_PLUGIN_PATH`
|
|
host-env-leak theory — all dead ends). The actual cause: `head -N` closes
|
|
its end of the pipe after N lines, sending Resolve's process group a
|
|
SIGPIPE that kills a startup helper before it finishes setting up its
|
|
app-support directories. Piping through `tail` instead (which reads to
|
|
EOF, no early close) or not piping at all made the error disappear
|
|
immediately, every time. **Lesson: never pipe `davinci-run`'s stdout
|
|
through something that can close its read end early (`head`, `sed -q`,
|
|
etc.) when diagnosing a "failed to start" report — redirect to a file or
|
|
use `tail` instead, or the pipe itself becomes the bug.**
|
|
- Real host environment leaking into the box (Nix/home-manager: `QT_PLUGIN_PATH`,
|
|
`PATH`, `XDG_DATA_DIRS` all full of `/nix/store/...` entries) turned out
|
|
to be harmless for Resolve itself — it uses its own bundled Qt5 via
|
|
`DT_RPATH` regardless of `QT_PLUGIN_PATH`. Not something `davinci-run`
|
|
needs to guard against.
|
|
- **No audio confirmed for real, as predicted in the README's "Known
|
|
gotchas":** `ResolveDebug.txt` is full of `ALSA lib dlmisc.c:339:
|
|
(snd_dlobj_cache_get0) [error.core] Cannot open shared library
|
|
libasound_module_pcm_pipewire.so` — the host's PipeWire ALSA plugin is a
|
|
Nix store path the box can't see. Not investigated further since the
|
|
README already documents the fix (swap to `alsa-plugins-pulseaudio`
|
|
inside the box); this just confirms the gotcha is real, not hypothetical.
|
|
- Not covered by this test: actually opening/editing a real project,
|
|
playback, OpenCL compute correctness, NVIDIA path (this host is AMD),
|
|
Studio+dongle, app-menu-entry end-to-end.
|
|
|
|
## What's still unverified after this build test
|
|
|
|
| Area | Confidence | Note |
|
|
|---|---|---|
|
|
| Base image + dependency list | High | Build-confirmed against Fedora 44 repos, 2026-09-09. |
|
|
| `-i -a -y` + `QT_QPA_PLATFORM=minimal` + `SKIP_PACKAGE_CHECK=1` at Docker build time, no display | High | Build-confirmed: installer completed and reported success. |
|
|
| patchelf fix (paths, not sonames) | High | Build-confirmed: ran without failing the build, `--print-needed` shows the entries landed on `resolve` and siblings. |
|
|
| Dependency sufficiency for the actual entry point (`ldd /opt/resolve/bin/resolve`) | High | Build-confirmed: zero missing libraries. |
|
|
| AppImage magic-bytes workaround (fat-tire's Arch/Manjaro-specific issue) | Not ported | Not hit with the 21.1 `.run` tested here; add back from fat-tire/resolve's Dockerfile if a future version's `--appimage-extract` fails on it. |
|
|
| `amd` variant (ROCm + Intel packages install) | High | Build-confirmed at Docker-build time, and now real-hardware-confirmed: `davinci-run` launched successfully on an AMD Radeon 680M host with `rocm-opencl`/`intel-compute-runtime` installed, 2026-09-09. OpenCL kernel *compute correctness* (actual color-science rendering) still not specifically checked — only that Resolve starts and its windows render normally. |
|
|
| `nvidia` variant / `--nvidia` vs CDI | Low | Still a real open question — see "NVIDIA gotcha" in README. Image builds fine either way; only the *runtime* GPU passthrough method is unverified. The 2026-09-09 real-hardware test above was AMD, not NVIDIA. |
|
|
| App menu entry steps | Medium | Directly adapted from a working upstream script, simplified; confirmed the `.desktop` files exist at the documented paths (`/opt/resolve/share/*.desktop`), not run end-to-end. |
|
|
| Actual GUI launch (`distrobox create` + `davinci-run`) | High | Real-hardware-confirmed 2026-09-09 on AMD/Hyprland: reached Project Manager → Create New Project → Transcode window, all mapped/focused normally. See "Real GUI launch test" above. |
|
|
| Audio | Low (confirmed broken as predicted) | `ResolveDebug.txt` shows the exact `libasound_module_pcm_pipewire.so` failure the README's "Known gotchas" section already predicted. Fix documented there, not yet applied/tested. |
|
|
| Rendering correctness / playback / licensing / project work | Untested | The 2026-09-09 test only confirmed the app starts and its dialogs render — no project was opened, no clip played back, no license flow exercised. |
|
|
|
|
## Repo-wide conventions
|
|
|
|
See the top-level `../README.md` for the multi-software repo convention
|
|
(one self-contained folder per app, shared registry setup notes) — that
|
|
file is meant for Simon to read; this one and `../houdini/CLAUDE.md` are for
|
|
future-Claude context.
|