#!/usr/bin/env bash # ============================================================================== # DaVinci Resolve Installer for openSUSE Tumbleweed # # Installs DaVinci Resolve (19/20, free or Studio) on openSUSE Tumbleweed. # Tumbleweed is a rolling-release distro that's always on the bleeding edge, # which means it often has newer library versions than Resolve expects. # # This script handles several Tumbleweed-specific compatibility issues: # # 1. gdk-pixbuf2 — Tumbleweed's version is too new for Resolve's bundled # Qt libraries. We fetch a compatible version from Fedora's archives # and place it in Resolve's lib directory. # # 2. GLib replacement — Same as other distros: Resolve's bundled GLib # conflicts with the system version. We replace it with system GLib. # # 3. OpenCL symlink — Resolve looks for libOpenCL.so.1 in its own lib # directory. We symlink the system's OpenCL there. # # 4. libtiff shim — Tumbleweed ships libtiff.so.6, but Resolve wants # libtiff.so.5. We create a compatibility symlink. # # 5. APR libraries — Apache Portable Runtime libs that Resolve's internal # database engine sometimes needs on Tumbleweed. # # 6. XWayland wrapper — Forces Resolve to run under X11 (via XWayland) # since it doesn't support native Wayland. # # Works for Resolve 19 and 20 (free and Studio editions). # # Prerequisites: # - openSUSE Tumbleweed with NVIDIA drivers installed # - DaVinci Resolve ZIP or .run downloaded to ~/Downloads/ # # Usage: # sudo ./install-resolve-tw.sh # # or specify a file directly: # sudo ./install-resolve-tw.sh /path/to/DaVinci_Resolve_Linux.zip # ============================================================================== # Ensure we're running in bash (not sh/dash) [ -n "${BASH_VERSION:-}" ] || exec /usr/bin/env bash "$0" "$@" set -euo pipefail # Add sbin paths — some tools like ldconfig live in /sbin on openSUSE export PATH="$PATH:/sbin:/usr/sbin" # Enable debug mode with DEBUG=1 for verbose output [[ "${DEBUG:-0}" == "1" ]] && set -x # Coloured logging helpers for easy visual scanning of output say() { echo -e "\033[1;32m==>\033[0m $*"; } warn() { echo -e "\033[1;33m[!]\033[0m $*"; } err() { echo -e "\033[1;31m[ERROR]\033[0m $*"; } have() { command -v "$1" >/dev/null 2>&1; } # zypper wrapper — --no-recommends keeps the install lean, || true prevents # a missing optional package from killing the script pkg_install() { sudo zypper -n in --no-recommends "$@" || true; } # Resolve the real user's home directory for finding the ZIP in ~/Downloads/ TARGET_USER="${SUDO_USER:-$USER}" TARGET_HOME="$(getent passwd "$TARGET_USER" | cut -d: -f6)" USR_APP_DIR="$TARGET_HOME/.local/share/applications" # Track temp dirs and X11 auth changes for cleanup on exit WORKDIR="" XHOST_ADDED="" # Cleanup handler — removes temp extraction directory and revokes X11 root # access that we may have granted for the GUI installer cleanup() { [[ -n "$WORKDIR" && -d "$WORKDIR" ]] && rm -rf "$WORKDIR" [[ -n "$XHOST_ADDED" ]] && xhost -SI:localuser:root >/dev/null 2>&1 || true } trap cleanup EXIT # Auto-detect the newest Resolve installer in ~/Downloads/. Checks for # both .zip and .run files, preferring .zip (more common download format). pick_latest() { local z r z=$(ls -t "$TARGET_HOME"/Downloads/DaVinci_Resolve*_Linux.zip 2>/dev/null | head -n1 || true) r=$(ls -t "$TARGET_HOME"/Downloads/DaVinci_Resolve*_Linux.run 2>/dev/null | head -n1 || true) [[ -n "$z" ]] && { echo "$z"; return; } [[ -n "$r" ]] && { echo "$r"; return; } echo "" } # -------- inputs ---------- SRC="${1:-}" [[ -z "$SRC" ]] && SRC="$(pick_latest)" [[ -n "$SRC" ]] || { err "Give a path to DaVinci Resolve Linux .zip or .run (or put it in ~/Downloads)."; exit 1; } [[ -e "$SRC" ]] || { err "File not found: $SRC"; exit 1; } # ==================== Dependencies ==================== # # Install runtime libraries that Resolve needs. Tumbleweed uses zypper # as its package manager. Key packages: # libOpenCL1: OpenCL support for GPU-accelerated processing # libjpeg62: JPEG library (Resolve uses the older ABI) # libX11-xcb1 + xcb-*: X11/XCB protocol libraries for display # libglib/gio/etc: GLib stack (system versions to replace bundled ones) # libapr1/util: Apache Portable Runtime (Resolve's DB engine needs these) say "Installing runtime tools + common libs…" sudo zypper -n ref || true RUNTIME_PKGS=( unzip xhost curl rpm cpio xwayland desktop-file-utils xdg-utils libOpenCL1 libjpeg62 libX11-xcb1 libxcb-xinerama0 libxkbcommon-x11-0 libxcb-keysyms1 libxcb-icccm4 libxcb-cursor0 libxcb-xfixes0 libxcb-randr0 libxcb-shape0 libglib-2_0-0 libgobject-2_0-0 libgmodule-2_0-0 libgio-2_0-0 libgthread-2_0-0 libapr1-0 libapr-util1-0 # APR libs Resolve sometimes needs on TW ) pkg_install "${RUNTIME_PKGS[@]}" # Ensure gthread exists (blackmagic GUI installer needs it) if ! ldconfig -p 2>/dev/null | grep -q 'libgthread-2\.0\.so\.0'; then pkg_install libgthread-2_0-0 fi # -------- prepare installer -------- RUN_PATH="" if [[ "$SRC" == *.run ]]; then RUN_PATH="$(readlink -f "$SRC")" elif [[ "$SRC" == *.zip ]]; then say "Validating ZIP…" unzip -tqq "$SRC" >/dev/null 2>&1 || { err "ZIP CRC failed. Re-download from Blackmagic."; exit 1; } BASE="${XDG_CACHE_HOME:-$TARGET_HOME/.cache}/resolve-installer" mkdir -p "$BASE" WORKDIR="$(mktemp -d -p "$BASE")" say "Extracting…" unzip -q "$SRC" -d "$WORKDIR" RUN_PATH="$(find "$WORKDIR" -maxdepth 3 -type f -name 'DaVinci_Resolve*_Linux.run' | head -n1 || true)" [[ -n "$RUN_PATH" && -f "$RUN_PATH" ]] || { err "Could not find DaVinci_Resolve*_Linux.run inside ZIP."; exit 1; } else err "Unsupported file type: $SRC" fi say "Using installer: $RUN_PATH" # ==================== Run Installer ==================== # # Blackmagic's installer is a GUI application. We try running it as the # current user first. If that doesn't result in /opt/resolve/bin/resolve # being created (e.g. permission denied writing to /opt), we retry with # sudo while passing through the display environment variables so the # GUI can still render. # # QT_QPA_PLATFORM=xcb forces the installer to use X11 (not Wayland). # SKIP_PACKAGE_CHECK=1 bypasses Resolve's distro check (it doesn't # recognise openSUSE as a supported distro). say "Running Blackmagic installer (user)…" chmod +x "$RUN_PATH" || true set +e env QT_QPA_PLATFORM=xcb SKIP_PACKAGE_CHECK=1 "$RUN_PATH" RC_USER=$? set -e say "User-run exit code: $RC_USER" if [[ ! -x /opt/resolve/bin/resolve ]]; then if [[ -n "${DISPLAY:-}" ]] && have xhost; then xhost +SI:localuser:root >/dev/null 2>&1 && XHOST_ADDED=1 || true fi say "Running Blackmagic installer (sudo fallback)…" set +e sudo -E env DISPLAY="${DISPLAY:-:0}" XAUTHORITY="${XAUTHORITY:-$HOME/.Xauthority}" \ XDG_RUNTIME_DIR="/run/user/$(id -u "$TARGET_USER")" \ QT_QPA_PLATFORM=xcb SKIP_PACKAGE_CHECK=1 "$RUN_PATH" RC_SUDO=$? set -e say "Sudo-run exit code: $RC_SUDO" fi [[ -d /opt/resolve/libs ]] || { err "/opt/resolve not present; installer likely cancelled."; exit 1; } # ==================== Tumbleweed-Specific Fixes ==================== # # gdk-pixbuf2 fix: # Tumbleweed's gdk-pixbuf2 is too new for Resolve's bundled Qt libraries # (ABI mismatch causes crashes). The workaround is to grab a compatible # version from Fedora's package archives and place it in Resolve's lib # directory. We try archived Fedora 38/40 builds first, then fall back # to scraping Rawhide for the latest version. say "Applying gdk-pixbuf + GLib + OpenCL + APR tweaks for Tumbleweed…" tmp="$(mktemp -d)" rpmfile="$tmp/gdk.rpm" fetch_ok="" # Try stable archived Fedora builds first (x86_64) for url in \ "https://archive.fedoraproject.org/pub/archive/fedora/linux/releases/38/Everything/x86_64/os/Packages/g/gdk-pixbuf2-2.42.10-2.fc38.x86_64.rpm" \ "https://archive.fedoraproject.org/pub/archive/fedora/linux/releases/40/Everything/x86_64/os/Packages/g/gdk-pixbuf2-2.42.10-8.fc40.x86_64.rpm" \ ; do if curl -fsSL -o "$rpmfile" "$url"; then fetch_ok="1"; break; fi done # Last resort: scrape Rawhide index for the latest gdk-pixbuf2 x86_64 rpm if [[ -z "$fetch_ok" ]]; then idx="https://dl.fedoraproject.org/pub/fedora/linux/development/rawhide/Everything/x86_64/os/Packages/g/" html="$(curl -fsSL "$idx" || true)" cand="$(printf "%s" "$html" | grep -o 'gdk-pixbuf2-[^\" ]*\.x86_64\.rpm' | head -n1 || true)" if [[ -n "$cand" ]]; then curl -fsSL -o "$rpmfile" "${idx}${cand}" && fetch_ok="1" fi fi if [[ -n "$fetch_ok" ]]; then say "Extracting Fedora gdk-pixbuf2 into /opt/resolve/libs…" ( cd "$tmp" && rpm2cpio "$rpmfile" | cpio -idmv >/dev/null 2>&1 ) if [[ -d "$tmp/usr/lib64" ]]; then sudo cp -vr "$tmp/usr/lib64/"* /opt/resolve/libs/ || true else warn "No usr/lib64 in RPM payload — skipping copy." fi else warn "Could not fetch a Fedora gdk-pixbuf2 RPM (all URLs failed)." fi rm -rf "$tmp" # Symlink the system's OpenCL library into Resolve's lib directory. # Resolve needs libOpenCL.so.1 for GPU-accelerated processing (effects, # colour grading, neural engine). On Tumbleweed it's usually provided # by ocl-icd (OpenCL Installable Client Driver). ocl="$(ldconfig -p 2>/dev/null | awk '/libOpenCL\.so\.1/{print $4; exit}')" [[ -z "${ocl:-}" && -e /usr/lib64/ocl-icd/libOpenCL.so.1.0.0 ]] && ocl=/usr/lib64/ocl-icd/libOpenCL.so.1.0.0 [[ -n "${ocl:-}" ]] && sudo ln -sf "$ocl" /opt/resolve/libs/libOpenCL.so.1 || warn "libOpenCL.so.1 not found." # Replace Resolve’s bundled GLib with the system version. Same fix as on # Arch/Mint/Rocky — the bundled version is older and conflicts with other # system libraries that Resolve also loads. if ls /lib64/libglib-2.0.* >/dev/null 2>&1; then sudo rm -f /opt/resolve/libs/libglib-2.0.so* || true sudo cp -va /lib64/libglib-2.0.* /opt/resolve/libs/ elif ls /usr/lib64/libglib-2.0.* >/dev/null 2>&1; then sudo rm -f /opt/resolve/libs/libglib-2.0.so* || true sudo cp -va /usr/lib64/libglib-2.0.* /opt/resolve/libs/ fi # libtiff compatibility shim — Tumbleweed ships libtiff.so.6, but Resolve # links against libtiff.so.5. Creating a symlink works because the ABI # is backwards-compatible between these versions. if ! ldconfig -p | grep -q 'libtiff\.so\.5'; then [[ -e /usr/lib64/libtiff.so.6 && ! -e /opt/resolve/libs/libtiff.so.5 ]] && \ sudo ln -s /usr/lib64/libtiff.so.6 /opt/resolve/libs/libtiff.so.5 || true fi # ==================== XWayland Wrapper ==================== # # Create a wrapper script that forces Resolve to run under X11 (XWayland) # and sets up the library search path. Tumbleweed defaults to Wayland on # most desktop environments, but Resolve doesn't support native Wayland. # # Key environment variables: # QT_QPA_PLATFORM=xcb: Force X11 mode # __GLX_VENDOR_LIBRARY_NAME=nvidia: Use NVIDIA's GLX implementation # QT_XCB_GL_INTEGRATION=none: Disable Qt's XCB GL integration # (avoids conflicts with NVIDIA GL) # QT_OPENGL=desktop: Use desktop OpenGL (not GLES) # LD_LIBRARY_PATH: Prioritise our patched libs in /opt/resolve/ say "Creating /usr/local/bin/resolve wrapper…" sudo tee /usr/local/bin/resolve >/dev/null <<'EOF' #!/usr/bin/env bash # Force X11/XWayland + NVIDIA GLVND export QT_QPA_PLATFORM=xcb export __GLX_VENDOR_LIBRARY_NAME=nvidia export QT_XCB_GL_INTEGRATION=none export QT_OPENGL=desktop # Prefer the libs we just placed in /opt/resolve/libs export LD_LIBRARY_PATH="/opt/resolve/libs:/opt/resolve/bin:${LD_LIBRARY_PATH:-}" exec /opt/resolve/bin/resolve "$@" EOF sudo chmod +x /usr/local/bin/resolve # Copy and patch desktop entries to use our wrapper instead of launching # Resolve directly. User-level entries in ~/.local/share/applications/ # take priority over system entries in /usr/share/applications/. say "Patching desktop entries to use wrapper…" mkdir -p "$USR_APP_DIR" for f in /usr/share/applications/davinci-resolve.desktop \ /usr/share/applications/com.blackmagicdesign.resolve.desktop; do if [[ -f "$f" ]]; then install -m 0644 "$f" "$USR_APP_DIR/" tgt="$USR_APP_DIR/$(basename "$f")" sed -i 's|^Exec=.*|Exec=/usr/local/bin/resolve %u|g' "$tgt" sed -i 's|^TryExec=.*|TryExec=/usr/local/bin/resolve|g' "$tgt" || true sed -i 's|^Path=.*|Path=/opt/resolve/|g' "$tgt" || true fi done command -v update-desktop-database >/dev/null 2>&1 && update-desktop-database "$USR_APP_DIR" || true say "Done. Launch with: resolve"