From 2af027c9fe5ad1ff4a23cf8bd03391670de7613a Mon Sep 17 00:00:00 2001 From: nosignal Date: Fri, 1 May 2026 22:29:14 +0100 Subject: [PATCH] =?UTF-8?q?Initial=20commit=20=E2=80=94=20DaVinci=20Resolv?= =?UTF-8?q?e=20installer=20for=20Intel=20Arc=20on=20Omarchy?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 9 + LICENSE | 21 + README.md | 354 +++++++++++++++ install-davinci-resolve-intel-arc.sh | 646 +++++++++++++++++++++++++++ 4 files changed, 1030 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md create mode 100755 install-davinci-resolve-intel-arc.sh diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e14212f --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +# Editor / OS junk +.DS_Store +*.swp +*~ + +# Local Resolve test artefacts +/squashfs-root/ +DaVinci_Resolve_*_Linux.run +DaVinci_Resolve_*_Linux.zip diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..ea5a604 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Gavin Nugent / NO SIGNAL + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..4d7cf8a --- /dev/null +++ b/README.md @@ -0,0 +1,354 @@ +# DaVinci Resolve - Intel Arc Omarchy + +Install [DaVinci Resolve](https://www.blackmagicdesign.com/products/davinciresolve) on [Omarchy](https://omarchy.com) (Arch Linux + Hyprland) with **Intel Arc** GPU support — Alchemist (Arc Axxx, A770), Battlemage (B580/B570), and Panther Lake Xe3-LPG iGPUs (Arc B360/B370/B380/B390 in Core Ultra 300). + +Adapted from the NVIDIA variant. Handles ABI-safe library replacement, RPATH patching, the OpenCL/Level Zero stack, GPU pinning by PCI BDF, the DeckLink → ALSA audio default, and the `snd-aloop` render-blocker fix. + +> **Support caveat** +> Blackmagic does **not** officially support Intel GPUs on Linux. With `intel-compute-runtime` installed the Arc shows up as an OpenCL device and editing/playback/transcode generally work, but Neural Engine, Fairlight FX, noise reduction, and some effects may fall back to CPU or fail. Treat this as community/experimental — not a supported configuration. + +## Requirements + +- **OS**: [Omarchy](https://omarchy.com) (Arch Linux + Hyprland) +- **GPU**: Intel Arc on the `xe` driver + - Alchemist Xe-HPG dGPU (Arc Axxx, e.g. A770) + - Battlemage Xe2 dGPU (Arc B580/B570, late 2024) + - Panther Lake Xe3-LPG iGPU (Core Ultra 300, Jan 2026) + - Older UHD/Iris on `i915` is detected but not preferred for pinning when an `xe` device is present +- **Kernel**: 6.12+ (Xe driver). 6.19+ recommended for stable Battlemage support +- **Audio stack**: PipeWire + Wireplumber (Omarchy default) +- **Disk space**: ~10 GiB free in `~/Downloads` for extraction (temporary) +- **DaVinci Resolve ZIP**: downloaded from Blackmagic's website + +## Quick Start + +1. **Download DaVinci Resolve** from [blackmagicdesign.com](https://www.blackmagicdesign.com/products/davinciresolve) + - Choose "DaVinci Resolve" (free) or "DaVinci Resolve Studio" (paid) + - Select **Linux** and download the ZIP + - Save it to `~/Downloads/` + +2. **Run the installer**: +```bash +git clone https://git.no-signal.uk/nosignal/DaVinci-Resolve-Intel-Arc-Omarchy.git +cd DaVinci-Resolve-Intel-Arc-Omarchy +chmod +x install-davinci-resolve-intel-arc.sh +./install-davinci-resolve-intel-arc.sh +``` + +3. **Launch Resolve** from your app menu, or run `resolve-intel-arc`. + +## What It Does + +### 1. Preflight checks + +- Verifies kernel ≥ 6.12 (warns and continues otherwise) +- Greps `lspci` for Intel Arc GPUs +- Picks the newest `DaVinci_Resolve*_Linux.zip` in `~/Downloads/` by mtime +- Refuses to start if `~/Downloads/` has under 10 GiB free + +### 2. Installs dependencies + +**Build/extraction tools:** + +| Package | Purpose | +|---------|---------| +| `unzip` | Extract the Resolve ZIP | +| `patchelf` | RPATH patching of all ELF binaries | +| `libarchive` | Archive handling | +| `desktop-file-utils` | App menu integration | +| `file` | Identify ELF binaries for patchelf | +| `gtk-update-icon-cache` | Refresh hicolor icon cache | + +**Runtime dependencies (Intel-specific stack on top of the common set):** + +| Package | Purpose | +|---------|---------| +| `libxcrypt-compat` | Legacy `libcrypt.so.1` (Arch moved to v2) | +| `ffmpeg4.4` | Older FFmpeg version Resolve links against | +| `glu` | OpenGL Utility Library | +| `fuse2` | AppImage compatibility layer | +| `mesa` | OpenGL stack (Iris driver) | +| `vulkan-intel` | ANV — Vulkan ICD for Intel | +| `intel-media-driver` | iHD VA-API driver (HW H.264/HEVC/AV1 decode/encode) | +| `intel-compute-runtime` | NEO — OpenCL & Level Zero ICD. **What Resolve actually uses for compute.** | +| `level-zero-loader` | Loader for Intel oneAPI Level Zero | +| `ocl-icd` | Generic OpenCL ICD loader (`libOpenCL.so.1`) | +| `clinfo` | Sanity tool — used post-install to confirm OpenCL visibility | + +The script aborts if any of `intel-compute-runtime`, `level-zero-loader`, `ocl-icd`, or `clinfo` failed to install — without them Resolve sees no OpenCL device and crashes with **Unsupported GPU Processing Mode** on first launch. + +> Note: `gtk2` is **not** installed. Verified via `ldd` that Resolve 21 doesn't link `libgtk-x11-2.0`; the modern UI is fully Qt. The leftover `gtk2` dep in older install scripts came from the era when Resolve had GTK file dialogs. + +### 3. Extracts Resolve + +``` +ZIP → .run file → squashfs-root (actual application files) +``` + +Temporary files clean up automatically via an `EXIT` trap. + +### 4. ABI-safe library replacement + +The same library policy as the NVIDIA variant — these libraries are GPU-agnostic: + +| Library | Action | Why | +|---------|--------|-----| +| `libglib-2.0.so` | **Replace** with system | Stable C ABI, safe to swap | +| `libgio-2.0.so` | **Replace** with system | Stable C ABI, safe to swap | +| `libgmodule-2.0.so` | **Replace** with system | Stable C ABI, safe to swap | +| `libc++.so` | **Keep** bundled | C++ ABI mismatch causes crashes | +| `libc++abi.so` | **Keep** bundled | C++ ABI mismatch causes crashes | + +### 5. Patches RPATH + +Every ELF binary in `/opt/resolve` gets RPATH patched to point at `/opt/resolve/libs/` and the relevant subdirectories (Fusion, BlackmagicRAW, Onboarding, Qt plugins, etc.). Without this, binaries would look for libraries at the original AppImage paths that no longer exist. + +### 6. Legacy `libcrypt.so.1` shim + +Arch dropped `libcrypt.so.1`. The script ensures `libxcrypt-compat` is present so Resolve's older link continues to resolve. + +### 7. Desktop integration + +- Installs `.desktop` entries for Resolve, Capture Logs, Control Panels Setup, BlackmagicRAW Player & SpeedTest +- Installs hicolor icons (128/256 px) +- Installs udev rules for Blackmagic capture cards, the Resolve Editor Keyboard, and DaVinci control panels +- Re-points all launchers at the XWayland wrapper (`/usr/local/bin/resolve-intel-arc`) +- Drops a user-level `.desktop` override at `~/.local/share/applications/davinci-resolve-wrapper.desktop` so future system updates don't undo the wrapper + +### 8. XWayland wrapper (Intel Arc) + +A wrapper script at `/usr/local/bin/resolve-intel-arc`: + +- Forces XWayland under Hyprland/Wayland (`QT_QPA_PLATFORM=xcb`) +- Pins `LIBVA_DRIVER_NAME=iHD` for Intel media driver VA-API decode +- Sets `OCL_ICD_VENDORS=/etc/OpenCL/vendors` so the Intel ICD is found +- Clears stale `qtsingleapp-DaVinci*lockfile` files left behind after a crash +- **Pins the GPU by PCI BDF**, not by Level Zero index + +#### GPU pinning (BDF-based) + +NEO/Level Zero enumerates *every* Intel GPU it supports across both `xe` and `i915` backends, sorted by PCI BDF — but the numeric index is not a reliable function of BDF order. On hybrid Battlemage + iGPU systems, NEO often enumerates the discrete card at index 0 even though its BDF sorts later. The wrapper avoids the indexing trap entirely: + +1. Walks `/sys/class/drm/card[0-9]*` and collects every device with vendor `0x8086` +2. **Priority 1**: discrete `xe` device (BDF *not* on bus `00:` — i.e. not an SoC iGPU). This picks Battlemage B580/B570 dGPUs. +3. **Priority 2**: any `xe` device (covers Panther Lake Xe3-LPG iGPU) +4. **Priority 3**: first Intel device (last-resort fallback) +5. Exports the chosen device's BDF as `ZE_AFFINITY_MASK` in `DDDD:BB:DD.F` form (e.g. `0000:03:00.0`) — NEO matches this directly against the device + +#### Battlemage OpenCL workaround + +Discrete Battlemage Xe2 silicon needs an OpenCL init workaround. The wrapper applies it **only** if `lspci` shows Battlemage **and** the picked BDF is *not* on bus `00:` (so iGPUs are excluded — Intel reuses the "Arc B-series" brand for the Xe3-LPG iGPUs in Panther Lake, and they don't want this debug key): + +```bash +export NEOReadDebugKeys=1 +export OverrideGpuAddressSpace=48 +``` + +### 9. Audio backend default (DeckLink → ALSA) + +Resolve ships with `Local.Audio.Type = DeckLink` in its system-wide config template at `/opt/resolve/share/default-config.dat`. Correct for users with a Blackmagic DeckLink card; aborts on first launch otherwise. The script patches: + +- The system template (so future first-launches are correct) +- Any existing user config at `~/.local/share/DaVinciResolve/configs/config.dat`, with a timestamped `.bak.` backup + +### 10. `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 is owned/contested by PipeWire's session manager, Resolve loops forever. Symptoms: + +- Wireplumber meters "flicker" as Resolve repeatedly opens `controlC*` +- Render sits at "in progress" with growing ETA, no output file +- `ResolveDebug.txt` shows nothing useful +- `strace` shows tens of thousands of `SNDRV_CTL_IOCTL_PCM_INFO` `ENXIO` ioctls per failed render attempt + +**The fix**: load the kernel's `snd-aloop` module. PipeWire ignores it (no ACP profile, not auto-acquired), so Resolve can fully own it and the render proceeds. The script: + +- `modprobe snd-aloop` for the current session +- Writes `/etc/modules-load.d/snd-aloop.conf` so it autoloads at boot +- Writes a PipeWire loopback bridge at `~/.config/pipewire/pipewire.conf.d/50-resolve-aloop-bridge.conf` so monitor audio routes from the loopback's capture side to the current default sink (without it, Resolve plays back silently — headphone/HDMI sink switching keeps working through the bridge) +- Restarts user PipeWire/Wireplumber so the conf loads immediately + +Set `RESOLVE_NO_ALOOP=1` to skip this entirely (useful if you have a dedicated audio interface Resolve already uses cleanly). + +### 11. Post-install OpenCL sanity check + +Runs `clinfo -l` and reports whether the Intel GPU is visible to the OpenCL stack. If it isn't, Resolve will fall back to CPU. + +### 12. Stale-config recovery + +Resolve defaults to `GPU Processing Mode = CUDA` on Linux. If a previous launch couldn't find an OpenCL device (e.g. compute runtime was missing the first time), Resolve writes out a config snapshot and segfaults on every subsequent launch — *even after* the OpenCL stack is fixed. The script detects the `Unsupported GPU Processing Mode` marker in `~/.local/share/DaVinciResolve/logs/ResolveDebug.txt` and clears `configs/` and `logs/` to force first-launch onboarding again. **Project databases under `Resolve Disk Database/` and `Resolve Project Library/` are not touched.** + +Force a manual reset with `RESOLVE_RESET_CONFIG=1`. + +## Files Installed + +### Application + +| Path | Purpose | +|------|---------| +| `/opt/resolve/` | Main application directory | +| `/opt/resolve/bin/resolve` | Resolve binary | +| `/opt/resolve/libs/` | Bundled libraries (vendor `libc++` kept) | + +### Scripts + +| Path | Purpose | +|------|---------| +| `/usr/local/bin/resolve-intel-arc` | XWayland wrapper (main launcher) | +| `/usr/bin/davinci-resolve` | Convenience symlink to wrapper | + +### Desktop entries + +| Path | Purpose | +|------|---------| +| `/usr/share/applications/DaVinciResolve.desktop` | System app menu entry | +| `~/.local/share/applications/davinci-resolve-wrapper.desktop` | User entry (takes priority, survives reinstalls) | + +### Icons + +| Path | Purpose | +|------|---------| +| `/usr/share/icons/hicolor/128x128/apps/davinci-resolve.png` | App icon | +| `/usr/share/icons/hicolor/256x256/apps/blackmagicraw-player.png` | BMRAW Player icon | + +### Hardware support + +| Path | Purpose | +|------|---------| +| `/usr/lib/udev/rules.d/99-BlackmagicDevices.rules` | Capture cards | +| `/usr/lib/udev/rules.d/99-ResolveKeyboardHID.rules` | Resolve Editor Keyboard | +| `/usr/lib/udev/rules.d/99-DavinciPanel.rules` | DaVinci control panels | + +### Audio + +| Path | Purpose | +|------|---------| +| `/etc/modules-load.d/snd-aloop.conf` | Autoload `snd-aloop` at boot | +| `~/.config/pipewire/pipewire.conf.d/50-resolve-aloop-bridge.conf` | Loopback monitor bridge | + +## Environment Variables + +All optional — set when running the script or the launcher: + +| Variable | Effect | +|----------|--------| +| `RESOLVE_FULL_UPGRADE=1` | Run `pacman -Syu` instead of just `-Sy` before installing deps | +| `RESOLVE_NO_ALOOP=1` | Skip the `snd-aloop` setup entirely (use if you have a dedicated audio interface) | +| `RESOLVE_RESET_CONFIG=1` | Force-clear Resolve's `configs/` and `logs/` even if no prior crash is detected | +| `RESOLVE_GPU_BDF=0000:XX:YY.Z` | Manual GPU pinning override (sets `ZE_AFFINITY_MASK`) | +| `RESOLVE_NO_PIN=1` | Disable `ZE_AFFINITY_MASK` pinning — let NEO pick whatever it wants | + +Examples: + +```bash +# First install on a system that hasn't been pacman-upgraded recently +RESOLVE_FULL_UPGRADE=1 ./install-davinci-resolve-intel-arc.sh + +# Skip the audio fix +RESOLVE_NO_ALOOP=1 ./install-davinci-resolve-intel-arc.sh + +# Pin to a specific Arc B580 at 04:00.0 +RESOLVE_GPU_BDF=0000:04:00.0 resolve-intel-arc +``` + +## Troubleshooting + +### Resolve crashes on launch with "Unsupported GPU Processing Mode" + +Either the OpenCL stack isn't visible, or you have a stale config from a previous failed launch. + +```bash +# Confirm OpenCL sees the Arc +clinfo -l + +# If clinfo lists nothing, check the compute stack +pacman -Q intel-compute-runtime level-zero-loader ocl-icd + +# If clinfo is fine but Resolve still crashes, force a config reset +RESOLVE_RESET_CONFIG=1 ./install-davinci-resolve-intel-arc.sh +``` + +### Render starts but never finishes (no output file, growing ETA) + +This is the `snd-aloop` render-blocker. Either you ran with `RESOLVE_NO_ALOOP=1`, or `snd-aloop` failed to load. + +```bash +# Confirm the module is loaded +lsmod | grep snd_aloop + +# If not, load it manually +sudo modprobe snd-aloop + +# And persist it +echo snd-aloop | sudo tee /etc/modules-load.d/snd-aloop.conf +``` + +### Wrong GPU selected on a hybrid system + +Override `ZE_AFFINITY_MASK` directly: + +```bash +# Find your Intel GPUs +for d in /sys/class/drm/card[0-9]*; do + vendor=$(cat "$d/device/vendor" 2>/dev/null) + [[ "$vendor" == "0x8086" ]] || continue + echo "$(basename "$(readlink -f "$d/device")") -> $(basename "$d")" +done + +# Pin to the right BDF +RESOLVE_GPU_BDF=0000:03:00.0 resolve-intel-arc +``` + +### Battlemage-specific OpenCL init failures + +The wrapper applies `NEOReadDebugKeys=1` + `OverrideGpuAddressSpace=48` automatically when it detects a discrete Battlemage card. If you've manually overridden `RESOLVE_GPU_BDF` to a non-Battlemage BDF, those debug keys aren't set — set them yourself if you actually want them. + +### Stale Qt lockfiles after a crash + +The wrapper clears `/tmp/qtsingleapp-DaVinci*lockfile` on every launch — but if the wrapper isn't being used (e.g. you ran `/opt/resolve/bin/resolve` directly), clear them manually: + +```bash +rm -f /tmp/qtsingleapp-DaVinci*lockfile +``` + +### Logs + +``` +~/.local/share/DaVinciResolve/logs/ResolveDebug.txt +``` + +## Uninstalling + +```bash +# Resolve itself +sudo rm -rf /opt/resolve +sudo rm -f /usr/local/bin/resolve-intel-arc /usr/bin/davinci-resolve + +# Desktop entries / icons +sudo rm -f /usr/share/applications/DaVinciResolve.desktop \ + /usr/share/applications/DaVinciResolveCaptureLogs.desktop \ + /usr/share/applications/DaVinciControlPanelsSetup.desktop \ + /usr/share/applications/blackmagicraw-player.desktop \ + /usr/share/applications/blackmagicraw-speedtest.desktop \ + /usr/share/icons/hicolor/128x128/apps/davinci-resolve*.png \ + /usr/share/icons/hicolor/256x256/apps/blackmagicraw-*.png +rm -f ~/.local/share/applications/davinci-resolve-wrapper.desktop + +# Audio fix (optional — leaving it in place is harmless) +sudo rm -f /etc/modules-load.d/snd-aloop.conf +rm -f ~/.config/pipewire/pipewire.conf.d/50-resolve-aloop-bridge.conf + +sudo update-desktop-database 2>/dev/null +sudo gtk-update-icon-cache -f /usr/share/icons/hicolor 2>/dev/null +``` + +User configs and project databases under `~/.local/share/DaVinciResolve/` are left in place — delete them by hand if you want a fully clean uninstall. + +## Related + +- [DaVinci-Resolve-Omarchy](https://git.no-signal.uk/nosignal/DaVinci-Resolve-Omarchy) — NVIDIA variant +- [DaVinci-Resolve-AMD-Omarchy](https://git.no-signal.uk/nosignal/DaVinci-Resolve-AMD-Omarchy) — AMD (RDNA 1–4) variant +- [DaVinci-Resolve-Linux-Mint](https://git.no-signal.uk/nosignal/DaVinci-Resolve-Linux-Mint), [DaVinci-Resolve-PopOS](https://git.no-signal.uk/nosignal/DaVinci-Resolve-PopOS), [DaVinci-Resolve-openSUSE-Tumbleweed](https://git.no-signal.uk/nosignal/DaVinci-Resolve-openSUSE-Tumbleweed) — non-Arch installers + +## License + +MIT — see [LICENSE](LICENSE). diff --git a/install-davinci-resolve-intel-arc.sh b/install-davinci-resolve-intel-arc.sh new file mode 100755 index 0000000..b608ce6 --- /dev/null +++ b/install-davinci-resolve-intel-arc.sh @@ -0,0 +1,646 @@ +#!/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