#!/usr/bin/env bash # ============================================================================== # DaVinci Resolve Installer for Omarchy (Arch Linux + Hyprland + Intel Arc) # # Adapted from the NVIDIA-Open variant for systems with an Intel Arc GPU # using the Xe kernel driver. Covers all current Arc-class hardware: # - Alchemist Xe-HPG dGPU (Arc Axxx, e.g. A770) — xe driver # - Battlemage Xe2 dGPU (Arc B580/B570, late 2024) — xe driver # - Panther Lake Xe3-LPG iGPU (Arc B360/B370/B380/B390, — xe driver # Core Ultra 300 series, launched Jan 2026) # Older iGPUs (UHD/Iris on Gen 9–12.5) sit on the i915 driver and are # also detected; they're left visible to OpenCL but not preferred for # pinning when an xe device is available. # # IMPORTANT — SUPPORT CAVEAT # Blackmagic does NOT officially support Intel GPUs on Linux. Resolve uses # OpenCL (or CUDA on NVIDIA) for compute. With intel-compute-runtime # installed, the Arc shows up as an OpenCL device and basic editing / # playback / transcode often work, but specific effects, Neural Engine, # Fairlight FX, and noise reduction may fall back to CPU or fail. Treat # this as community/experimental — not a supported configuration. # # What this script does (same shape as the NVIDIA version): # 1. Finds the Resolve ZIP in ~/Downloads/ # 2. Installs system + Intel GPU runtime dependencies # 3. Extracts the ZIP → .run → squashfs-root (AppImage payload) # 4. Replaces bundled glib/gio/gmodule with system versions (ABI-safe) # 5. Keeps vendor libc++/libc++abi (removing these breaks Resolve) # 6. Installs to /opt/resolve with RPATH patching for all ELF binaries # 7. Ensures legacy libcrypt.so.1 is available (Arch dropped it) # 8. Installs desktop entries, icons, and udev rules # 9. Creates an XWayland wrapper script for Hyprland with Intel/OpenCL hints # # Prerequisites: # - Omarchy (Arch Linux) with kernel 6.12+ (Xe driver). 6.19+ recommended # for stable Battlemage support. # - DaVinci Resolve Linux ZIP downloaded to ~/Downloads/ # - Internet connection # ============================================================================== set -euo pipefail log(){ echo -e "▶ $*"; } warn(){ echo -e "⚠️ $*" >&2; } err(){ echo -e "❌ $*" >&2; exit 1; } # ==================== Preflight: kernel + GPU ==================== KVER_FULL="$(uname -r)" KMAJ="${KVER_FULL%%.*}"; KREST="${KVER_FULL#*.}"; KMIN="${KREST%%.*}" if (( KMAJ < 6 )) || { (( KMAJ == 6 )) && (( KMIN < 12 )); }; then warn "Kernel ${KVER_FULL} is older than 6.12 — Arc B580 (Battlemage) needs the Xe driver from 6.12+. Continue at your own risk." else log "Kernel ${KVER_FULL} OK for Xe driver" fi if lspci -nn 2>/dev/null | grep -qiE 'Intel.*(Arc|Battlemage|Alchemist|DG2)'; then log "Intel Arc GPU detected" else warn "No Intel Arc GPU detected via lspci — script will continue but you may not have GPU acceleration" fi # ==================== Locate ZIP ==================== ZIP_DIR="${HOME}/Downloads" shopt -s nullglob ZIP_FILES=("${ZIP_DIR}"/DaVinci_Resolve*_Linux.zip) shopt -u nullglob if [[ ${#ZIP_FILES[@]} -eq 0 ]]; then err "Put the official DaVinci Resolve Linux ZIP in ${ZIP_DIR}" fi # Pick the newest ZIP by mtime without parsing `ls` output. RESOLVE_ZIP="" RESOLVE_ZIP_MTIME=0 for _zf in "${ZIP_FILES[@]}"; do _m=$(stat -c%Y "${_zf}" 2>/dev/null || echo 0) if (( _m > RESOLVE_ZIP_MTIME )); then RESOLVE_ZIP_MTIME=${_m} RESOLVE_ZIP="${_zf}" fi done [[ -n "${RESOLVE_ZIP}" ]] || err "Could not determine newest ZIP file" log "Using installer ZIP: ${RESOLVE_ZIP}" # ==================== Package Installation ==================== if [[ "${RESOLVE_FULL_UPGRADE:-0}" == "1" ]]; then log "Updating system packages (RESOLVE_FULL_UPGRADE=1)..." sudo pacman -Syu --noconfirm else log "Skipping full system upgrade (set RESOLVE_FULL_UPGRADE=1 to enable)" sudo pacman -Sy --noconfirm fi # Build/extraction tools (same as NVIDIA variant) log "Installing required tools..." if ! sudo pacman -S --needed --noconfirm unzip patchelf libarchive xdg-user-dirs desktop-file-utils file gtk-update-icon-cache; then warn "Some optional tools failed to install, continuing anyway..." fi # Runtime dependencies — Intel-specific stack added on top of the common set: # libxcrypt-compat: Provides legacy libcrypt.so.1 (Arch moved to v2) # ffmpeg4.4: Older FFmpeg version Resolve links against # glu / gtk2 / fuse2: Same as NVIDIA variant (UI / AppImage compat) # mesa: OpenGL stack (Iris driver for Intel) # vulkan-intel: ANV — Vulkan ICD for Intel # intel-media-driver: iHD VA-API driver (HW decode/encode H.264/HEVC/AV1) # intel-compute-runtime: NEO — OpenCL (and Level Zero) ICD for Intel GPUs. # This is what Resolve will actually use for compute. # level-zero-loader: Loader for Intel oneAPI Level Zero (used by NEO) # ocl-icd: Generic OpenCL ICD loader (libOpenCL.so.1) # clinfo: Sanity tool — used at the end to confirm Resolve # will see the Arc as an OpenCL device. log "Installing Intel GPU + Resolve runtime dependencies..." INTEL_RUNTIME_PKGS=( libxcrypt-compat ffmpeg4.4 glu fuse2 mesa vulkan-intel intel-media-driver intel-compute-runtime level-zero-loader ocl-icd clinfo ) # Note: NOT installing gtk2 — verified via ldd that Resolve 21 does not link # libgtk-x11-2.0. It links libgdk_pixbuf-2.0 (a different package, gdk-pixbuf2, # already pulled in by virtually any desktop install). The gtk2 dep in older # Resolve install scripts was a leftover from when Resolve had GTK file # dialogs — modern Resolve is fully Qt. if ! sudo pacman -S --needed --noconfirm "${INTEL_RUNTIME_PKGS[@]}"; then err "pacman failed to install one or more runtime dependencies — re-run with the offending package name to see the error" fi # Compute-stack packages are non-negotiable: without them Resolve sees no # OpenCL device and crashes with "Unsupported GPU Processing Mode" on first # launch. Verify each is actually present before continuing. for pkg in intel-compute-runtime level-zero-loader ocl-icd clinfo; do pacman -Q "$pkg" >/dev/null 2>&1 || err "Required package not installed: ${pkg}" done log "Intel compute stack confirmed installed" # Resolve's built-in extras downloader expects RHEL-style cert path if [[ ! -e /etc/pki/tls ]]; then sudo mkdir -p /etc/pki sudo ln -sf /etc/ssl /etc/pki/tls fi # ==================== Extraction ==================== NEEDED_GB=10 FREE_KB=$(df --output=avail -k "${ZIP_DIR}" | tail -n1); FREE_GB=$((FREE_KB/1024/1024)) (( FREE_GB >= NEEDED_GB )) || err "Not enough free space in ${ZIP_DIR}: ${FREE_GB} GiB < ${NEEDED_GB} GiB" WORKDIR="$(mktemp -d -p "${ZIP_DIR}" .resolve-extract-XXXXXXXX)" cleanup() { if [[ -n "${WORKDIR:-}" && -d "${WORKDIR}" ]]; then log "Cleaning up temporary directory..." rm -rf "${WORKDIR}" 2>/dev/null || true fi } trap cleanup EXIT log "Unpacking ZIP to ${WORKDIR}…" unzip -q "${RESOLVE_ZIP}" -d "${WORKDIR}" RUN_FILE="$(find "${WORKDIR}" -maxdepth 2 -type f -name 'DaVinci_Resolve_*_Linux.run' | head -n1 || true)" [[ -n "${RUN_FILE}" ]] || err "Could not find the .run installer in the ZIP" chmod +x "${RUN_FILE}" EX_DIR="$(dirname "${RUN_FILE}")" log "Extracting AppImage payload…" if ! ( cd "${EX_DIR}" && "./$(basename "${RUN_FILE}")" --appimage-extract >/dev/null ); then err "Failed to extract AppImage payload" fi APPDIR="${EX_DIR}/squashfs-root" [[ -d "${APPDIR}" ]] || err "Extraction failed (no squashfs-root)" chmod -R u+rwX,go+rX,go-w "${APPDIR}" || warn "Could not normalize all permissions" [[ -s "${APPDIR}/bin/resolve" ]] || err "resolve binary missing or zero-size" # ==================== ABI-Safe Library Replacement ==================== # (Identical to NVIDIA variant — these are GPU-agnostic.) pushd "${APPDIR}" >/dev/null declare -A GLIB_LIBS=( ["/usr/lib/libglib-2.0.so.0"]="libs/libglib-2.0.so.0" ["/usr/lib/libgio-2.0.so.0"]="libs/libgio-2.0.so.0" ["/usr/lib/libgmodule-2.0.so.0"]="libs/libgmodule-2.0.so.0" ) for syslib in "${!GLIB_LIBS[@]}"; do target="${GLIB_LIBS[$syslib]}" if [[ -e "${syslib}" ]]; then rm -f "${target}" || true ln -sf "${syslib}" "${target}" || warn "Failed to symlink ${syslib}" else warn "System library ${syslib} not found, keeping bundled version" fi done if [[ -d "share/panels" ]]; then pushd "share/panels" >/dev/null tar -zxf dvpanel-framework-linux-x86_64.tgz 2>/dev/null || true mkdir -p "${APPDIR}/libs" find . -maxdepth 1 -type f -name '*.so' -exec mv -f {} "${APPDIR}/libs" \; 2>/dev/null || true if [[ -d lib ]]; then find lib -type f -name '*.so*' -exec mv -f {} "${APPDIR}/libs" \; 2>/dev/null || true fi popd >/dev/null fi rm -f "AppRun" "AppRun*" 2>/dev/null || true rm -rf "installer" "installer*" 2>/dev/null || true mkdir -p "bin" ln -sf "../BlackmagicRAWPlayer/BlackmagicRawAPI" "bin/" 2>/dev/null || true popd >/dev/null # ==================== Install to /opt/resolve ==================== log "Installing Resolve to /opt/resolve…" sudo rm -rf /opt/resolve sudo mkdir -p /opt/resolve if command -v rsync >/dev/null 2>&1; then sudo rsync -a --delete "${APPDIR}/" /opt/resolve/ else sudo cp -a "${APPDIR}/." /opt/resolve/ fi sudo mkdir -p /opt/resolve/.license log "Applying RPATH with patchelf (this may take a while for large libraries)…" RPATH_DIRS=( "libs" "libs/plugins/sqldrivers" "libs/plugins/xcbglintegrations" "libs/plugins/imageformats" "libs/plugins/platforms" "libs/Fusion" "plugins" "bin" "BlackmagicRAWSpeedTest/BlackmagicRawAPI" "BlackmagicRAWSpeedTest/plugins/platforms" "BlackmagicRAWSpeedTest/plugins/imageformats" "BlackmagicRAWSpeedTest/plugins/mediaservice" "BlackmagicRAWSpeedTest/plugins/audio" "BlackmagicRAWSpeedTest/plugins/xcbglintegrations" "BlackmagicRAWSpeedTest/plugins/bearer" "BlackmagicRAWPlayer/BlackmagicRawAPI" "BlackmagicRAWPlayer/plugins/mediaservice" "BlackmagicRAWPlayer/plugins/imageformats" "BlackmagicRAWPlayer/plugins/audio" "BlackmagicRAWPlayer/plugins/platforms" "BlackmagicRAWPlayer/plugins/xcbglintegrations" "BlackmagicRAWPlayer/plugins/bearer" "Onboarding/plugins/xcbglintegrations" "Onboarding/plugins/qtwebengine" "Onboarding/plugins/platforms" "Onboarding/plugins/imageformats" "DaVinci Control Panels Setup/plugins/platforms" "DaVinci Control Panels Setup/plugins/imageformats" "DaVinci Control Panels Setup/plugins/bearer" "DaVinci Control Panels Setup/AdminUtility/PlugIns/DaVinciKeyboards" "DaVinci Control Panels Setup/AdminUtility/PlugIns/DaVinciPanels" ) RPATH_ABS=""; for p in "${RPATH_DIRS[@]}"; do RPATH_ABS+="/opt/resolve/${p}:"; done; RPATH_ABS+="\$ORIGIN" if command -v patchelf >/dev/null 2>&1; then PATCH_COUNT=0 PATCH_FAIL=0 PATCH_SKIP=0 while IFS= read -r -d '' f; do FILE_INFO="$(file -b "$f" 2>/dev/null)" if [[ "${FILE_INFO}" =~ ELF.*executable ]] || [[ "${FILE_INFO}" =~ ELF.*shared\ object ]]; then CURRENT_RPATH="$(patchelf --print-rpath "$f" 2>/dev/null || true)" if [[ "${CURRENT_RPATH}" == "${RPATH_ABS}" ]]; then ((PATCH_SKIP++)) || true continue fi if sudo patchelf --set-rpath "${RPATH_ABS}" "$f" 2>/dev/null; then ((PATCH_COUNT++)) || true else ((PATCH_FAIL++)) || true FILE_SIZE=$(stat -c%s "$f" 2>/dev/null || echo 0) if (( FILE_SIZE > 33554432 )); then warn "Failed to patch large file: ${f##/opt/resolve/}" fi fi fi done < <(find /opt/resolve -type f -print0) log "Patched RPATH: ${PATCH_COUNT} files (${PATCH_FAIL} failures, ${PATCH_SKIP} already correct)" else warn "patchelf not found, skipping RPATH patching" fi # Legacy libcrypt fix (same as NVIDIA variant) sudo pacman -S --needed --noconfirm libxcrypt-compat || true sudo ldconfig || true if [[ -e /usr/lib/libcrypt.so.1 ]]; then sudo ln -sf /usr/lib/libcrypt.so.1 /opt/resolve/libs/libcrypt.so.1 fi # ==================== Desktop Integration ==================== log "Installing desktop entries and icons..." declare -A DESKTOP_FILES=( ["/opt/resolve/share/DaVinciResolve.desktop"]="/usr/share/applications/DaVinciResolve.desktop" ["/opt/resolve/share/DaVinciControlPanelsSetup.desktop"]="/usr/share/applications/DaVinciControlPanelsSetup.desktop" ["/opt/resolve/share/blackmagicraw-player.desktop"]="/usr/share/applications/blackmagicraw-player.desktop" ["/opt/resolve/share/blackmagicraw-speedtest.desktop"]="/usr/share/applications/blackmagicraw-speedtest.desktop" ) for src in "${!DESKTOP_FILES[@]}"; do dest="${DESKTOP_FILES[$src]}" if [[ -f "${src}" ]]; then sudo install -D -m 0644 "${src}" "${dest}" else warn "Desktop file not found: ${src}" fi done declare -A ICON_FILES=( ["/opt/resolve/graphics/DV_Resolve.png"]="/usr/share/icons/hicolor/128x128/apps/davinci-resolve.png" ["/opt/resolve/graphics/DV_Panels.png"]="/usr/share/icons/hicolor/128x128/apps/davinci-resolve-panels-setup.png" ["/opt/resolve/graphics/blackmagicraw-player_256x256_apps.png"]="/usr/share/icons/hicolor/256x256/apps/blackmagicraw-player.png" ["/opt/resolve/graphics/blackmagicraw-speedtest_256x256_apps.png"]="/usr/share/icons/hicolor/256x256/apps/blackmagicraw-speedtest.png" ) for src in "${!ICON_FILES[@]}"; do dest="${ICON_FILES[$src]}" if [[ -f "${src}" ]]; then sudo install -D -m 0644 "${src}" "${dest}" else warn "Icon file not found: ${src}" fi done sudo update-desktop-database >/dev/null 2>&1 || true sudo gtk-update-icon-cache -f /usr/share/icons/hicolor >/dev/null 2>&1 || true for r in 99-BlackmagicDevices.rules 99-ResolveKeyboardHID.rules 99-DavinciPanel.rules; do if [[ -f "/opt/resolve/share/etc/udev/rules.d/${r}" ]]; then sudo install -D -m 0644 "/opt/resolve/share/etc/udev/rules.d/${r}" "/usr/lib/udev/rules.d/${r}" fi done sudo udevadm control --reload-rules && sudo udevadm trigger || true # ==================== XWayland Wrapper Script (Intel Arc) ==================== # # Resolve still needs XWayland under Hyprland. Intel-specific bits: # - OCL_ICD_VENDORS: Force the OpenCL ICD search dir. # - NEOReadDebugKeys=1 + # OverrideGpuAddressSpace=48: # Workaround for OpenCL init failures on # Battlemage. Applied ONLY if Battlemage is # detected — Xe3 (Panther Lake) and Alchemist # don't need it. # - LIBVA_DRIVER_NAME=iHD: Pin Intel media driver for VA-API decode. # # GPU SELECTION (BDF-based, not index-based) # The wrapper enumerates Intel GPUs at launch and picks one: # - If a discrete Arc is present (PCI bus != 00, e.g. Battlemage B580 on # 03:00.0), pick it. # - Otherwise pick the only xe device available (covers Panther Lake # laptops with just the Xe3 iGPU, etc.). # The chosen device's PCI BDF is exported as ZE_AFFINITY_MASK in # "DDDD:BB:DD.F" form (e.g. "0000:03:00.0"). NEO's numeric Level Zero index # is NOT a reliable function of BDF order — on hybrid systems NEO often # enumerates the discrete card at index 0 even though its BDF sorts later — # so we use the BDF format which NEO matches against the actual device. # Override with RESOLVE_GPU_BDF=0000:XX:YY.Z if needed; disable pinning # entirely with RESOLVE_NO_PIN=1. cat << 'EOF' | sudo tee /usr/local/bin/resolve-intel-arc >/dev/null #!/usr/bin/env bash set -euo pipefail # Clear stale single-instance Qt lockfiles if [[ -r /tmp ]]; then for lockfile in /tmp/qtsingleapp-DaVinci*lockfile; do [[ -f "$lockfile" ]] && rm -f "$lockfile" 2>/dev/null || true done fi # Force XWayland under Hyprland/Wayland export QT_QPA_PLATFORM=xcb export QT_AUTO_SCREEN_SCALE_FACTOR=1 # Intel OpenCL / Level Zero (ICD search dir) export OCL_ICD_VENDORS="${OCL_ICD_VENDORS:-/etc/OpenCL/vendors}" # Intel VA-API (HW decode) export LIBVA_DRIVER_NAME=iHD # --- Detect Intel GPUs and pick the Arc to pin to --- # NEO/Level Zero enumerates ALL Intel GPUs it supports (both i915 and xe # backends), sorted by PCI BDF. The picker mirrors that ordering so the # index we emit matches what ZE_AFFINITY_MASK expects. # # Selection priority: # 1. xe-driven device on a non-SoC PCI bus (a discrete Battlemage like B580) # 2. any xe-driven device (covers Panther Lake Xe3 iGPU) # 3. first Intel device found (last-resort fallback) arc_pick() { local -a entries=() local d vendor driver bdf for d in /sys/class/drm/card[0-9]*; do # Skip connector subentries like card0-DP-2 [[ "$d" =~ /card[0-9]+$ ]] || continue [[ -e "$d/device/uevent" ]] || continue vendor="$(cat "$d/device/vendor" 2>/dev/null || echo)" [[ "$vendor" == "0x8086" ]] || continue driver="$(awk -F= '/^DRIVER=/{print $2}' "$d/device/uevent")" bdf="$(basename "$(readlink -f "$d/device")")" entries+=("$bdf|$driver") done ((${#entries[@]})) || return 1 # Sort by BDF (purely cosmetic — selection priorities below don't depend # on order, and ZE_AFFINITY_MASK takes the BDF directly) IFS=$'\n' read -rd '' -a entries < <(printf '%s\n' "${entries[@]}" | sort; printf '\0') || true local picked_bdf="" picked_drv="" local n=${#entries[@]} i e b drv # Priority 1: discrete xe device (NOT on PCI bus 00 — those are SoC iGPUs) for ((i=0; i&2 ARC_BDF="${RESOLVE_GPU_BDF}" elif read -r ARC_BDF ARC_DRV < <(arc_pick); then export ZE_AFFINITY_MASK="${ARC_BDF}" echo "Resolve: pinning to Arc GPU at ${ARC_BDF} (driver=${ARC_DRV})" >&2 else echo "Resolve: no Intel GPU found; not pinning ZE_AFFINITY_MASK" >&2 fi fi # OpenCL init workaround is specific to discrete Battlemage Xe2 silicon # (Arc B5x0/B7x0 dGPU). Intel reuses the "Arc B-series" brand for the Xe3-LPG # iGPUs in Panther Lake (B360/B370/B380/B390, launched Jan 2026), but those # don't need — and don't want — this debug key. Gate on lspci match AND a # non-SoC PCI bus, since iGPUs always live on 0000:00:02.0. if lspci -nn 2>/dev/null | grep -qi 'Battlemage' \ && [[ -n "${ARC_BDF:-}" && ! "${ARC_BDF}" =~ ^0000:00: ]]; then export NEOReadDebugKeys=1 export OverrideGpuAddressSpace=48 fi exec /opt/resolve/bin/resolve "$@" EOF sudo chmod +x /usr/local/bin/resolve-intel-arc # Convenience symlink at /usr/bin/davinci-resolve if [[ ! -e /usr/bin/davinci-resolve ]]; then if [[ -x /usr/local/bin/resolve-intel-arc ]]; then echo -e '#!/usr/bin/env bash\nexec /usr/local/bin/resolve-intel-arc "$@"' | sudo tee /usr/bin/davinci-resolve >/dev/null else echo -e '#!/usr/bin/env bash\nexec /opt/resolve/bin/resolve "$@"' | sudo tee /usr/bin/davinci-resolve >/dev/null fi sudo chmod +x /usr/bin/davinci-resolve fi # Point system .desktop entries at the wrapper WRAPPER="/usr/local/bin/resolve-intel-arc" if [[ -f /usr/share/applications/DaVinciResolve.desktop ]]; then sudo sed -i "s|^Exec=.*|Exec=${WRAPPER} %U|" /usr/share/applications/DaVinciResolve.desktop fi if [[ -f /usr/share/applications/DaVinciResolveCaptureLogs.desktop ]]; then sudo sed -i "s|^Exec=.*|Exec=${WRAPPER} %U|" /usr/share/applications/DaVinciResolveCaptureLogs.desktop fi sudo update-desktop-database >/dev/null 2>&1 || true # User-level .desktop overrides system entry (survives reinstalls) mkdir -p "${HOME}/.local/share/applications" cat > "${HOME}/.local/share/applications/davinci-resolve-wrapper.desktop" << EOF [Desktop Entry] Type=Application Name=DaVinci Resolve Comment=DaVinci Resolve via XWayland wrapper (Intel Arc) Exec=${WRAPPER} %U TryExec=${WRAPPER} Terminal=false Icon=davinci-resolve Categories=AudioVideo;Video;Audio;Graphics; StartupWMClass=resolve X-GNOME-UsesNotifications=true EOF update-desktop-database "${HOME}/.local/share/applications" >/dev/null 2>&1 || true sudo gtk-update-icon-cache -f /usr/share/icons/hicolor >/dev/null 2>&1 || true # ==================== Audio backend fix (DeckLink → ALSA) ==================== # # Resolve ships with `Local.Audio.Type = DeckLink` as the default in its # system-wide config template at /opt/resolve/share/default-config.dat. # That's correct for users with a Blackmagic DeckLink capture/playback card, # but on systems without one Resolve aborts on first launch. Patch both the # template (so future first-launches are correct) and any existing user # config (so the current install isn't broken). log "Switching Resolve audio backend default from DeckLink to ALSA..." TEMPLATE=/opt/resolve/share/default-config.dat if [[ -f "${TEMPLATE}" ]] && grep -q '^Local\.Audio\.Type = DeckLink$' "${TEMPLATE}"; then sudo sed -i 's|^Local\.Audio\.Type = DeckLink$|Local.Audio.Type = ALSA|' "${TEMPLATE}" log " Patched system template ${TEMPLATE}" fi USER_CFG="${HOME}/.local/share/DaVinciResolve/configs/config.dat" if [[ -f "${USER_CFG}" ]] && grep -q '^Local\.Audio\.Type = DeckLink$' "${USER_CFG}"; then cp "${USER_CFG}" "${USER_CFG}.bak.$(date +%s)" sed -i 's|^Local\.Audio\.Type = DeckLink$|Local.Audio.Type = ALSA|' "${USER_CFG}" log " Patched existing user config ${USER_CFG} (backup .bak. created)" fi # ==================== snd-aloop (the actual render-blocker fix) ==================== # # Resolve's audio engine opens raw ALSA hardware via snd_pcm_open("hw:%d", ...) # — it never goes through ALSA's plugin layer (default/pulse/pipewire) and it # enumerates EVERY card under /dev/snd/controlC[0-32] looking for a usable PCM. # When every real ALSA card on the system is owned/contested by PipeWire's # session manager, Resolve's enumeration loops forever, the render queue # never spawns the encoder, and the user sees: # - alsa device meters "flickering" in wireplumber (each enumeration cycle # briefly opens controlC*; PipeWire reacts) # - render that "won't start" with no error in ResolveDebug.txt # Confirmed via strace: 14000+ SNDRV_CTL_IOCTL_PCM_INFO ENXIO ioctls and # 47000+ /dev/snd/controlCN ENOENT opens during the failed render attempt, # concentrated AFTER the user clicks Render — i.e. a tight retry loop. # # THE FIX: load the kernel's snd-aloop module. It exposes a virtual ALSA # loopback card that PipeWire ignores (no ACP profile, not auto-acquired). # Resolve's enumerator finds it, can fully own it, settles on it, and the # render proceeds. Side effect: a "Loopback" device shows up in alsamixer # and pavucontrol — harmless. # # Skipped if RESOLVE_NO_ALOOP=1 (e.g. user already has a dedicated audio # interface that Resolve uses). Persistent across reboots via # /etc/modules-load.d/. if [[ "${RESOLVE_NO_ALOOP:-0}" == "1" ]]; then log "Skipping snd-aloop setup (RESOLVE_NO_ALOOP=1)" else log "Setting up snd-aloop (virtual ALSA card so Resolve render can start)..." if ! lsmod | grep -qE '^snd_aloop'; then if sudo modprobe snd-aloop 2>/dev/null; then log " snd-aloop loaded for the current session" else warn " modprobe snd-aloop failed — kernel may lack the module." warn " On Arch this is part of linux/linux-zen/linux-lts; verify: modinfo snd-aloop" fi else log " snd-aloop already loaded" fi ALOOP_CONF=/etc/modules-load.d/snd-aloop.conf if [[ ! -f "${ALOOP_CONF}" ]] || ! grep -qx 'snd-aloop' "${ALOOP_CONF}" 2>/dev/null; then echo 'snd-aloop' | sudo tee "${ALOOP_CONF}" >/dev/null log " Wrote ${ALOOP_CONF} (autoloads at boot)" else log " ${ALOOP_CONF} already configured" fi # Bridge snd-aloop capture → default sink so monitor audio is audible. # Without this, Resolve writes to the loopback and the audio goes nowhere # (loopback is a black hole until something captures the other side). # The bridge is a PipeWire loopback module loaded from user config; it # tracks the default sink so headphone/HDMI switching keeps working. ALOOP_BRIDGE_DIR="${HOME}/.config/pipewire/pipewire.conf.d" ALOOP_BRIDGE_FILE="${ALOOP_BRIDGE_DIR}/50-resolve-aloop-bridge.conf" mkdir -p "${ALOOP_BRIDGE_DIR}" if [[ ! -f "${ALOOP_BRIDGE_FILE}" ]]; then cat > "${ALOOP_BRIDGE_FILE}" <<'EOF' # DaVinci Resolve aloop monitor bridge — managed by install-davinci-resolve-intel-arc.sh # Bridges snd-aloop's capture side to the system default sink so Resolve's # monitor audio is audible while editing. Without this, Resolve renders fine # but you hear nothing during playback. Remove this file + restart PipeWire # to disable. context.modules = [ { name = libpipewire-module-loopback args = { node.description = "DaVinci Resolve aloop monitor bridge" capture.props = { node.name = "resolve-aloop-capture" target.object = "alsa_input.platform-snd_aloop.0.analog-stereo" node.passive = true } playback.props = { node.name = "resolve-aloop-playback" media.class = "Stream/Output/Audio" } } } ] EOF log " Wrote ${ALOOP_BRIDGE_FILE} (PipeWire loopback bridge)" # Reload user PipeWire services so the new conf is picked up if systemctl --user is-active --quiet pipewire 2>/dev/null; then systemctl --user restart pipewire pipewire-pulse wireplumber 2>/dev/null || true log " Reloaded user PipeWire services" fi else log " ${ALOOP_BRIDGE_FILE} already in place" fi fi # ==================== Post-install OpenCL sanity check ==================== echo if command -v clinfo >/dev/null 2>&1; then if clinfo -l 2>/dev/null | grep -qiE 'Arc|Intel.*Graphics|Battlemage|Alchemist'; then log "OpenCL: Intel GPU is visible to clinfo — Resolve should see it for compute." else warn "OpenCL: no Intel GPU listed by clinfo. Resolve will likely fall back to CPU." warn " Try: clinfo -l (and check that intel-compute-runtime is installed)" fi else warn "clinfo not installed — skipped OpenCL visibility check" fi # ==================== Reset stale Resolve user configs ==================== # # Resolve defaults to GPU Processing Mode = CUDA on Linux. If a previous # launch couldn't find an OpenCL device (e.g. Intel compute runtime was # missing), Resolve writes out a config snapshot and segfaults before the # UI ever appears with "Unsupported GPU Processing Mode". Subsequent # launches reuse that broken snapshot and crash the same way — even after # the OpenCL stack is fixed. The fix is to delete configs/ and logs/ so # Resolve goes through first-launch onboarding again with a working GPU # stack present. # # We only wipe if we detect that prior-crash marker (or RESOLVE_RESET_CONFIG=1 # is set explicitly). Project databases under "Resolve Disk Database/" and # "Resolve Project Library/" are NOT touched. RESOLVE_USER_DIR="${HOME}/.local/share/DaVinciResolve" PRIOR_CRASH=0 if [[ -f "${RESOLVE_USER_DIR}/logs/ResolveDebug.txt" ]] \ && grep -q 'Unsupported GPU Processing Mode' "${RESOLVE_USER_DIR}/logs/ResolveDebug.txt" 2>/dev/null; then PRIOR_CRASH=1 fi if (( PRIOR_CRASH )) || [[ "${RESOLVE_RESET_CONFIG:-0}" == "1" ]]; then if (( PRIOR_CRASH )); then log "Detected prior crashed launch ('Unsupported GPU Processing Mode')." else log "RESOLVE_RESET_CONFIG=1 set — forcing config reset." fi log "Resetting Resolve configs and logs to first-launch state. Project databases preserved." rm -rf "${RESOLVE_USER_DIR}/configs" "${RESOLVE_USER_DIR}/logs" 2>/dev/null || true fi echo echo "✅ DaVinci Resolve installed to /opt/resolve" echo " (vendor libc++ kept; libcrypt.so.1 ensured; Intel Arc OpenCL/VA-API enabled)" echo " Launch from your app menu, or run: resolve-intel-arc" echo " GPU pinning is automatic — discrete Arc preferred over iGPU." echo " Override: RESOLVE_GPU_BDF=0000:XX:YY.Z resolve-intel-arc" echo " Disable: RESOLVE_NO_PIN=1 resolve-intel-arc" echo " Force config reset on next install: RESOLVE_RESET_CONFIG=1 ./install-davinci-resolve-intel-arc.sh" echo " Skip snd-aloop module setup: RESOLVE_NO_ALOOP=1 ./install-davinci-resolve-intel-arc.sh" echo " Logs: ~/.local/share/DaVinciResolve/logs/ResolveDebug.txt" echo " Note: Intel Arc on Linux is unsupported by Blackmagic — expect quirks." echo