Total rewrite of the installer mirroring the proven NVIDIA-Open install path,
with two new root-cause fixes for AMD on hybrid systems.
Installer (v3.0 -> v4.1):
- Pin ROCm 7.1.1 from Arch Linux Archive as the OpenCL provider; current
7.2.x is broken with DaVinci Resolve (clCreateContext fails / Color page
hangs on every AMD card). Adds IgnorePkg to /etc/pacman.conf and aborts
if pacman -U partial-downgrades.
- DRI_PRIME explicit PCI-tag pin in launcher (DRI_PRIME=pci-0000_BB_DD_F)
instead of DRI_PRIME=1, which on Intel+AMD hybrids flips OpenGL to the
iGPU and breaks CL/GL interop. switcherooctl branch removed (same bug).
- MESA_VK_DEVICE_SELECT pin added as defense-in-depth for Vulkan.
- Full glib-family symlink swap: all five of libglib-2.0, libgio-2.0,
libgmodule-2.0, libgobject-2.0, libgthread-2.0 (was three; mismatch
caused latent segfaults on signal emit / type registration).
- Manual install to /opt/resolve via ZIP -> .run -> appimage-extract ->
rsync, with patchelf --set-rpath on every ELF (replaces AUR PKGBUILD
approach).
- Auto-wipe stale ~/.local/share/DaVinciResolve/{configs,logs} on fresh
installs and whenever known crash markers appear in ResolveDebug.txt.
- Generation-aware gfx target detection (gfx1030/1100/1101/1102/1200/1201)
with auto HSA_OVERRIDE_GFX_VERSION for non-natively-supported cards.
- Hyprland windowrule v3 syntax; dropped stay_focused (trapped-cursor in
modals); removed duplicate user-level .desktop entry; removed unused
Studio USB-dongle udev rule.
Docs:
- Rewrite README to match v4.1 reality (manual /opt/resolve install,
ROCm pinning rationale, hybrid-GPU PCI-tag note, refreshed GPU support
tiers, corrected uninstall steps).
- Add NOTES.md with full root-cause analysis, currently-pinned package
versions, recovery playbook, and quick sanity checks.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2313 lines
89 KiB
Bash
Executable file
2313 lines
89 KiB
Bash
Executable file
#!/bin/bash
|
|
|
|
# =============================================================================
|
|
# DaVinci Resolve Free - Arch Linux + AMD (RDNA2/3/4) + Hyprland Install Script
|
|
# =============================================================================
|
|
#
|
|
# Version 4.1 - Mirrors the proven NVIDIA-Open install path; only the GPU
|
|
# stack (ROCm vs CUDA) and HSA_OVERRIDE handling differ.
|
|
# 4.1: pinned ROCm 7.1.1 from Arch Linux Archive as default OpenCL provider,
|
|
# because Arch's current ROCm 7.2.x breaks DaVinci Resolve on AMD.
|
|
#
|
|
# Install method (shared with NVIDIA script):
|
|
# 1. Find the Resolve ZIP in ~/Downloads/
|
|
# 2. unzip ZIP -> .run AppImage -> --appimage-extract -> squashfs-root
|
|
# 3. Replace bundled glib/gio/gmodule with system symlinks (ABI-safe)
|
|
# KEEP vendored libc++/libc++abi (removing breaks Resolve)
|
|
# 4. rsync to /opt/resolve, patchelf --set-rpath every ELF
|
|
# 5. Install desktop entries, icons, udev rules system-wide
|
|
# 6. Apply audio fixes: DeckLink->ALSA, snd-aloop, PipeWire bridge
|
|
# 7. Apply Hyprland window rules and create XWayland launcher
|
|
#
|
|
# AMD-specific bits:
|
|
# - ROCm 7.2 (Arch extra) for OpenCL, with auto-detected HSA_OVERRIDE for
|
|
# RDNA2/3/4 cards that aren't natively in ROCm's supported list
|
|
# - Generation-aware gfx target detection (gfx1030/1100/1101/1102/1200/1201)
|
|
# - switcherooctl integration for hybrid Intel/AMD systems
|
|
# - BlackmagicRaw OpenCL decoder disable (prevents ROCm conflicts)
|
|
#
|
|
# Pacman does NOT track this install. To remove:
|
|
# sudo rm -rf /opt/resolve
|
|
# sudo rm -f /usr/share/applications/{DaVinciResolve,blackmagicraw-*}.desktop
|
|
# sudo rm -f /usr/lib/udev/rules.d/{99-BlackmagicDevices,99-ResolveKeyboardHID,99-DavinciPanel}.rules
|
|
#
|
|
# Based on techniques from:
|
|
# - The Omarchy NVIDIA-Open Resolve installer (this script is its mirror)
|
|
# - https://github.com/zelikos/davincibox
|
|
# - https://wiki.archlinux.org/title/DaVinci_Resolve
|
|
#
|
|
# Usage:
|
|
# chmod +x install-davinci-resolve.sh
|
|
# ./install-davinci-resolve.sh
|
|
#
|
|
# Env vars:
|
|
# RESOLVE_NO_ALOOP=1 Skip snd-aloop setup (you have a real audio interface)
|
|
#
|
|
# =============================================================================
|
|
|
|
set -e
|
|
|
|
# Colors for output
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
CYAN='\033[0;36m'
|
|
MAGENTA='\033[0;35m'
|
|
BOLD='\033[1m'
|
|
NC='\033[0m' # No Color
|
|
|
|
# Logging functions
|
|
info() { echo -e "${BLUE}[INFO]${NC} $1"; }
|
|
success() { echo -e "${GREEN}[OK]${NC} $1"; }
|
|
warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
|
|
error() { echo -e "${RED}[ERROR]${NC} $1"; exit 1; }
|
|
header() { echo -e "\n${CYAN}=== $1 ===${NC}\n"; }
|
|
scan_item() { echo -e " ${MAGENTA}•${NC} $1: ${BOLD}$2${NC}"; }
|
|
|
|
# =============================================================================
|
|
# CONFIGURATION OPTIONS
|
|
# =============================================================================
|
|
|
|
# OpenCL Provider:
|
|
# "rocm-pinned-7.1.1" - DEFAULT. ROCm 7.1.1 stack from Arch Linux Archive,
|
|
# pinned in /etc/pacman.conf IgnorePkg. This is the
|
|
# ONLY currently-known-working configuration for
|
|
# DaVinci Resolve on AMD as of May 2026.
|
|
# Confirmed by CachyOS community + this script's
|
|
# own testing on RX 9060 XT (Navi 44, gfx1200).
|
|
# Refs:
|
|
# https://github.com/ROCm/ROCm/issues/5982
|
|
# https://discuss.cachyos.org/t/davinci-resolve-amd-rocm-fails-without-downgrade/28036
|
|
# "rocm-full" - Current Arch repos ROCm 7.2.x. KNOWN BROKEN with
|
|
# DaVinci Resolve - clCreateContext fails or hangs
|
|
# on Color page. Will work again when ROCm 7.3+ ships.
|
|
# "opencl-amd" - AUR opencl-amd 7.2.x. Same ROCm 7.2 ABI bug.
|
|
# KNOWN BROKEN with Resolve currently.
|
|
OPENCL_PROVIDER="rocm-pinned-7.1.1"
|
|
|
|
# =============================================================================
|
|
# SYSTEM SCAN VARIABLES (populated during scan)
|
|
# =============================================================================
|
|
|
|
# System info
|
|
SCAN_KERNEL_VERSION=""
|
|
SCAN_KERNEL_MAJOR=0
|
|
SCAN_KERNEL_MINOR=0
|
|
SCAN_ARCH=""
|
|
|
|
# GPU info - Single GPU (legacy/primary)
|
|
SCAN_GPU_VENDOR=""
|
|
SCAN_GPU_MODEL=""
|
|
SCAN_GPU_DRIVER=""
|
|
SCAN_GPU_RDNA_VERSION=""
|
|
SCAN_IS_RDNA4=false
|
|
|
|
# GPU info - Multi-GPU support
|
|
SCAN_GPU_COUNT=0
|
|
SCAN_GPUS=()
|
|
SCAN_GPU_VENDORS=()
|
|
SCAN_GPU_MODELS=()
|
|
SCAN_GPU_TYPES=()
|
|
SCAN_GPU_PCI_IDS=()
|
|
SCAN_GPU_RDNA_VERSIONS=()
|
|
SCAN_GPU_GFX_TARGETS=() # Per-GPU gfx target (e.g. gfx1030, gfx1102, gfx1200)
|
|
SCAN_GPU_HSA_OVERRIDES=() # Per-GPU recommended HSA_OVERRIDE_GFX_VERSION ("" if natively supported)
|
|
SCAN_GPU_DRIVERS_LOADED=()
|
|
SCAN_PRIMARY_GPU_INDEX=0
|
|
SCAN_HSA_OVERRIDE_VALUE="" # Set from primary GPU after scan
|
|
SCAN_GFX_TARGET="" # Set from primary GPU after scan
|
|
|
|
# Hybrid GPU flags
|
|
SCAN_HAS_IGPU=false
|
|
SCAN_HAS_DGPU=false
|
|
SCAN_HAS_AMD_DGPU=false
|
|
SCAN_HAS_NVIDIA_DGPU=false
|
|
SCAN_HAS_AMD_IGPU=false
|
|
SCAN_HAS_INTEL_IGPU=false
|
|
SCAN_IS_HYBRID=false
|
|
SCAN_PRIME_AVAILABLE=false
|
|
|
|
# Mesa/Graphics
|
|
SCAN_MESA_VERSION=""
|
|
SCAN_MESA_MAJOR=0
|
|
SCAN_VULKAN_AVAILABLE=false
|
|
SCAN_OPENGL_RENDERER=""
|
|
|
|
# OpenCL
|
|
SCAN_OPENCL_INSTALLED=false
|
|
SCAN_OPENCL_PROVIDER=""
|
|
SCAN_OPENCL_PLATFORMS=""
|
|
SCAN_AMD_OPENCL_WORKING=false
|
|
|
|
# Audio
|
|
SCAN_AUDIO_SERVER=""
|
|
SCAN_PIPEWIRE_INSTALLED=false
|
|
SCAN_PULSEAUDIO_INSTALLED=false
|
|
|
|
# Display
|
|
SCAN_DISPLAY_SERVER=""
|
|
SCAN_COMPOSITOR=""
|
|
SCAN_HYPRLAND_INSTALLED=false
|
|
SCAN_HYPRLAND_RUNNING=false
|
|
|
|
# DaVinci Resolve
|
|
SCAN_RESOLVE_INSTALLED=false
|
|
SCAN_RESOLVE_VERSION=""
|
|
SCAN_RESOLVE_PATH=""
|
|
|
|
# Package manager
|
|
SCAN_AUR_HELPER=""
|
|
|
|
# Disk space
|
|
SCAN_ROOT_FREE_GB=0
|
|
SCAN_HOME_FREE_GB=0
|
|
|
|
# Existing packages (to avoid reinstalling)
|
|
SCAN_INSTALLED_PACKAGES=""
|
|
|
|
# =============================================================================
|
|
# SYSTEM SCAN FUNCTIONS
|
|
# =============================================================================
|
|
|
|
scan_kernel() {
|
|
SCAN_KERNEL_VERSION=$(uname -r)
|
|
SCAN_KERNEL_MAJOR=$(echo "$SCAN_KERNEL_VERSION" | cut -d'.' -f1)
|
|
SCAN_KERNEL_MINOR=$(echo "$SCAN_KERNEL_VERSION" | cut -d'.' -f2)
|
|
SCAN_ARCH=$(uname -m)
|
|
}
|
|
|
|
scan_gpu() {
|
|
# Arrays for multi-GPU detection
|
|
SCAN_GPU_COUNT=0
|
|
SCAN_GPUS=() # Array of GPU info strings
|
|
SCAN_GPU_VENDORS=() # Array of vendors
|
|
SCAN_GPU_MODELS=() # Array of models
|
|
SCAN_GPU_TYPES=() # "integrated" or "discrete"
|
|
SCAN_GPU_PCI_IDS=() # PCI bus IDs
|
|
|
|
# Flags for GPU types present
|
|
SCAN_HAS_IGPU=false
|
|
SCAN_HAS_DGPU=false
|
|
SCAN_HAS_AMD_DGPU=false
|
|
SCAN_HAS_NVIDIA_DGPU=false
|
|
SCAN_HAS_AMD_IGPU=false
|
|
SCAN_HAS_INTEL_IGPU=false
|
|
SCAN_IS_HYBRID=false
|
|
|
|
# Primary GPU for DaVinci Resolve (discrete preferred)
|
|
SCAN_PRIMARY_GPU_INDEX=0
|
|
|
|
if ! command -v lspci &>/dev/null; then
|
|
return
|
|
fi
|
|
|
|
# Get all GPUs
|
|
while IFS= read -r gpu_line; do
|
|
[[ -z "$gpu_line" ]] && continue
|
|
|
|
local pci_id=$(echo "$gpu_line" | cut -d' ' -f1)
|
|
local gpu_info=$(echo "$gpu_line" | sed 's/^[^ ]* //' | sed 's/.*: //')
|
|
local vendor=""
|
|
local gpu_type="discrete" # Default assumption
|
|
local rdna_ver=""
|
|
|
|
# Detect vendor and type.
|
|
# Order matters: check Intel/NVIDIA first because "ATI" matches
|
|
# "Corpor[ATI]on" in Intel/NVIDIA lspci lines case-insensitively.
|
|
if echo "$gpu_line" | grep -qi "Intel"; then
|
|
vendor="Intel"
|
|
gpu_type="integrated"
|
|
SCAN_HAS_IGPU=true
|
|
SCAN_HAS_INTEL_IGPU=true
|
|
rdna_ver="N/A"
|
|
|
|
elif echo "$gpu_line" | grep -qi "NVIDIA"; then
|
|
vendor="NVIDIA"
|
|
gpu_type="discrete"
|
|
SCAN_HAS_DGPU=true
|
|
SCAN_HAS_NVIDIA_DGPU=true
|
|
rdna_ver="N/A"
|
|
|
|
elif echo "$gpu_line" | grep -qiE '\bAMD\b|\bATI\b|Radeon'; then
|
|
vendor="AMD"
|
|
|
|
# Check if integrated (APU) - common identifiers
|
|
if echo "$gpu_line" | grep -qiE "Radeon.*(Graphics|Vega|RX Vega|Renoir|Cezanne|Barcelo|Rembrandt|Phoenix|Hawk|Strix Point)|AMD.*Ryzen.*Radeon|Integrated"; then
|
|
gpu_type="integrated"
|
|
SCAN_HAS_IGPU=true
|
|
SCAN_HAS_AMD_IGPU=true
|
|
else
|
|
gpu_type="discrete"
|
|
SCAN_HAS_DGPU=true
|
|
SCAN_HAS_AMD_DGPU=true
|
|
fi
|
|
|
|
# Detect RDNA generation
|
|
if echo "$gpu_line" | grep -qiE "9070|9080|Navi 4|gfx1201"; then
|
|
rdna_ver="RDNA4"
|
|
SCAN_IS_RDNA4=true
|
|
elif echo "$gpu_line" | grep -qiE "7[0-9]{3}|Navi 3|gfx11"; then
|
|
rdna_ver="RDNA3"
|
|
elif echo "$gpu_line" | grep -qiE "6[0-9]{3}|Navi 2|gfx103"; then
|
|
rdna_ver="RDNA2"
|
|
elif echo "$gpu_line" | grep -qiE "5[0-9]{3}|Navi 1|gfx101"; then
|
|
rdna_ver="RDNA1"
|
|
elif echo "$gpu_line" | grep -qiE "Vega|gfx9"; then
|
|
rdna_ver="Vega"
|
|
elif echo "$gpu_line" | grep -qiE "Phoenix|Hawk Point|Strix"; then
|
|
rdna_ver="RDNA3 (iGPU)"
|
|
elif echo "$gpu_line" | grep -qiE "Rembrandt|Barcelo"; then
|
|
rdna_ver="RDNA2 (iGPU)"
|
|
else
|
|
rdna_ver="Pre-RDNA/GCN"
|
|
fi
|
|
|
|
# Detect gfx target and required HSA_OVERRIDE_GFX_VERSION.
|
|
# ROCm 7.2 officially supports: gfx1030, gfx1100, gfx1101, gfx1200, gfx1201.
|
|
# Other RDNA2/3 silicon needs HSA_OVERRIDE to spoof as the nearest supported target.
|
|
local gfx_target=""
|
|
local hsa_override=""
|
|
|
|
# RDNA4 - all natively supported
|
|
if echo "$gpu_line" | grep -qiE "Navi 48|9070|9080|gfx1201"; then
|
|
gfx_target="gfx1201"
|
|
elif echo "$gpu_line" | grep -qiE "Navi 44|RX 90[6-9][0-9]|gfx1200"; then
|
|
gfx_target="gfx1200"
|
|
|
|
# RDNA3
|
|
elif echo "$gpu_line" | grep -qiE "Navi 31|RX 79[0-9]{2}|gfx1100"; then
|
|
gfx_target="gfx1100"
|
|
elif echo "$gpu_line" | grep -qiE "Navi 32|RX 7[78][0-9]{2}|gfx1101"; then
|
|
gfx_target="gfx1101"
|
|
elif echo "$gpu_line" | grep -qiE "Navi 33|RX 76[0-9]{2}|gfx1102"; then
|
|
gfx_target="gfx1102"
|
|
hsa_override="11.0.0" # gfx1102 not natively supported, spoof as gfx1100
|
|
|
|
# RDNA2
|
|
elif echo "$gpu_line" | grep -qiE "Navi 21|RX 6[89][0-9]{2}|gfx1030"; then
|
|
gfx_target="gfx1030"
|
|
elif echo "$gpu_line" | grep -qiE "Navi 22|RX 67[0-9]{2}|gfx1031"; then
|
|
gfx_target="gfx1031"
|
|
hsa_override="10.3.0" # spoof as gfx1030
|
|
elif echo "$gpu_line" | grep -qiE "Navi 23|RX 66[0-9]{2}|gfx1032"; then
|
|
gfx_target="gfx1032"
|
|
hsa_override="10.3.0"
|
|
elif echo "$gpu_line" | grep -qiE "Navi 24|RX 6[45][0-9]{2}|gfx1034"; then
|
|
gfx_target="gfx1034"
|
|
hsa_override="10.3.0"
|
|
fi
|
|
fi
|
|
|
|
# Store GPU info
|
|
SCAN_GPUS+=("$gpu_info")
|
|
SCAN_GPU_VENDORS+=("$vendor")
|
|
SCAN_GPU_MODELS+=("$gpu_info")
|
|
SCAN_GPU_TYPES+=("$gpu_type")
|
|
SCAN_GPU_PCI_IDS+=("$pci_id")
|
|
|
|
# Store RDNA version, gfx target, and HSA override for AMD GPUs
|
|
if [[ "$vendor" == "AMD" ]]; then
|
|
SCAN_GPU_RDNA_VERSIONS+=("$rdna_ver")
|
|
SCAN_GPU_GFX_TARGETS+=("$gfx_target")
|
|
SCAN_GPU_HSA_OVERRIDES+=("$hsa_override")
|
|
else
|
|
SCAN_GPU_RDNA_VERSIONS+=("")
|
|
SCAN_GPU_GFX_TARGETS+=("")
|
|
SCAN_GPU_HSA_OVERRIDES+=("")
|
|
fi
|
|
|
|
SCAN_GPU_COUNT=$((SCAN_GPU_COUNT + 1))
|
|
|
|
done < <(lspci 2>/dev/null | grep -iE "VGA|3D|Display")
|
|
|
|
# Detect hybrid graphics
|
|
if [[ "$SCAN_HAS_IGPU" == true && "$SCAN_HAS_DGPU" == true ]]; then
|
|
SCAN_IS_HYBRID=true
|
|
fi
|
|
|
|
# Select primary GPU for DaVinci Resolve (prefer discrete AMD, then discrete NVIDIA, then any AMD)
|
|
for i in "${!SCAN_GPU_VENDORS[@]}"; do
|
|
if [[ "${SCAN_GPU_VENDORS[$i]}" == "AMD" && "${SCAN_GPU_TYPES[$i]}" == "discrete" ]]; then
|
|
SCAN_PRIMARY_GPU_INDEX=$i
|
|
break
|
|
fi
|
|
done
|
|
|
|
# If no discrete AMD, check for discrete NVIDIA
|
|
if [[ ${#SCAN_GPU_TYPES[@]} -gt 0 && "${SCAN_GPU_TYPES[$SCAN_PRIMARY_GPU_INDEX]}" != "discrete" ]]; then
|
|
for i in "${!SCAN_GPU_VENDORS[@]}"; do
|
|
if [[ "${SCAN_GPU_VENDORS[$i]}" == "NVIDIA" && "${SCAN_GPU_TYPES[$i]}" == "discrete" ]]; then
|
|
SCAN_PRIMARY_GPU_INDEX=$i
|
|
break
|
|
fi
|
|
done
|
|
fi
|
|
|
|
# Set legacy variables for compatibility (using primary GPU)
|
|
if [[ $SCAN_GPU_COUNT -gt 0 ]]; then
|
|
SCAN_GPU_VENDOR="${SCAN_GPU_VENDORS[$SCAN_PRIMARY_GPU_INDEX]}"
|
|
SCAN_GPU_MODEL="${SCAN_GPU_MODELS[$SCAN_PRIMARY_GPU_INDEX]}"
|
|
SCAN_GPU_RDNA_VERSION="${SCAN_GPU_RDNA_VERSIONS[$SCAN_PRIMARY_GPU_INDEX]}"
|
|
SCAN_GFX_TARGET="${SCAN_GPU_GFX_TARGETS[$SCAN_PRIMARY_GPU_INDEX]}"
|
|
SCAN_HSA_OVERRIDE_VALUE="${SCAN_GPU_HSA_OVERRIDES[$SCAN_PRIMARY_GPU_INDEX]}"
|
|
fi
|
|
|
|
# Check loaded kernel drivers
|
|
SCAN_GPU_DRIVERS_LOADED=()
|
|
if lsmod 2>/dev/null | grep -q "^amdgpu"; then
|
|
SCAN_GPU_DRIVERS_LOADED+=("amdgpu")
|
|
SCAN_GPU_DRIVER="amdgpu"
|
|
fi
|
|
if lsmod 2>/dev/null | grep -q "^nvidia"; then
|
|
SCAN_GPU_DRIVERS_LOADED+=("nvidia")
|
|
[[ -z "$SCAN_GPU_DRIVER" ]] && SCAN_GPU_DRIVER="nvidia"
|
|
fi
|
|
if lsmod 2>/dev/null | grep -q "^i915"; then
|
|
SCAN_GPU_DRIVERS_LOADED+=("i915")
|
|
[[ -z "$SCAN_GPU_DRIVER" ]] && SCAN_GPU_DRIVER="i915"
|
|
fi
|
|
if lsmod 2>/dev/null | grep -q "^radeon"; then
|
|
SCAN_GPU_DRIVERS_LOADED+=("radeon")
|
|
fi
|
|
|
|
# Detect DRI_PRIME / PRIME render offload status
|
|
SCAN_PRIME_AVAILABLE=false
|
|
if [[ "$SCAN_IS_HYBRID" == true ]]; then
|
|
# Check if DRI_PRIME would work
|
|
if [[ -d "/sys/class/drm" ]]; then
|
|
local render_nodes=$(ls /dev/dri/renderD* 2>/dev/null | wc -l)
|
|
if [[ $render_nodes -gt 1 ]]; then
|
|
SCAN_PRIME_AVAILABLE=true
|
|
fi
|
|
fi
|
|
fi
|
|
}
|
|
|
|
scan_mesa() {
|
|
if command -v glxinfo &>/dev/null; then
|
|
SCAN_MESA_VERSION=$(glxinfo 2>/dev/null | grep "OpenGL version" | grep -oP "Mesa \K[0-9]+\.[0-9]+(\.[0-9]+)?" || echo "")
|
|
SCAN_OPENGL_RENDERER=$(glxinfo 2>/dev/null | grep "OpenGL renderer" | sed 's/OpenGL renderer string: //' || echo "")
|
|
|
|
if [[ -n "$SCAN_MESA_VERSION" ]]; then
|
|
SCAN_MESA_MAJOR=$(echo "$SCAN_MESA_VERSION" | cut -d'.' -f1)
|
|
fi
|
|
fi
|
|
|
|
# Check Vulkan
|
|
if command -v vulkaninfo &>/dev/null && vulkaninfo --summary &>/dev/null; then
|
|
SCAN_VULKAN_AVAILABLE=true
|
|
fi
|
|
}
|
|
|
|
scan_opencl() {
|
|
# Check what OpenCL packages are installed
|
|
# Check for full ROCm stack first (preferred for RDNA4)
|
|
if pacman -Qq rocm-opencl-runtime &>/dev/null; then
|
|
SCAN_OPENCL_INSTALLED=true
|
|
# Check if full ROCm stack is installed
|
|
if pacman -Qq rocm-hip-runtime rocm-core &>/dev/null; then
|
|
SCAN_OPENCL_PROVIDER="rocm-full"
|
|
# Get ROCm version
|
|
local rocm_ver=$(pacman -Q rocm-core 2>/dev/null | awk '{print $2}' | cut -d'-' -f1)
|
|
[[ -n "$rocm_ver" ]] && SCAN_OPENCL_PROVIDER="rocm-full ($rocm_ver)"
|
|
else
|
|
SCAN_OPENCL_PROVIDER="rocm-opencl-runtime"
|
|
fi
|
|
elif pacman -Qq opencl-amd &>/dev/null; then
|
|
SCAN_OPENCL_INSTALLED=true
|
|
SCAN_OPENCL_PROVIDER="opencl-amd"
|
|
elif pacman -Qq mesa-opencl &>/dev/null || pacman -Qq opencl-mesa &>/dev/null; then
|
|
SCAN_OPENCL_INSTALLED=true
|
|
SCAN_OPENCL_PROVIDER="mesa (rusticl)"
|
|
elif pacman -Qq intel-compute-runtime &>/dev/null; then
|
|
SCAN_OPENCL_INSTALLED=true
|
|
SCAN_OPENCL_PROVIDER="intel-compute-runtime"
|
|
fi
|
|
|
|
# Check if OpenCL actually works with AMD
|
|
if command -v clinfo &>/dev/null; then
|
|
SCAN_OPENCL_PLATFORMS=$(clinfo --list 2>/dev/null | head -5 || echo "")
|
|
if clinfo --list 2>/dev/null | grep -qi "AMD\|gfx\|Radeon"; then
|
|
SCAN_AMD_OPENCL_WORKING=true
|
|
fi
|
|
fi
|
|
}
|
|
|
|
scan_audio() {
|
|
# Detect audio server
|
|
if command -v pactl &>/dev/null; then
|
|
local server_name=$(pactl info 2>/dev/null | grep "Server Name" || echo "")
|
|
if echo "$server_name" | grep -qi "PipeWire"; then
|
|
SCAN_AUDIO_SERVER="PipeWire"
|
|
SCAN_PIPEWIRE_INSTALLED=true
|
|
elif echo "$server_name" | grep -qi "PulseAudio"; then
|
|
SCAN_AUDIO_SERVER="PulseAudio"
|
|
SCAN_PULSEAUDIO_INSTALLED=true
|
|
fi
|
|
fi
|
|
|
|
# Double-check with package detection
|
|
if pacman -Qq pipewire &>/dev/null; then
|
|
SCAN_PIPEWIRE_INSTALLED=true
|
|
fi
|
|
if pacman -Qq pulseaudio &>/dev/null; then
|
|
SCAN_PULSEAUDIO_INSTALLED=true
|
|
fi
|
|
|
|
# If we couldn't detect from pactl, use package info
|
|
if [[ -z "$SCAN_AUDIO_SERVER" ]]; then
|
|
if [[ "$SCAN_PIPEWIRE_INSTALLED" == true ]]; then
|
|
SCAN_AUDIO_SERVER="PipeWire (detected from packages)"
|
|
elif [[ "$SCAN_PULSEAUDIO_INSTALLED" == true ]]; then
|
|
SCAN_AUDIO_SERVER="PulseAudio (detected from packages)"
|
|
else
|
|
SCAN_AUDIO_SERVER="Unknown/None"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
scan_display() {
|
|
# Detect display server
|
|
if [[ -n "$WAYLAND_DISPLAY" ]]; then
|
|
SCAN_DISPLAY_SERVER="Wayland"
|
|
elif [[ "$XDG_SESSION_TYPE" == "wayland" ]]; then
|
|
# Wayland session but WAYLAND_DISPLAY not set (XWayland context)
|
|
SCAN_DISPLAY_SERVER="Wayland (XWayland available)"
|
|
elif [[ -n "$DISPLAY" ]]; then
|
|
SCAN_DISPLAY_SERVER="X11"
|
|
else
|
|
SCAN_DISPLAY_SERVER="None/TTY"
|
|
fi
|
|
|
|
# Detect compositor
|
|
if [[ -n "$HYPRLAND_INSTANCE_SIGNATURE" ]]; then
|
|
SCAN_COMPOSITOR="Hyprland"
|
|
SCAN_HYPRLAND_RUNNING=true
|
|
elif [[ -n "$SWAYSOCK" ]]; then
|
|
SCAN_COMPOSITOR="Sway"
|
|
elif [[ -n "$GNOME_DESKTOP_SESSION_ID" ]]; then
|
|
SCAN_COMPOSITOR="GNOME"
|
|
elif [[ -n "$KDE_FULL_SESSION" ]]; then
|
|
SCAN_COMPOSITOR="KDE Plasma"
|
|
elif pgrep -x "hyprland" &>/dev/null; then
|
|
SCAN_COMPOSITOR="Hyprland"
|
|
SCAN_HYPRLAND_RUNNING=true
|
|
else
|
|
SCAN_COMPOSITOR="Unknown"
|
|
fi
|
|
|
|
# Check if Hyprland is installed
|
|
if pacman -Qq hyprland &>/dev/null || command -v Hyprland &>/dev/null; then
|
|
SCAN_HYPRLAND_INSTALLED=true
|
|
fi
|
|
}
|
|
|
|
scan_resolve() {
|
|
# Check if DaVinci Resolve is installed
|
|
if [[ -d "/opt/resolve" ]] || [[ -f "/opt/resolve/bin/resolve" ]]; then
|
|
SCAN_RESOLVE_INSTALLED=true
|
|
SCAN_RESOLVE_PATH="/opt/resolve"
|
|
|
|
# Try to get version
|
|
if [[ -f "/opt/resolve/docs/License.txt" ]]; then
|
|
SCAN_RESOLVE_VERSION=$(grep -oP "DaVinci Resolve \K[0-9]+\.[0-9]+(\.[0-9]+)?" /opt/resolve/docs/License.txt 2>/dev/null | head -1 || echo "Unknown")
|
|
fi
|
|
fi
|
|
|
|
# Also check via pacman
|
|
if pacman -Qq davinci-resolve &>/dev/null || pacman -Qq davinci-resolve-studio &>/dev/null; then
|
|
SCAN_RESOLVE_INSTALLED=true
|
|
fi
|
|
}
|
|
|
|
scan_aur_helper() {
|
|
if command -v paru &>/dev/null; then
|
|
SCAN_AUR_HELPER="paru"
|
|
elif command -v yay &>/dev/null; then
|
|
SCAN_AUR_HELPER="yay"
|
|
elif command -v trizen &>/dev/null; then
|
|
SCAN_AUR_HELPER="trizen"
|
|
elif command -v pikaur &>/dev/null; then
|
|
SCAN_AUR_HELPER="pikaur"
|
|
else
|
|
SCAN_AUR_HELPER=""
|
|
fi
|
|
}
|
|
|
|
scan_disk_space() {
|
|
# Get free space in GB
|
|
SCAN_ROOT_FREE_GB=$(df -BG / 2>/dev/null | awk 'NR==2 {print $4}' | tr -d 'G' || echo "0")
|
|
SCAN_HOME_FREE_GB=$(df -BG "$HOME" 2>/dev/null | awk 'NR==2 {print $4}' | tr -d 'G' || echo "0")
|
|
}
|
|
|
|
scan_installed_packages() {
|
|
# Get list of installed packages for comparison
|
|
SCAN_INSTALLED_PACKAGES=$(pacman -Qq 2>/dev/null || echo "")
|
|
}
|
|
|
|
is_pkg_installed() {
|
|
echo "$SCAN_INSTALLED_PACKAGES" | grep -qx "$1"
|
|
}
|
|
|
|
# =============================================================================
|
|
# MAIN SYSTEM SCAN
|
|
# =============================================================================
|
|
|
|
run_system_scan() {
|
|
header "System Scan"
|
|
|
|
echo -e "${BOLD}Scanning your system to optimize installation...${NC}\n"
|
|
|
|
# Run all scans
|
|
echo -n " Scanning kernel... "
|
|
scan_kernel
|
|
echo -e "${GREEN}done${NC}"
|
|
|
|
echo -n " Scanning GPU... "
|
|
scan_gpu
|
|
echo -e "${GREEN}done${NC}"
|
|
|
|
echo -n " Scanning graphics stack... "
|
|
scan_mesa
|
|
echo -e "${GREEN}done${NC}"
|
|
|
|
echo -n " Scanning OpenCL... "
|
|
scan_opencl
|
|
echo -e "${GREEN}done${NC}"
|
|
|
|
echo -n " Scanning audio... "
|
|
scan_audio
|
|
echo -e "${GREEN}done${NC}"
|
|
|
|
echo -n " Scanning display... "
|
|
scan_display
|
|
echo -e "${GREEN}done${NC}"
|
|
|
|
echo -n " Scanning for DaVinci Resolve... "
|
|
scan_resolve
|
|
echo -e "${GREEN}done${NC}"
|
|
|
|
echo -n " Scanning AUR helpers... "
|
|
scan_aur_helper
|
|
echo -e "${GREEN}done${NC}"
|
|
|
|
echo -n " Scanning disk space... "
|
|
scan_disk_space
|
|
echo -e "${GREEN}done${NC}"
|
|
|
|
echo -n " Scanning installed packages... "
|
|
scan_installed_packages
|
|
echo -e "${GREEN}done${NC}"
|
|
|
|
echo ""
|
|
}
|
|
|
|
# =============================================================================
|
|
# DISPLAY SCAN RESULTS
|
|
# =============================================================================
|
|
|
|
display_scan_results() {
|
|
header "System Configuration Detected"
|
|
|
|
echo -e "${BOLD}System:${NC}"
|
|
scan_item "Kernel" "$SCAN_KERNEL_VERSION"
|
|
scan_item "Architecture" "$SCAN_ARCH"
|
|
|
|
echo ""
|
|
echo -e "${BOLD}GPU(s) Detected: ${SCAN_GPU_COUNT}${NC}"
|
|
|
|
if [[ $SCAN_GPU_COUNT -eq 0 ]]; then
|
|
scan_item "GPU" "None detected"
|
|
else
|
|
for i in "${!SCAN_GPUS[@]}"; do
|
|
local gpu_label="GPU $((i+1))"
|
|
local gpu_type_label="${SCAN_GPU_TYPES[$i]}"
|
|
local vendor="${SCAN_GPU_VENDORS[$i]}"
|
|
|
|
# Mark primary GPU
|
|
local primary_marker=""
|
|
if [[ $i -eq $SCAN_PRIMARY_GPU_INDEX ]]; then
|
|
primary_marker=" ${GREEN}← PRIMARY${NC}"
|
|
fi
|
|
|
|
echo ""
|
|
echo -e " ${BOLD}$gpu_label ($gpu_type_label):${NC}$primary_marker"
|
|
echo -e " Vendor: ${SCAN_GPU_VENDORS[$i]}"
|
|
echo -e " Model: ${SCAN_GPU_MODELS[$i]}"
|
|
|
|
if [[ "$vendor" == "AMD" && -n "${SCAN_GPU_RDNA_VERSIONS[$i]}" ]]; then
|
|
echo -e " Gen: ${SCAN_GPU_RDNA_VERSIONS[$i]}"
|
|
fi
|
|
|
|
if [[ "$vendor" == "AMD" && -n "${SCAN_GPU_GFX_TARGETS[$i]}" ]]; then
|
|
local override_note=""
|
|
if [[ -n "${SCAN_GPU_HSA_OVERRIDES[$i]}" ]]; then
|
|
override_note=" ${YELLOW}(needs HSA_OVERRIDE_GFX_VERSION=${SCAN_GPU_HSA_OVERRIDES[$i]})${NC}"
|
|
else
|
|
override_note=" ${GREEN}(natively supported)${NC}"
|
|
fi
|
|
echo -e " GFX: ${SCAN_GPU_GFX_TARGETS[$i]}$override_note"
|
|
fi
|
|
|
|
echo -e " PCI: ${SCAN_GPU_PCI_IDS[$i]}"
|
|
done
|
|
|
|
echo ""
|
|
if [[ "$SCAN_IS_HYBRID" == true ]]; then
|
|
echo -e " ${YELLOW}⚡ Hybrid Graphics Detected${NC}"
|
|
if [[ "$SCAN_PRIME_AVAILABLE" == true ]]; then
|
|
echo -e " DRI_PRIME offloading available"
|
|
fi
|
|
fi
|
|
|
|
if [[ ${#SCAN_GPU_DRIVERS_LOADED[@]} -gt 0 ]]; then
|
|
echo -e " Loaded drivers: ${SCAN_GPU_DRIVERS_LOADED[*]}"
|
|
fi
|
|
fi
|
|
|
|
echo ""
|
|
echo -e "${BOLD}Graphics Stack:${NC}"
|
|
scan_item "Mesa" "${SCAN_MESA_VERSION:-Not detected}"
|
|
scan_item "OpenGL Renderer" "${SCAN_OPENGL_RENDERER:-Not detected}"
|
|
scan_item "Vulkan" "$( [[ "$SCAN_VULKAN_AVAILABLE" == true ]] && echo "Available" || echo "Not available" )"
|
|
|
|
echo ""
|
|
echo -e "${BOLD}OpenCL:${NC}"
|
|
if [[ "$SCAN_OPENCL_INSTALLED" == true ]]; then
|
|
scan_item "Provider" "$SCAN_OPENCL_PROVIDER"
|
|
scan_item "AMD Working" "$( [[ "$SCAN_AMD_OPENCL_WORKING" == true ]] && echo "Yes ✓" || echo "No ✗" )"
|
|
else
|
|
scan_item "Status" "Not installed"
|
|
fi
|
|
|
|
echo ""
|
|
echo -e "${BOLD}Audio:${NC}"
|
|
scan_item "Server" "$SCAN_AUDIO_SERVER"
|
|
|
|
echo ""
|
|
echo -e "${BOLD}Display:${NC}"
|
|
scan_item "Server" "$SCAN_DISPLAY_SERVER"
|
|
scan_item "Compositor" "$SCAN_COMPOSITOR"
|
|
scan_item "Hyprland" "$( [[ "$SCAN_HYPRLAND_INSTALLED" == true ]] && echo "Installed" || echo "Not installed" )"
|
|
|
|
echo ""
|
|
echo -e "${BOLD}DaVinci Resolve:${NC}"
|
|
if [[ "$SCAN_RESOLVE_INSTALLED" == true ]]; then
|
|
scan_item "Status" "Installed"
|
|
scan_item "Version" "${SCAN_RESOLVE_VERSION:-Unknown}"
|
|
scan_item "Path" "$SCAN_RESOLVE_PATH"
|
|
else
|
|
scan_item "Status" "Not installed"
|
|
fi
|
|
|
|
echo ""
|
|
echo -e "${BOLD}Package Management:${NC}"
|
|
scan_item "AUR Helper" "${SCAN_AUR_HELPER:-None detected}"
|
|
|
|
echo ""
|
|
echo -e "${BOLD}Disk Space:${NC}"
|
|
scan_item "Root partition" "${SCAN_ROOT_FREE_GB}GB free"
|
|
scan_item "Home partition" "${SCAN_HOME_FREE_GB}GB free"
|
|
|
|
echo ""
|
|
}
|
|
|
|
# =============================================================================
|
|
# ANALYZE SCAN AND PROVIDE RECOMMENDATIONS
|
|
# =============================================================================
|
|
|
|
analyze_scan_results() {
|
|
header "Analysis & Recommendations"
|
|
|
|
local issues=0
|
|
local warnings=0
|
|
|
|
# Check kernel compatibility
|
|
if [[ $SCAN_KERNEL_MAJOR -lt 6 ]] || [[ $SCAN_KERNEL_MAJOR -eq 6 && $SCAN_KERNEL_MINOR -lt 12 ]]; then
|
|
if [[ "$SCAN_IS_RDNA4" == true ]]; then
|
|
echo -e "${RED}[ISSUE]${NC} Kernel $SCAN_KERNEL_VERSION is too old for RDNA 4. Need 6.12+."
|
|
issues=$((issues+1))
|
|
fi
|
|
fi
|
|
|
|
if [[ $SCAN_KERNEL_MAJOR -eq 6 && ($SCAN_KERNEL_MINOR -eq 14 || $SCAN_KERNEL_MINOR -eq 15) ]]; then
|
|
echo -e "${YELLOW}[WARNING]${NC} Kernel 6.14/6.15 has ROCm DKMS issues. Consider 6.12 or 6.13."
|
|
warnings=$((warnings+1))
|
|
fi
|
|
|
|
# Kernel 7.x is bleeding edge - ROCm DKMS may not yet support it
|
|
if [[ $SCAN_KERNEL_MAJOR -ge 7 ]]; then
|
|
echo -e "${YELLOW}[WARNING]${NC} Kernel $SCAN_KERNEL_VERSION is very new. ROCm DKMS may not support it yet."
|
|
warnings=$((warnings+1))
|
|
fi
|
|
|
|
# =========================================================================
|
|
# HYBRID GPU HANDLING
|
|
# =========================================================================
|
|
|
|
if [[ "$SCAN_IS_HYBRID" == true ]]; then
|
|
echo -e "${CYAN}[HYBRID GPU]${NC} Multiple GPUs detected - special configuration needed."
|
|
|
|
# AMD iGPU + AMD dGPU
|
|
if [[ "$SCAN_HAS_AMD_IGPU" == true && "$SCAN_HAS_AMD_DGPU" == true ]]; then
|
|
echo -e "${YELLOW}[NOTE]${NC} AMD iGPU + AMD dGPU detected."
|
|
echo " DaVinci Resolve should use the discrete GPU automatically."
|
|
echo " If it uses the wrong GPU, the launcher pins via PCI tag (DRI_PRIME=pci-DDDD_BB_DD_F)"
|
|
warnings=$((warnings+1))
|
|
fi
|
|
|
|
# Intel iGPU + AMD dGPU
|
|
if [[ "$SCAN_HAS_INTEL_IGPU" == true && "$SCAN_HAS_AMD_DGPU" == true ]]; then
|
|
echo -e "${YELLOW}[NOTE]${NC} Intel iGPU + AMD dGPU detected."
|
|
echo " You may need to launch with: DRI_PRIME=pci-DDDD_BB_DD_F davinci-resolve (use lspci to find the AMD bus)"
|
|
echo " The launcher script will be configured for this."
|
|
warnings=$((warnings+1))
|
|
fi
|
|
|
|
# Intel iGPU + NVIDIA dGPU
|
|
if [[ "$SCAN_HAS_INTEL_IGPU" == true && "$SCAN_HAS_NVIDIA_DGPU" == true ]]; then
|
|
echo -e "${YELLOW}[NOTE]${NC} Intel iGPU + NVIDIA dGPU (Optimus) detected."
|
|
echo " For NVIDIA GPU: use prime-run or __NV_PRIME_RENDER_OFFLOAD=1"
|
|
echo " Consider using NVIDIA GPU for better Resolve performance."
|
|
warnings=$((warnings+1))
|
|
fi
|
|
|
|
# AMD iGPU + NVIDIA dGPU
|
|
if [[ "$SCAN_HAS_AMD_IGPU" == true && "$SCAN_HAS_NVIDIA_DGPU" == true ]]; then
|
|
echo -e "${YELLOW}[NOTE]${NC} AMD iGPU + NVIDIA dGPU detected."
|
|
echo " For NVIDIA GPU: use prime-run or __NV_PRIME_RENDER_OFFLOAD=1"
|
|
warnings=$((warnings+1))
|
|
fi
|
|
|
|
# Check if PRIME is available
|
|
if [[ "$SCAN_PRIME_AVAILABLE" == true ]]; then
|
|
echo -e "${GREEN}[OK]${NC} PRIME GPU switching is available (multiple render nodes detected)."
|
|
else
|
|
echo -e "${YELLOW}[WARNING]${NC} PRIME switching may not be configured correctly."
|
|
warnings=$((warnings+1))
|
|
fi
|
|
|
|
echo ""
|
|
fi
|
|
|
|
# Check GPU vendor
|
|
if [[ "$SCAN_GPU_VENDOR" != "AMD" && "$SCAN_HAS_AMD_DGPU" != true ]]; then
|
|
if [[ "$SCAN_GPU_VENDOR" == "NVIDIA" ]]; then
|
|
echo -e "${YELLOW}[NOTE]${NC} NVIDIA GPU detected. This script is optimized for AMD."
|
|
echo " NVIDIA GPUs work well with Resolve but use different drivers (nvidia + CUDA)."
|
|
warnings=$((warnings+1))
|
|
elif [[ "$SCAN_GPU_VENDOR" == "Intel" ]]; then
|
|
echo -e "${YELLOW}[WARNING]${NC} Only Intel GPU detected. DaVinci Resolve has limited Intel support."
|
|
warnings=$((warnings+1))
|
|
else
|
|
echo -e "${YELLOW}[WARNING]${NC} GPU vendor not recognized. This script is optimized for AMD GPUs."
|
|
warnings=$((warnings+1))
|
|
fi
|
|
fi
|
|
|
|
# Check Mesa for RDNA 4
|
|
if [[ "$SCAN_IS_RDNA4" == true && $SCAN_MESA_MAJOR -lt 25 ]]; then
|
|
echo -e "${YELLOW}[WARNING]${NC} Mesa $SCAN_MESA_VERSION may not fully support RDNA 4. Consider updating."
|
|
warnings=$((warnings+1))
|
|
fi
|
|
|
|
# Check OpenCL
|
|
if [[ "$SCAN_OPENCL_INSTALLED" == true && "$SCAN_AMD_OPENCL_WORKING" == false ]]; then
|
|
echo -e "${YELLOW}[WARNING]${NC} OpenCL installed but AMD platform not detected. May need reconfiguration."
|
|
warnings=$((warnings+1))
|
|
fi
|
|
|
|
# RDNA4 info
|
|
if [[ "$SCAN_IS_RDNA4" == true ]]; then
|
|
echo -e "${CYAN}[RDNA4]${NC} Detected RDNA4 GPU (gfx1201)"
|
|
echo " Note: RDNA4 support is new - compatibility may vary"
|
|
echo " If Resolve fails, try switching OPENCL_PROVIDER in script"
|
|
fi
|
|
|
|
# Show selected OpenCL provider with explanation
|
|
echo -e "${CYAN}[CONFIG]${NC} OpenCL provider: $OPENCL_PROVIDER"
|
|
if [[ "$OPENCL_PROVIDER" == "opencl-amd" ]]; then
|
|
echo " Using AUR package (recommended by Arch Wiki for Resolve)"
|
|
else
|
|
echo " Using official Arch ROCm packages"
|
|
fi
|
|
|
|
# Check disk space (DaVinci Resolve needs ~3GB, opencl-amd ~500MB)
|
|
if [[ $SCAN_ROOT_FREE_GB -lt 5 ]]; then
|
|
echo -e "${RED}[ISSUE]${NC} Low disk space on root (${SCAN_ROOT_FREE_GB}GB). Need at least 5GB free."
|
|
issues=$((issues+1))
|
|
fi
|
|
|
|
# Check AUR helper
|
|
if [[ -z "$SCAN_AUR_HELPER" ]]; then
|
|
echo -e "${RED}[ISSUE]${NC} No AUR helper found. Install yay or paru first."
|
|
issues=$((issues+1))
|
|
fi
|
|
|
|
# Check display server
|
|
if [[ "$SCAN_DISPLAY_SERVER" == "None/TTY" ]]; then
|
|
echo -e "${YELLOW}[WARNING]${NC} No display server detected. Run this script from a graphical session."
|
|
warnings=$((warnings+1))
|
|
fi
|
|
|
|
# Check existing Resolve installation
|
|
if [[ "$SCAN_RESOLVE_INSTALLED" == true ]]; then
|
|
echo -e "${YELLOW}[NOTE]${NC} DaVinci Resolve already installed (v${SCAN_RESOLVE_VERSION}). Will update/reconfigure."
|
|
warnings=$((warnings+1))
|
|
fi
|
|
|
|
# Summary
|
|
echo ""
|
|
if [[ $issues -eq 0 && $warnings -eq 0 ]]; then
|
|
echo -e "${GREEN}✓ No issues detected. System looks ready for installation.${NC}"
|
|
elif [[ $issues -eq 0 ]]; then
|
|
echo -e "${YELLOW}⚠ $warnings warning(s) detected, but installation can proceed.${NC}"
|
|
else
|
|
echo -e "${RED}✗ $issues issue(s) and $warnings warning(s) detected.${NC}"
|
|
echo -e "${RED} Please resolve issues before continuing.${NC}"
|
|
fi
|
|
|
|
echo ""
|
|
return $issues
|
|
}
|
|
|
|
# =============================================================================
|
|
# SMART PACKAGE SELECTION
|
|
# =============================================================================
|
|
|
|
build_package_list() {
|
|
header "Building Package List"
|
|
|
|
# Arrays for packages to install
|
|
PACMAN_PACKAGES=()
|
|
AUR_PACKAGES=()
|
|
SKIP_PACKAGES=()
|
|
|
|
# ---- Build/extraction tools (one-time, used by install step) ----
|
|
# Resolve ships as a ZIP containing a .run AppImage; we extract, patchelf,
|
|
# rsync to /opt/resolve, and update desktop/icon caches afterward.
|
|
local tools=(
|
|
unzip patchelf libarchive xdg-user-dirs desktop-file-utils
|
|
file gtk-update-icon-cache rsync
|
|
)
|
|
|
|
# ---- Resolve runtime deps NOT bundled in the AppImage ----
|
|
# Resolve bundles its own copies of Qt5, libpng12, libxcb-*, etc. and we
|
|
# patch RPATH so they're found in /opt/resolve/libs. The few libs below
|
|
# genuinely have to come from the host system.
|
|
local runtime=(
|
|
libxcrypt-compat # provides libcrypt.so.1 (Arch dropped it)
|
|
ffmpeg4.4 # Resolve links against this older FFmpeg ABI
|
|
glu # OpenGL Utility (3D rendering)
|
|
fuse2 # AppImage runtime compat
|
|
mesa # graphics stack (usually already present)
|
|
)
|
|
|
|
# ---- Display/Wayland compat for Hyprland ----
|
|
local display=(
|
|
xorg-xwayland # Resolve has no native Wayland support
|
|
xdg-desktop-portal
|
|
xdg-desktop-portal-gtk
|
|
)
|
|
if [[ "$SCAN_IS_HYBRID" == true ]]; then
|
|
display+=(switcheroo-control)
|
|
fi
|
|
|
|
# ---- AMD-specific OpenCL provider ----
|
|
# rocm-pinned-7.1.1 is the default and only currently-working path with
|
|
# DaVinci Resolve. The actual install of the 7.1.1 packages happens in
|
|
# install_rocm_pinned() (downloads from Arch Linux Archive).
|
|
local amd_opencl=()
|
|
case "$OPENCL_PROVIDER" in
|
|
rocm-pinned-7.1.1)
|
|
info "Using ROCm 7.1.1 pinned (working stack for DaVinci Resolve on AMD)"
|
|
# ocl-icd provides libOpenCL.so.1 loader. rocminfo for diagnostics.
|
|
# rocm-smi-lib for power/clock monitoring. rocm-* 7.1.1 are
|
|
# installed by install_rocm_pinned() below.
|
|
amd_opencl=(ocl-icd rocminfo rocm-smi-lib)
|
|
;;
|
|
rocm-full)
|
|
warn "rocm-full = ROCm 7.2.x - KNOWN BROKEN with DaVinci Resolve as of May 2026"
|
|
warn " See https://github.com/ROCm/ROCm/issues/5982"
|
|
warn " Switch OPENCL_PROVIDER to 'rocm-pinned-7.1.1' for the working stack."
|
|
amd_opencl=(
|
|
rocm-core rocm-opencl-runtime rocm-hip-runtime
|
|
hsa-rocr rocminfo rocm-smi-lib
|
|
)
|
|
;;
|
|
opencl-amd)
|
|
warn "opencl-amd = AUR ROCm 7.2.x - KNOWN BROKEN with DaVinci Resolve as of May 2026"
|
|
warn " Same ABI bug as rocm-full. Switch to 'rocm-pinned-7.1.1' for working stack."
|
|
amd_opencl=(ocl-icd)
|
|
AUR_PACKAGES+=(opencl-amd)
|
|
;;
|
|
*)
|
|
error "Unknown OPENCL_PROVIDER: '$OPENCL_PROVIDER'"
|
|
;;
|
|
esac
|
|
|
|
# ---- Audio (smart-pick based on detected server) ----
|
|
local audio=()
|
|
if [[ "$SCAN_AUDIO_SERVER" == *"PipeWire"* ]]; then
|
|
info "PipeWire detected - installing pipewire-pulse + pipewire-alsa"
|
|
audio=(pipewire-pulse pipewire-alsa)
|
|
else
|
|
info "PulseAudio detected - installing pulseaudio-alsa"
|
|
audio=(pulseaudio-alsa)
|
|
fi
|
|
|
|
# ---- Diagnostics ----
|
|
local diag=(clinfo mesa-utils expac python-distro)
|
|
|
|
# Combine and split into "need install" vs "skip"
|
|
for pkg in "${tools[@]}" "${runtime[@]}" "${display[@]}" \
|
|
"${amd_opencl[@]}" "${audio[@]}" "${diag[@]}"; do
|
|
if is_pkg_installed "$pkg"; then
|
|
SKIP_PACKAGES+=("$pkg")
|
|
else
|
|
PACMAN_PACKAGES+=("$pkg")
|
|
fi
|
|
done
|
|
|
|
# Display summary
|
|
echo -e "${BOLD}Packages to install from official repos:${NC}"
|
|
if [[ ${#PACMAN_PACKAGES[@]} -gt 0 ]]; then
|
|
echo " ${PACMAN_PACKAGES[*]}"
|
|
else
|
|
echo " (none needed)"
|
|
fi
|
|
|
|
echo ""
|
|
echo -e "${BOLD}Packages to install from AUR:${NC}"
|
|
if [[ ${#AUR_PACKAGES[@]} -gt 0 ]]; then
|
|
echo " ${AUR_PACKAGES[*]}"
|
|
else
|
|
echo " (none needed)"
|
|
fi
|
|
|
|
echo ""
|
|
echo -e "${BOLD}Packages already installed (skipping):${NC}"
|
|
if [[ ${#SKIP_PACKAGES[@]} -gt 0 ]]; then
|
|
echo " ${SKIP_PACKAGES[*]}"
|
|
else
|
|
echo " (none)"
|
|
fi
|
|
|
|
echo ""
|
|
}
|
|
|
|
# =============================================================================
|
|
# INSTALLATION FUNCTIONS
|
|
# =============================================================================
|
|
|
|
install_pacman_packages() {
|
|
if [[ ${#PACMAN_PACKAGES[@]} -eq 0 ]]; then
|
|
info "No official repo packages to install."
|
|
return 0
|
|
fi
|
|
|
|
header "Installing Official Repo Packages"
|
|
|
|
# Handle opencl-amd removal when using full ROCm stack
|
|
if [[ "$OPENCL_PROVIDER" == "rocm-full" ]] && is_pkg_installed "opencl-amd"; then
|
|
warn "Removing opencl-amd (AUR) to install official ROCm stack..."
|
|
sudo pacman -Rns opencl-amd --noconfirm 2>/dev/null || true
|
|
fi
|
|
|
|
# Handle OpenCL conflicts - rusticl/mesa-opencl breaks ROCm (confirmed by davincibox)
|
|
# Reference: https://github.com/zelikos/davincibox - "mesa-libOpenCL breaks rocm-opencl"
|
|
local -a opencl_conflicts=()
|
|
for pkg in opencl-rusticl-mesa opencl-clover-mesa mesa-opencl pocl; do
|
|
if is_pkg_installed "$pkg"; then
|
|
opencl_conflicts+=("$pkg")
|
|
fi
|
|
done
|
|
if [[ ${#opencl_conflicts[@]} -gt 0 ]]; then
|
|
warn "Removing conflicting OpenCL packages (breaks ROCm): ${opencl_conflicts[*]}"
|
|
sudo pacman -Rns "${opencl_conflicts[@]}" --noconfirm 2>/dev/null || true
|
|
fi
|
|
|
|
info "Installing ${#PACMAN_PACKAGES[@]} packages..."
|
|
sudo pacman -S --needed --noconfirm "${PACMAN_PACKAGES[@]}"
|
|
|
|
success "Official packages installed."
|
|
}
|
|
|
|
install_aur_packages() {
|
|
if [[ ${#AUR_PACKAGES[@]} -eq 0 ]]; then
|
|
info "No AUR packages to install."
|
|
return 0
|
|
fi
|
|
|
|
header "Installing AUR Packages"
|
|
|
|
# Handle OpenCL conflicts
|
|
if [[ " ${AUR_PACKAGES[*]} " =~ " opencl-amd " ]]; then
|
|
# Check for conflicting packages
|
|
local -a conflicts=()
|
|
for pkg in mesa-opencl pocl intel-compute-runtime rocm-opencl-runtime; do
|
|
if is_pkg_installed "$pkg"; then
|
|
conflicts+=("$pkg")
|
|
fi
|
|
done
|
|
|
|
if [[ ${#conflicts[@]} -gt 0 ]]; then
|
|
warn "Found conflicting OpenCL packages: ${conflicts[*]}"
|
|
read -p "Remove them to install opencl-amd? [Y/n] " -n 1 -r
|
|
echo
|
|
if [[ ! $REPLY =~ ^[Nn]$ ]]; then
|
|
sudo pacman -Rns "${conflicts[@]}" --noconfirm 2>/dev/null || true
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
info "Installing AUR packages..."
|
|
$SCAN_AUR_HELPER -S --needed --noconfirm "${AUR_PACKAGES[@]}"
|
|
|
|
success "AUR packages installed."
|
|
}
|
|
|
|
install_rocm_pinned() {
|
|
# Install ROCm 7.1.1 from the Arch Linux Archive (ALA) and pin it in
|
|
# /etc/pacman.conf IgnorePkg.
|
|
#
|
|
# Why: ROCm 7.2.x (current Arch extra) breaks DaVinci Resolve - the
|
|
# OpenCL clCreateContext call fails on AMD GPUs after the 7.2 update.
|
|
# See ROCm/ROCm#5982 (filed 2026-02-19, still open).
|
|
# Confirmed broken on 760M iGPU, 7800 XT, RX 9060 XT (this user).
|
|
# 7.1.1 is the last working release.
|
|
#
|
|
# Why not opencl-amd: it bundles its own 7.2.x ROCm internally and
|
|
# has the same ABI bug. It also conflicts with rocm-opencl-runtime
|
|
# so you can only have one or the other.
|
|
#
|
|
# When ROCm 7.3+ ships with the fix, lift the pin:
|
|
# sudo sed -i '/^IgnorePkg.*rocm-/d' /etc/pacman.conf
|
|
# sudo pacman -Syu
|
|
|
|
[[ "$OPENCL_PROVIDER" != "rocm-pinned-7.1.1" ]] && return 0
|
|
|
|
header "Installing ROCm 7.1.1 (pinned)"
|
|
|
|
# If the working stack is already present at the right version, skip.
|
|
local need_install=0
|
|
for pkg in rocm-core rocm-device-libs rocm-llvm rocm-opencl-runtime comgr; do
|
|
local ver
|
|
ver=$(pacman -Q "$pkg" 2>/dev/null | awk '{print $2}')
|
|
if [[ -z "$ver" || ! "$ver" =~ 7\.1\.1 ]]; then
|
|
need_install=1
|
|
break
|
|
fi
|
|
done
|
|
if [[ "$need_install" == 0 ]] && pacman -Q spirv-llvm-translator 2>/dev/null | grep -q "21.1.3"; then
|
|
info "ROCm 7.1.1 stack already present at correct versions - skipping ALA download."
|
|
else
|
|
# Remove conflicting package: opencl-amd bundles ROCm 7.2.1 and
|
|
# conflicts with rocm-opencl-runtime
|
|
if pacman -Q opencl-amd &>/dev/null; then
|
|
warn "Removing opencl-amd (AUR, conflicts with rocm-opencl-runtime)..."
|
|
sudo pacman -Rns opencl-amd --noconfirm 2>/dev/null || true
|
|
fi
|
|
if pacman -Q opencl-amd-debug &>/dev/null; then
|
|
sudo pacman -Rns opencl-amd-debug --noconfirm 2>/dev/null || true
|
|
fi
|
|
|
|
# Download the 6 packages from Arch Linux Archive
|
|
local ala="https://archive.archlinux.org/packages"
|
|
local pkgs=(
|
|
"${ala}/r/rocm-core/rocm-core-7.1.1-1-x86_64.pkg.tar.zst"
|
|
"${ala}/r/rocm-device-libs/rocm-device-libs-2:7.1.1-1-x86_64.pkg.tar.zst"
|
|
"${ala}/r/rocm-llvm/rocm-llvm-2:7.1.1-1-x86_64.pkg.tar.zst"
|
|
"${ala}/r/rocm-opencl-runtime/rocm-opencl-runtime-7.1.1-1-x86_64.pkg.tar.zst"
|
|
"${ala}/c/comgr/comgr-2:7.1.1-1-x86_64.pkg.tar.zst"
|
|
"${ala}/s/spirv-llvm-translator/spirv-llvm-translator-21.1.3-1-x86_64.pkg.tar.zst"
|
|
)
|
|
|
|
local tmpdir
|
|
tmpdir=$(mktemp -d -t rocm-pinned-XXXXXX)
|
|
local trap_old
|
|
# shellcheck disable=SC2064
|
|
trap "rm -rf '$tmpdir'" EXIT
|
|
|
|
info "Downloading ROCm 7.1.1 packages from Arch Linux Archive..."
|
|
local downloaded=()
|
|
for url in "${pkgs[@]}"; do
|
|
local fname
|
|
fname=$(basename "$url")
|
|
info " $fname"
|
|
if curl -fsSL --output "$tmpdir/$fname" "$url"; then
|
|
downloaded+=("$tmpdir/$fname")
|
|
else
|
|
error "Failed to download $url"
|
|
fi
|
|
done
|
|
|
|
# numactl + gflags are runtime deps usually already installed
|
|
sudo pacman -S --needed --noconfirm numactl gflags 2>&1 | tail -3 || true
|
|
|
|
info "Installing pinned ROCm 7.1.1 packages..."
|
|
sudo pacman -U --noconfirm "${downloaded[@]}" \
|
|
|| error "Failed to install pinned ROCm 7.1.1 packages from ALA - aborting before launcher/config steps run against a broken stack."
|
|
|
|
rm -rf "$tmpdir"
|
|
trap - EXIT
|
|
fi
|
|
|
|
# Pin in /etc/pacman.conf [options] IgnorePkg so future -Syu doesn't
|
|
# break Resolve again. Idempotent.
|
|
local pin_pkgs="rocm-core rocm-device-libs rocm-llvm rocm-opencl-runtime comgr spirv-llvm-translator"
|
|
if grep -q "^IgnorePkg.*rocm-core" /etc/pacman.conf; then
|
|
info "IgnorePkg already pins ROCm packages."
|
|
else
|
|
info "Adding IgnorePkg pin for ROCm 7.1.1 packages..."
|
|
# Insert immediately after [options] section header
|
|
sudo sed -i "/^\[options\]/a IgnorePkg = ${pin_pkgs}" /etc/pacman.conf
|
|
success "Pinned in /etc/pacman.conf [options]."
|
|
fi
|
|
|
|
success "ROCm 7.1.1 installed and pinned."
|
|
}
|
|
|
|
install_davinci_resolve() {
|
|
# NVIDIA-mirrored install path:
|
|
# 1. Find ZIP in ~/Downloads
|
|
# 2. Disk-space check (~10 GB free)
|
|
# 3. mktemp + trap to clean up on any exit
|
|
# 4. unzip ZIP -> find .run -> --appimage-extract -> squashfs-root
|
|
# 5. Replace bundled glib/gio/gmodule with system symlinks
|
|
# (KEEP vendored libc++/libc++abi - removing breaks Resolve)
|
|
# 6. Extract DaVinci panel-framework tarball if present
|
|
# 7. rsync squashfs-root to /opt/resolve
|
|
# 8. patchelf --set-rpath on every ELF in /opt/resolve
|
|
# 9. libcrypt.so.1 fallback symlink
|
|
# 10. Install desktop entries / icons / udev rules system-wide
|
|
#
|
|
# No AUR PKGBUILD, no qt5-webengine source build. Resolve's bundled Qt5
|
|
# is used via RPATH. Pacman does not track this install - to remove:
|
|
# `sudo rm -rf /opt/resolve` and the desktop/icon/udev files.
|
|
|
|
if [[ "$SCAN_RESOLVE_INSTALLED" == true ]]; then
|
|
info "DaVinci Resolve already installed at /opt/resolve."
|
|
info "Will apply workarounds and configuration updates."
|
|
return 0
|
|
fi
|
|
|
|
header "Installing DaVinci Resolve"
|
|
|
|
# ---- Locate the ZIP installer ----
|
|
local downloads_dir="$HOME/Downloads"
|
|
local resolve_zip=""
|
|
while IFS= read -r -d '' file; do
|
|
resolve_zip="$file"
|
|
done < <(find "$downloads_dir" -maxdepth 1 -name "DaVinci_Resolve_*_Linux.zip" -type f -print0 2>/dev/null | sort -zV)
|
|
|
|
if [[ -z "$resolve_zip" ]]; then
|
|
echo ""
|
|
warn "DaVinci Resolve ZIP not found in ~/Downloads"
|
|
echo " 1. Go to: https://www.blackmagicdesign.com/products/davinciresolve"
|
|
echo " 2. Click 'Download' -> 'DaVinci Resolve' (Free)"
|
|
echo " 3. Select 'Linux' and save the ZIP to ~/Downloads"
|
|
echo ""
|
|
read -p "Open download page? [Y/n] " -n 1 -r
|
|
echo
|
|
if [[ ! $REPLY =~ ^[Nn]$ ]]; then
|
|
xdg-open "https://www.blackmagicdesign.com/products/davinciresolve" 2>/dev/null || true
|
|
fi
|
|
return 1
|
|
fi
|
|
success "Found installer: $resolve_zip"
|
|
|
|
local resolve_version=$(basename "$resolve_zip" | grep -oP 'Resolve_\K[0-9]+\.[0-9]+(\.[0-9]+)?' || echo "")
|
|
if [[ "$SCAN_IS_RDNA4" == true && -n "$resolve_version" ]]; then
|
|
local major=$(echo "$resolve_version" | cut -d'.' -f1)
|
|
if [[ "$major" -lt 20 ]]; then
|
|
warn "DaVinci Resolve $resolve_version may not work with RDNA 4 (need 20.x+)"
|
|
fi
|
|
fi
|
|
|
|
# ---- Disk space check (~10 GB needed for staged extraction) ----
|
|
local needed_gb=10
|
|
local free_kb=$(df --output=avail -k "$downloads_dir" | tail -n1)
|
|
local free_gb=$((free_kb / 1024 / 1024))
|
|
if (( free_gb < needed_gb )); then
|
|
error "Not enough free space in $downloads_dir: ${free_gb} GiB < ${needed_gb} GiB"
|
|
fi
|
|
|
|
# ---- Stage extraction in a temp dir under ~/Downloads ----
|
|
local workdir
|
|
workdir=$(mktemp -d -p "$downloads_dir" .resolve-extract-XXXXXXXX)
|
|
local original_dir="$PWD"
|
|
cleanup_resolve_build() {
|
|
cd "$original_dir" 2>/dev/null || cd ~
|
|
if [[ -n "${workdir:-}" && -d "$workdir" ]]; then
|
|
info "Cleaning up extraction directory..."
|
|
rm -rf "$workdir" 2>/dev/null || true
|
|
fi
|
|
}
|
|
trap cleanup_resolve_build EXIT
|
|
|
|
info "Unpacking ZIP to $workdir ..."
|
|
unzip -q "$resolve_zip" -d "$workdir"
|
|
|
|
local run_file
|
|
run_file=$(find "$workdir" -maxdepth 2 -type f -name 'DaVinci_Resolve_*_Linux.run' | head -n1 || true)
|
|
[[ -n "$run_file" ]] || error "Could not find the .run installer inside the ZIP"
|
|
chmod +x "$run_file"
|
|
|
|
local ex_dir=$(dirname "$run_file")
|
|
info "Extracting AppImage payload..."
|
|
if ! ( cd "$ex_dir" && "./$(basename "$run_file")" --appimage-extract >/dev/null ); then
|
|
error "Failed to extract AppImage payload from $run_file"
|
|
fi
|
|
|
|
local appdir="$ex_dir/squashfs-root"
|
|
[[ -d "$appdir" ]] || error "Extraction produced no squashfs-root directory"
|
|
[[ -s "$appdir/bin/resolve" ]] || error "resolve binary missing or zero-size after extraction"
|
|
|
|
chmod -R u+rwX,go+rX,go-w "$appdir" 2>/dev/null || warn "Could not normalize all permissions"
|
|
|
|
# ---- ABI-safe bundled-library replacement ----
|
|
# Replace bundled glib family with system versions (stable C ABI -
|
|
# safe to swap and avoids the well-known Resolve+Arch glib clash).
|
|
#
|
|
# All five glib-family libs must be swapped together: GObject's vtable
|
|
# layout has to match the GLib it was built against, and GThread shares
|
|
# internal state with GLib. Mixing a system libglib with bundled
|
|
# libgobject means GObject calls into GLib symbols that have moved
|
|
# between versions (Arch ships glib2 2.88+, bundled GObject is from
|
|
# 2.68) and segfaults on the first signal emit / type registration.
|
|
# Symptoms: random crashes in file pickers, GIO async ops, gstreamer
|
|
# media import.
|
|
#
|
|
# KEEP vendored libc++/libc++abi - replacing them causes immediate crashes
|
|
# because Resolve was compiled against specific libc++ ABI versions.
|
|
info "Replacing bundled glib family (glib/gio/gmodule/gobject/gthread) with system versions..."
|
|
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"
|
|
["/usr/lib/libgobject-2.0.so.0"]="libs/libgobject-2.0.so.0"
|
|
["/usr/lib/libgthread-2.0.so.0"]="libs/libgthread-2.0.so.0"
|
|
)
|
|
for syslib in "${!glib_libs[@]}"; do
|
|
local target="${glib_libs[$syslib]}"
|
|
if [[ -e "$syslib" ]]; then
|
|
rm -f "$target" || true
|
|
ln -sf "$syslib" "$target" || warn "Failed to symlink $syslib -> $target"
|
|
else
|
|
warn "System library $syslib not found, keeping bundled version"
|
|
fi
|
|
done
|
|
|
|
# Extract bundled DaVinci panel-framework (control surface support libs)
|
|
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
|
|
|
|
# AppImage launcher leftovers - we install to /opt/resolve, not run as AppImage
|
|
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 ----
|
|
info "Installing to /opt/resolve (rsync) ..."
|
|
sudo rm -rf /opt/resolve
|
|
sudo mkdir -p /opt/resolve
|
|
sudo rsync -a --delete "$appdir/" /opt/resolve/
|
|
sudo mkdir -p /opt/resolve/.license
|
|
|
|
# ---- RPATH patching ----
|
|
# Resolve's bundled binaries have RPATHs pointing to AppImage extraction
|
|
# paths that no longer exist. Patch every ELF (executable + shared object)
|
|
# to search /opt/resolve/libs/ and its plugin subdirectories.
|
|
info "Patching RPATH on every ELF in /opt/resolve (may take a minute)..."
|
|
local 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"
|
|
)
|
|
local rpath_abs=""
|
|
for p in "${rpath_dirs[@]}"; do rpath_abs+="/opt/resolve/${p}:"; done
|
|
rpath_abs+="\$ORIGIN"
|
|
|
|
local patch_count=0 patch_fail=0 patch_skip=0
|
|
while IFS= read -r -d '' f; do
|
|
local file_info
|
|
file_info=$(file -b "$f" 2>/dev/null)
|
|
if [[ "$file_info" =~ ELF.*executable ]] || [[ "$file_info" =~ ELF.*shared\ object ]]; then
|
|
local current_rpath
|
|
current_rpath=$(patchelf --print-rpath "$f" 2>/dev/null || true)
|
|
if [[ "$current_rpath" == "$rpath_abs" ]]; then
|
|
patch_skip=$((patch_skip + 1))
|
|
continue
|
|
fi
|
|
if sudo patchelf --set-rpath "$rpath_abs" "$f" 2>/dev/null; then
|
|
patch_count=$((patch_count + 1))
|
|
else
|
|
patch_fail=$((patch_fail + 1))
|
|
local file_size=$(stat -c%s "$f" 2>/dev/null || echo 0)
|
|
if (( file_size > 33554432 )); then
|
|
warn "Failed to patch large file (>32MB): ${f##/opt/resolve/}"
|
|
fi
|
|
fi
|
|
fi
|
|
done < <(find /opt/resolve -type f -print0)
|
|
success "Patched RPATH: $patch_count files ($patch_fail failures, $patch_skip already correct)"
|
|
|
|
# ---- libcrypt.so.1 fallback symlink ----
|
|
# libxcrypt-compat already provides /usr/lib/libcrypt.so.1; symlink it
|
|
# into /opt/resolve/libs as a belt-and-braces fallback.
|
|
sudo ldconfig 2>/dev/null || 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 entries (system-wide) ----
|
|
info "Installing desktop entries, icons, and udev rules..."
|
|
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
|
|
local dest="${desktop_files[$src]}"
|
|
if [[ -f "$src" ]]; then
|
|
sudo install -D -m 0644 "$src" "$dest"
|
|
# Critical: Resolve's bundled .desktop files have a literal
|
|
# "RESOLVE_INSTALL_LOCATION" placeholder that the official
|
|
# installer would substitute. Our manual copy doesn't, so the
|
|
# app menu launcher would do nothing. Substitute now.
|
|
sudo sed -i "s|RESOLVE_INSTALL_LOCATION|/opt/resolve|g" "$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
|
|
local 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
|
|
|
|
# ---- udev rules for Blackmagic capture cards / control surfaces ----
|
|
for r in 99-BlackmagicDevices.rules 99-ResolveKeyboardHID.rules 99-DavinciPanel.rules; do
|
|
local src="/opt/resolve/share/etc/udev/rules.d/$r"
|
|
if [[ -f "$src" ]]; then
|
|
sudo install -D -m 0644 "$src" "/usr/lib/udev/rules.d/$r"
|
|
fi
|
|
done
|
|
sudo udevadm control --reload-rules 2>/dev/null && sudo udevadm trigger 2>/dev/null || true
|
|
|
|
# Cleanup extraction tree
|
|
cleanup_resolve_build
|
|
trap - EXIT
|
|
|
|
# Refresh scan flag so downstream functions see the install
|
|
SCAN_RESOLVE_INSTALLED=true
|
|
SCAN_RESOLVE_PATH="/opt/resolve"
|
|
|
|
success "DaVinci Resolve installed to /opt/resolve."
|
|
}
|
|
|
|
disable_opencl_decoders() {
|
|
# Davincibox-style fix: disable BlackmagicRaw OpenCL decoders to prevent conflicts
|
|
# These are the exact paths from davincibox setup-davinci script
|
|
header "Disabling Problematic OpenCL Decoders"
|
|
|
|
local decoder_paths=(
|
|
# Exact paths from davincibox
|
|
"/opt/resolve/BlackmagicRAWPlayer/BlackmagicRawAPI/libDecoderOpenCL.so"
|
|
"/opt/resolve/BlackmagicRAWSpeedTest/BlackmagicRawAPI/libDecoderOpenCL.so"
|
|
# Additional possible locations
|
|
"/opt/resolve/libs/BlackmagicRawAPI/libDecoderOpenCL.so"
|
|
"/opt/resolve/BlackmagicRawAPI/libDecoderOpenCL.so"
|
|
)
|
|
|
|
local disabled=0
|
|
for decoder in "${decoder_paths[@]}"; do
|
|
if [[ -f "$decoder" && ! -f "${decoder}.bak" ]]; then
|
|
info "Disabling: $decoder"
|
|
sudo mv "$decoder" "${decoder}.bak"
|
|
disabled=$((disabled + 1))
|
|
elif [[ -f "${decoder}.bak" ]]; then
|
|
info "Already disabled: $decoder"
|
|
fi
|
|
done
|
|
|
|
if [[ $disabled -gt 0 ]]; then
|
|
success "Disabled $disabled OpenCL decoder(s) to prevent conflicts."
|
|
else
|
|
info "No OpenCL decoders needed disabling."
|
|
fi
|
|
}
|
|
|
|
setup_tls_symlink() {
|
|
# Resolve's built-in extras downloader expects RHEL/CentOS cert path
|
|
# /etc/pki/tls instead of Arch's /etc/ssl. Symlink so updates work.
|
|
header "Configuring TLS Cert Path for Resolve"
|
|
|
|
if [[ -e /etc/pki/tls ]]; then
|
|
info "/etc/pki/tls already exists - skipping."
|
|
return
|
|
fi
|
|
|
|
sudo mkdir -p /etc/pki
|
|
sudo ln -sf /etc/ssl /etc/pki/tls
|
|
success "Linked /etc/pki/tls -> /etc/ssl"
|
|
}
|
|
|
|
patch_audio_backend() {
|
|
# Resolve ships with `Local.Audio.Type = DeckLink` in its system-wide
|
|
# config template. On systems without a Blackmagic DeckLink card this
|
|
# makes Resolve fail on first launch. Switch the default to ALSA.
|
|
header "Patching Resolve Audio Backend (DeckLink -> ALSA)"
|
|
|
|
local 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"
|
|
success "Patched system template: $template"
|
|
elif [[ -f "$template" ]]; then
|
|
info "System template already patched or non-default."
|
|
else
|
|
warn "System template not found - skipping."
|
|
fi
|
|
|
|
local 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"
|
|
success "Patched user config (backup .bak.<timestamp> created)"
|
|
fi
|
|
}
|
|
|
|
setup_snd_aloop() {
|
|
# Resolve's audio engine opens raw ALSA hw: devices and never uses ALSA's
|
|
# plugin layer (default/pulse/pipewire). When PipeWire owns every real
|
|
# card, Resolve's enumerator loops looking for a free PCM and renders
|
|
# never start. Loading snd-aloop gives Resolve a virtual card it can fully
|
|
# own; PipeWire ignores it. Strace evidence: 14k+ SNDRV_CTL_IOCTL_PCM_INFO
|
|
# ENXIO / 47k+ /dev/snd/controlCN ENOENT during a stuck render.
|
|
#
|
|
# Skip with RESOLVE_NO_ALOOP=1 (e.g. user has a dedicated audio interface).
|
|
header "snd-aloop Render-Blocker Fix"
|
|
|
|
if [[ "${RESOLVE_NO_ALOOP:-0}" == "1" ]]; then
|
|
info "Skipping snd-aloop setup (RESOLVE_NO_ALOOP=1)."
|
|
return
|
|
fi
|
|
|
|
# 1. Load module now
|
|
if lsmod | grep -qE '^snd_aloop'; then
|
|
info "snd-aloop already loaded."
|
|
else
|
|
if sudo modprobe snd-aloop 2>/dev/null; then
|
|
success "snd-aloop loaded for the current session."
|
|
else
|
|
warn "modprobe snd-aloop failed. Verify with: modinfo snd-aloop"
|
|
warn "On Arch this is part of linux/linux-zen/linux-lts kernel packages."
|
|
fi
|
|
fi
|
|
|
|
# 2. Persist across reboots
|
|
local 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
|
|
success "Wrote $aloop_conf (autoloads at boot)."
|
|
else
|
|
info "$aloop_conf already configured."
|
|
fi
|
|
|
|
# 3. PipeWire loopback bridge - sends aloop capture to system default sink
|
|
# so Resolve monitor audio is audible while editing.
|
|
local bridge_dir="${HOME}/.config/pipewire/pipewire.conf.d"
|
|
local bridge_file="${bridge_dir}/50-resolve-aloop-bridge.conf"
|
|
mkdir -p "$bridge_dir"
|
|
if [[ ! -f "$bridge_file" ]]; then
|
|
cat > "$bridge_file" <<'EOF'
|
|
# DaVinci Resolve aloop monitor bridge - managed by install-davinci-resolve.sh
|
|
# Bridges snd-aloop's capture side to the system default sink so Resolve's
|
|
# monitor audio is audible while editing. Without this, renders complete 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
|
|
success "Wrote $bridge_file (PipeWire loopback bridge)."
|
|
else
|
|
info "$bridge_file already in place."
|
|
fi
|
|
|
|
# 4. Wireplumber rule - keep aloop OUT of default-sink rotation.
|
|
# Without this, wireplumber promotes aloop to default whenever Resolve
|
|
# makes it RUNNING, and the bridge feeds aloop back into itself.
|
|
local wp_dir="${HOME}/.config/wireplumber/wireplumber.conf.d"
|
|
local wp_file="${wp_dir}/51-resolve-aloop-no-default.conf"
|
|
mkdir -p "$wp_dir"
|
|
if [[ ! -f "$wp_file" ]]; then
|
|
cat > "$wp_file" <<'EOF'
|
|
# DaVinci Resolve aloop default-sink exclusion - managed by install-davinci-resolve.sh
|
|
# Without this, wireplumber promotes aloop to default whenever Resolve makes
|
|
# it RUNNING and the loopback bridge sends audio back into aloop. Setting
|
|
# both dont-fallback and disable-fallback covers minor key renames in the
|
|
# wireplumber 0.5.x series.
|
|
monitor.alsa.rules = [
|
|
{
|
|
matches = [
|
|
{ node.name = "alsa_output.platform-snd_aloop.0.analog-stereo" }
|
|
{ node.name = "alsa_input.platform-snd_aloop.0.analog-stereo" }
|
|
]
|
|
actions = {
|
|
update-props = {
|
|
priority.session = 0
|
|
priority.driver = 0
|
|
node.dont-fallback = true
|
|
node.disable-fallback = true
|
|
}
|
|
}
|
|
}
|
|
]
|
|
EOF
|
|
success "Wrote $wp_file (wireplumber default-sink exclusion)."
|
|
else
|
|
info "$wp_file already in place."
|
|
fi
|
|
|
|
# 5. Restart user services so the configs are picked up. wireplumber
|
|
# first, then pipewire/pipewire-pulse so the alsa rule re-applies
|
|
# when pipewire republishes aloop nodes.
|
|
if systemctl --user is-active --quiet pipewire 2>/dev/null; then
|
|
systemctl --user restart wireplumber pipewire pipewire-pulse 2>/dev/null || true
|
|
info "Reloaded user wireplumber + PipeWire services."
|
|
fi
|
|
}
|
|
|
|
configure_user_groups() {
|
|
# Davincibox requirement: user must be in 'render' and 'video' groups
|
|
# Without these, DaVinci Resolve may hang during rendering or fail to detect GPU
|
|
header "Configuring User Groups"
|
|
|
|
local groups_to_add=()
|
|
local current_groups=$(groups "$USER" 2>/dev/null)
|
|
|
|
# Check render group
|
|
if ! echo "$current_groups" | grep -qw "render"; then
|
|
if getent group render &>/dev/null; then
|
|
groups_to_add+=("render")
|
|
else
|
|
info "Group 'render' does not exist on this system (may not be needed)"
|
|
fi
|
|
else
|
|
info "User already in 'render' group"
|
|
fi
|
|
|
|
# Check video group
|
|
if ! echo "$current_groups" | grep -qw "video"; then
|
|
if getent group video &>/dev/null; then
|
|
groups_to_add+=("video")
|
|
fi
|
|
else
|
|
info "User already in 'video' group"
|
|
fi
|
|
|
|
# Add user to missing groups
|
|
if [[ ${#groups_to_add[@]} -gt 0 ]]; then
|
|
info "Adding user to groups: ${groups_to_add[*]}"
|
|
for grp in "${groups_to_add[@]}"; do
|
|
sudo usermod -a -G "$grp" "$USER"
|
|
done
|
|
warn "You will need to log out and back in for group changes to take effect!"
|
|
success "User added to required groups."
|
|
else
|
|
success "User already has required group memberships."
|
|
fi
|
|
}
|
|
|
|
reset_stale_configs() {
|
|
# Resolve defaults to GPU Processing Mode = CUDA on Linux. If a previous
|
|
# launch couldn't find an OpenCL device (e.g. ROCm wasn't installed yet,
|
|
# or an install was interrupted), Resolve writes a config snapshot and
|
|
# segfaults 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.
|
|
#
|
|
# Project databases under "Resolve Disk Database/" and "Resolve Project
|
|
# Library/" are NOT touched. Set RESOLVE_RESET_CONFIG=1 to force.
|
|
header "Checking for stale Resolve configs"
|
|
|
|
local resolve_user_dir="${HOME}/.local/share/DaVinciResolve"
|
|
local prior_crash=0
|
|
|
|
# Match any of the known crash signatures. ROCm 7.2 produces several:
|
|
# 'Unsupported GPU Processing Mode' is the original symptom (no OpenCL
|
|
# device visible at all). 'OpenCL Context Manager failed to create
|
|
# context' / 'Failed to create OpenCL context' fire when the device IS
|
|
# visible but clCreateContext fails - the actual recurrence the v4.1
|
|
# script missed on fresh installs. Once any of these poisoned configs
|
|
# land, every subsequent launch reuses them and crashes the same way.
|
|
local crash_markers='Unsupported GPU Processing Mode|OpenCL Context Manager failed to create context|Failed to create OpenCL context'
|
|
if [[ -f "${resolve_user_dir}/logs/ResolveDebug.txt" ]] && \
|
|
grep -qE "${crash_markers}" "${resolve_user_dir}/logs/ResolveDebug.txt" 2>/dev/null; then
|
|
prior_crash=1
|
|
local hit
|
|
hit=$(grep -oE "${crash_markers}" "${resolve_user_dir}/logs/ResolveDebug.txt" 2>/dev/null | head -1)
|
|
warn "Detected prior crash marker: '${hit}'"
|
|
fi
|
|
|
|
# On a fresh Resolve install (SCAN_RESOLVE_INSTALLED=false), any configs
|
|
# present can only have been written by a failed launch during this same
|
|
# install run - there is no real user state to preserve. Wipe them
|
|
# unconditionally so we never re-read a poisoned snapshot.
|
|
local fresh_install=0
|
|
if [[ "${SCAN_RESOLVE_INSTALLED}" != "true" ]]; then
|
|
fresh_install=1
|
|
fi
|
|
|
|
if (( prior_crash )) || (( fresh_install )) || [[ "${RESOLVE_RESET_CONFIG:-0}" == "1" ]]; then
|
|
if (( prior_crash )); then
|
|
info "Resetting stale configs to recover from prior failed launch."
|
|
elif (( fresh_install )); then
|
|
info "Fresh Resolve install - clearing any configs from in-install launches."
|
|
else
|
|
info "RESOLVE_RESET_CONFIG=1 set - forcing config reset."
|
|
fi
|
|
info "Project databases preserved (Resolve Disk Database, Resolve Project Library)."
|
|
rm -rf "${resolve_user_dir}/configs" "${resolve_user_dir}/logs" 2>/dev/null || true
|
|
success "Stale configs cleared. Next launch will run first-launch onboarding."
|
|
else
|
|
info "No stale config markers found."
|
|
fi
|
|
}
|
|
|
|
verify_opencl() {
|
|
# Sanity-check that an AMD OpenCL platform is visible after install.
|
|
# Resolve crashes on first launch with 'Unsupported GPU Processing Mode'
|
|
# if it can't see ANY OpenCL device, so this is the most useful single
|
|
# check we can do without launching Resolve.
|
|
header "OpenCL Sanity Check"
|
|
|
|
if ! command -v clinfo &>/dev/null; then
|
|
warn "clinfo not installed - cannot verify OpenCL visibility."
|
|
return
|
|
fi
|
|
|
|
local platforms
|
|
platforms=$(clinfo -l 2>/dev/null || true)
|
|
|
|
if echo "$platforms" | grep -qiE "AMD|gfx|Radeon"; then
|
|
success "AMD OpenCL platform visible to clinfo:"
|
|
echo "$platforms" | head -10
|
|
else
|
|
warn "No AMD OpenCL platform detected. Resolve will crash with 'Unsupported GPU Processing Mode'."
|
|
warn "Run: clinfo -l (and check rocminfo for ROCm device detection)"
|
|
warn "Verify ICD vendor file: ls /etc/OpenCL/vendors/ (should include amdocl64.icd)"
|
|
fi
|
|
|
|
# Pinned-stack health check
|
|
if [[ "$OPENCL_PROVIDER" == "rocm-pinned-7.1.1" ]]; then
|
|
local stack_ok=1
|
|
for pkg in rocm-core rocm-device-libs rocm-llvm rocm-opencl-runtime comgr; do
|
|
local ver
|
|
ver=$(pacman -Q "$pkg" 2>/dev/null | awk '{print $2}')
|
|
if [[ -z "$ver" ]]; then
|
|
warn "Missing pinned package: $pkg"
|
|
stack_ok=0
|
|
elif [[ ! "$ver" =~ 7\.1\.1 ]]; then
|
|
warn "$pkg is at $ver but expected 7.1.1 - pin may have been overridden!"
|
|
stack_ok=0
|
|
fi
|
|
done
|
|
local spirv_ver
|
|
spirv_ver=$(pacman -Q spirv-llvm-translator 2>/dev/null | awk '{print $2}')
|
|
if [[ -n "$spirv_ver" && ! "$spirv_ver" =~ 21\.1\.3 ]]; then
|
|
warn "spirv-llvm-translator is at $spirv_ver but expected 21.1.3"
|
|
stack_ok=0
|
|
fi
|
|
if [[ "$stack_ok" == 1 ]]; then
|
|
success "ROCm 7.1.1 pinned stack confirmed at correct versions."
|
|
else
|
|
warn "ROCm pinned stack drift detected - re-run install_rocm_pinned to repair."
|
|
fi
|
|
|
|
# IgnorePkg sanity
|
|
if grep -qE "^IgnorePkg.*rocm-core" /etc/pacman.conf; then
|
|
success "IgnorePkg pin is in place in /etc/pacman.conf [options]."
|
|
else
|
|
warn "IgnorePkg pin missing - next 'pacman -Syu' will break Resolve."
|
|
warn "Re-run install_rocm_pinned to fix."
|
|
fi
|
|
fi
|
|
}
|
|
|
|
cleanup_stale_extracts() {
|
|
# Previous failed runs may leave .resolve-extract-XXXXXX dirs (5-10 GB each)
|
|
# in ~/Downloads. Always clean these at the start.
|
|
local downloads_dir="$HOME/Downloads"
|
|
local stale=()
|
|
while IFS= read -r -d '' d; do
|
|
stale+=("$d")
|
|
done < <(find "$downloads_dir" -maxdepth 1 -type d -name '.resolve-extract-*' -print0 2>/dev/null)
|
|
|
|
if [[ ${#stale[@]} -gt 0 ]]; then
|
|
info "Cleaning ${#stale[@]} stale extraction dir(s) in ~/Downloads..."
|
|
rm -rf "${stale[@]}" 2>/dev/null || true
|
|
fi
|
|
}
|
|
|
|
create_launcher() {
|
|
header "Creating Launcher"
|
|
|
|
local launcher_dir="$HOME/.local/bin"
|
|
mkdir -p "$launcher_dir"
|
|
|
|
# GPU lock: whenever an AMD discrete GPU is present, pin OpenGL/Vulkan
|
|
# to that exact PCI bus address. This is unconditional - not gated on
|
|
# SCAN_IS_HYBRID, not gated on switcherooctl - because:
|
|
#
|
|
# - DRI_PRIME=1 is index-based and unsafe: it means "the OTHER card
|
|
# relative to Mesa's default", which on systems where the monitor
|
|
# is plugged into the AMD card is already AMD. =1 then FLIPS OpenGL
|
|
# to the iGPU, OpenCL stays on AMD via ROCR_VISIBLE_DEVICES, and
|
|
# CL/GL interop (clCreateContext with CL_GL_CONTEXT_KHR) fails -
|
|
# Resolve hangs on the Color page.
|
|
# - switcherooctl internally also uses DRI_PRIME=1, so it inherits
|
|
# the same bug. Skipping it avoids a needless layer.
|
|
# - On a single-GPU AMD box the pin is a no-op (correct card by
|
|
# default) but harmless, so we always emit it for safety.
|
|
#
|
|
# The explicit pci-DDDD_BB_DD_F tag pins by bus address and always
|
|
# lands on the real AMD card regardless of enumeration order, monitor
|
|
# routing, or compositor GBM device selection.
|
|
local gpu_launch_method=""
|
|
local prime_config=""
|
|
if [[ "$SCAN_HAS_AMD_DGPU" == true ]]; then
|
|
local amd_pci_tag=""
|
|
for i in "${!SCAN_GPU_VENDORS[@]}"; do
|
|
if [[ "${SCAN_GPU_VENDORS[$i]}" == "AMD" && "${SCAN_GPU_TYPES[$i]}" == "discrete" ]]; then
|
|
amd_pci_tag="pci-0000_${SCAN_GPU_PCI_IDS[$i]//[:.]/_}"
|
|
break
|
|
fi
|
|
done
|
|
if [[ -n "$amd_pci_tag" ]]; then
|
|
gpu_launch_method="dri_prime"
|
|
prime_config="
|
|
# Lock GPU to the discrete AMD card by PCI bus address. See create_launcher()
|
|
# in install-davinci-resolve.sh for why this is unconditional and why
|
|
# DRI_PRIME=1 / switcherooctl are deliberately not used.
|
|
export DRI_PRIME=${amd_pci_tag}
|
|
export MESA_VK_DEVICE_SELECT_FORCE_DEFAULT_DEVICE=1
|
|
export MESA_VK_DEVICE_SELECT=${amd_pci_tag}"
|
|
else
|
|
warn "AMD discrete GPU detected but PCI ID missing - falling back to no DRI_PRIME pin."
|
|
fi
|
|
elif [[ "$SCAN_IS_HYBRID" == true && "$SCAN_HAS_NVIDIA_DGPU" == true ]]; then
|
|
# Hybrid + NVIDIA discrete (no AMD discrete): use NVIDIA offload
|
|
gpu_launch_method="nvidia_prime"
|
|
prime_config='
|
|
# Hybrid GPU: Force discrete NVIDIA GPU
|
|
export __NV_PRIME_RENDER_OFFLOAD=1
|
|
export __GLX_VENDOR_LIBRARY_NAME=nvidia
|
|
export __VK_LAYER_NV_optimus=NVIDIA_only'
|
|
fi
|
|
|
|
# ROCm environment configuration.
|
|
# For rocm-pinned-7.1.1 (the working stack), ALWAYS export
|
|
# HSA_OVERRIDE_GFX_VERSION (matched to the detected gfx target) and
|
|
# ROCR_VISIBLE_DEVICES=0. These were empirically required to make
|
|
# Resolve's clCreateContext succeed on RDNA4 + ROCm 7.1.1 even though
|
|
# gfx1200 is "natively supported".
|
|
local rocm_config=""
|
|
if [[ "$OPENCL_PROVIDER" == "rocm-pinned-7.1.1" || "$OPENCL_PROVIDER" == "rocm-full" ]]; then
|
|
# Choose HSA value:
|
|
# - if scan detected a card needing spoof override, use that
|
|
# - else if we know the gfx target, use the matching native value
|
|
# - else leave unset (let ROCm autodetect)
|
|
local hsa_value="${SCAN_HSA_OVERRIDE_VALUE}"
|
|
if [[ -z "$hsa_value" && -n "$SCAN_GFX_TARGET" ]]; then
|
|
case "$SCAN_GFX_TARGET" in
|
|
gfx1201) hsa_value="12.0.1" ;;
|
|
gfx1200) hsa_value="12.0.0" ;;
|
|
gfx1101) hsa_value="11.0.1" ;;
|
|
gfx1100) hsa_value="11.0.0" ;;
|
|
gfx1030) hsa_value="10.3.0" ;;
|
|
esac
|
|
fi
|
|
|
|
local hsa_section=""
|
|
if [[ -n "$hsa_value" ]]; then
|
|
hsa_section="
|
|
# Detected ${SCAN_GFX_TARGET}. Setting HSA_OVERRIDE_GFX_VERSION explicitly
|
|
# (required for Resolve to succeed at clCreateContext on AMD even though
|
|
# this target is natively supported by ROCm).
|
|
export HSA_OVERRIDE_GFX_VERSION=${hsa_value}
|
|
# Pin Resolve to the discrete AMD GPU (defensive)
|
|
export ROCR_VISIBLE_DEVICES=0"
|
|
else
|
|
hsa_section='
|
|
# Could not auto-detect gfx target. Uncomment one of the lines below:
|
|
# export HSA_OVERRIDE_GFX_VERSION=12.0.1 # RX 9070 / 9070 XT (Navi 48, gfx1201)
|
|
# export HSA_OVERRIDE_GFX_VERSION=12.0.0 # RX 9060 / 9060 XT (Navi 44, gfx1200)
|
|
# export HSA_OVERRIDE_GFX_VERSION=11.0.1 # RX 7700/7800 (Navi 32, gfx1101)
|
|
# export HSA_OVERRIDE_GFX_VERSION=11.0.0 # RX 7900 (Navi 31, gfx1100) / RX 7600 (Navi 33, gfx1102)
|
|
# export HSA_OVERRIDE_GFX_VERSION=10.3.0 # RX 6800/6900 / RX 6600/6700 (RDNA2)
|
|
# export ROCR_VISIBLE_DEVICES=0'
|
|
fi
|
|
|
|
rocm_config="
|
|
# ROCm environment
|
|
export ROCM_PATH=/opt/rocm
|
|
export PATH=\"\$ROCM_PATH/bin:\$PATH\"
|
|
export LD_LIBRARY_PATH=\"\$ROCM_PATH/lib:\$ROCM_PATH/lib64:\$LD_LIBRARY_PATH\"
|
|
${hsa_section}
|
|
|
|
# ROCm OpenCL configuration
|
|
export OCL_ICD_VENDORS=/etc/OpenCL/vendors"
|
|
fi
|
|
|
|
# Create main launcher. AMD-discrete pin (prime_config) is unconditional
|
|
# when an AMD dGPU is present, so there is only one launcher template.
|
|
cat > "$launcher_dir/davinci-resolve" << EOF
|
|
#!/bin/bash
|
|
# DaVinci Resolve Launcher with workarounds
|
|
# Generated by install script on $(date)
|
|
# OpenCL Provider: $OPENCL_PROVIDER
|
|
# Fixes applied: patchelf (davincibox method)
|
|
|
|
# Clear stale single-instance Qt lockfiles (left behind by crashes/SIGKILL)
|
|
for lockfile in /tmp/qtsingleapp-DaVinci*lockfile; do
|
|
[[ -f "\$lockfile" ]] && rm -f "\$lockfile" 2>/dev/null || true
|
|
done
|
|
|
|
# Qt configuration for XWayland
|
|
export QT_QPA_PLATFORM=xcb
|
|
export QT_AUTO_SCREEN_SCALE_FACTOR=1
|
|
${prime_config}
|
|
${rocm_config}
|
|
|
|
# Increase file descriptor limit for large projects
|
|
ulimit -n 65535 2>/dev/null
|
|
|
|
exec /opt/resolve/bin/resolve "\$@"
|
|
EOF
|
|
|
|
chmod +x "$launcher_dir/davinci-resolve"
|
|
|
|
# Create Rusticl fallback launcher (davincibox -c flag equivalent)
|
|
# Use this if ROCm OpenCL doesn't work with your GPU
|
|
cat > "$launcher_dir/davinci-resolve-rusticl" << 'EOF'
|
|
#!/bin/bash
|
|
# DaVinci Resolve Launcher - Rusticl OpenCL Fallback
|
|
# Use this if ROCm doesn't work with your GPU (davincibox -c equivalent)
|
|
# Requires: opencl-rusticl-mesa package
|
|
|
|
export QT_QPA_PLATFORM=xcb
|
|
export QT_AUTO_SCREEN_SCALE_FACTOR=1
|
|
|
|
# Rusticl configuration (Mesa OpenCL implementation)
|
|
export RUSTICL_ENABLE=radeonsi,iris,nouveau
|
|
export OCL_ICD_VENDORS=rusticl.icd
|
|
|
|
ulimit -n 65535 2>/dev/null
|
|
exec /opt/resolve/bin/resolve "$@"
|
|
EOF
|
|
chmod +x "$launcher_dir/davinci-resolve-rusticl"
|
|
info "Created Rusticl fallback launcher: davinci-resolve-rusticl"
|
|
|
|
# Also create a version that forces integrated GPU (useful for testing/power saving)
|
|
if [[ "$SCAN_IS_HYBRID" == true ]]; then
|
|
cat > "$launcher_dir/davinci-resolve-igpu" << 'EOF'
|
|
#!/bin/bash
|
|
# DaVinci Resolve Launcher - Force Integrated GPU
|
|
# Use this for power saving or if discrete GPU causes issues
|
|
|
|
export QT_QPA_PLATFORM=xcb
|
|
export QT_AUTO_SCREEN_SCALE_FACTOR=1
|
|
export DRI_PRIME=0
|
|
|
|
ulimit -n 65535 2>/dev/null
|
|
exec /opt/resolve/bin/resolve "$@"
|
|
EOF
|
|
chmod +x "$launcher_dir/davinci-resolve-igpu"
|
|
info "Created alternate launcher: davinci-resolve-igpu (uses integrated GPU)"
|
|
fi
|
|
|
|
# Update PATH in shell configs
|
|
for rcfile in ~/.bashrc ~/.zshrc; do
|
|
if [[ -f "$rcfile" ]] && ! grep -q 'HOME/.local/bin' "$rcfile"; then
|
|
echo 'export PATH="$HOME/.local/bin:$PATH"' >> "$rcfile"
|
|
fi
|
|
done
|
|
|
|
# Patch the Resolve-bundled system .desktop files to invoke our wrapper
|
|
# instead of the bare /opt/resolve/bin/resolve. The bare binary skips Qt
|
|
# lockfile cleanup, DRI_PRIME pinning, HSA_OVERRIDE, etc. This is the
|
|
# difference between "app-menu launch silently does nothing" and
|
|
# "Resolve actually starts".
|
|
#
|
|
# We deliberately DO NOT also create ~/.local/share/applications/davinci-resolve.desktop
|
|
# - the basenames differ from the system entry (davinci-resolve.desktop vs
|
|
# DaVinciResolve.desktop), so XDG would not shadow it and walker / app
|
|
# menus would show TWO "DaVinci Resolve" entries. One patched system
|
|
# entry is sufficient.
|
|
local wrapper="$HOME/.local/bin/davinci-resolve"
|
|
for sysdesktop in \
|
|
/usr/share/applications/DaVinciResolve.desktop \
|
|
/usr/share/applications/DaVinciResolveCaptureLogs.desktop; do
|
|
if [[ -f "$sysdesktop" ]]; then
|
|
sudo sed -i "s|^Exec=.*|Exec=$wrapper %U|" "$sysdesktop"
|
|
fi
|
|
done
|
|
|
|
# Remove any user-level davinci-resolve.desktop left over from older
|
|
# script runs (would duplicate the system entry in walker).
|
|
rm -f "$HOME/.local/share/applications/davinci-resolve.desktop" 2>/dev/null || true
|
|
|
|
sudo update-desktop-database >/dev/null 2>&1 || true
|
|
update-desktop-database "$HOME/.local/share/applications" >/dev/null 2>&1 || true
|
|
|
|
# System-wide convenience symlink so `davinci-resolve` works from any
|
|
# shell even when ~/.local/bin isn't on PATH (e.g. cron, ssh).
|
|
if [[ ! -e /usr/bin/davinci-resolve ]]; then
|
|
echo -e "#!/usr/bin/env bash\nexec $wrapper \"\$@\"" | \
|
|
sudo tee /usr/bin/davinci-resolve >/dev/null
|
|
sudo chmod +x /usr/bin/davinci-resolve
|
|
info "Created /usr/bin/davinci-resolve symlink"
|
|
fi
|
|
|
|
success "Launcher created."
|
|
|
|
echo ""
|
|
info "Available launchers:"
|
|
echo " davinci-resolve - Main launcher (default)"
|
|
echo " davinci-resolve-rusticl - Rusticl OpenCL fallback (if ROCm fails)"
|
|
|
|
if [[ "$SCAN_IS_HYBRID" == true ]]; then
|
|
echo " davinci-resolve-igpu - Force integrated GPU"
|
|
fi
|
|
echo ""
|
|
if [[ "$SCAN_HAS_AMD_DGPU" == true ]]; then
|
|
info "Launcher locked to AMD discrete GPU via PCI tag (DRI_PRIME=${amd_pci_tag:-<pci-tag>})"
|
|
elif [[ "$SCAN_IS_HYBRID" == true && "$SCAN_HAS_NVIDIA_DGPU" == true ]]; then
|
|
info "Hybrid GPU detected - launcher uses NVIDIA discrete via __NV_PRIME_RENDER_OFFLOAD"
|
|
fi
|
|
|
|
echo ""
|
|
info "If Resolve fails to use GPU, try: davinci-resolve-rusticl"
|
|
echo " (requires: sudo pacman -S opencl-rusticl-mesa)"
|
|
}
|
|
|
|
configure_hyprland() {
|
|
if [[ "$SCAN_HYPRLAND_INSTALLED" != true ]]; then
|
|
info "Hyprland not installed. Skipping configuration."
|
|
return
|
|
fi
|
|
|
|
header "Configuring Hyprland"
|
|
|
|
local hypr_conf="$HOME/.config/hypr/hyprland.conf"
|
|
|
|
if [[ ! -f "$hypr_conf" ]]; then
|
|
warn "Hyprland config not found at $hypr_conf"
|
|
echo "Add these rules manually (Hyprland 0.53+ syntax):"
|
|
echo ""
|
|
cat << 'EOF'
|
|
# Tag every floating Resolve window for easy targeting of the cosmetic
|
|
# tweaks below. Do NOT add `stay_focused on` here - it locks focus inside
|
|
# modal dialogs (Project Settings, Preferences, Render) so clicks on the
|
|
# main window do nothing, which feels like a trapped cursor.
|
|
windowrule = tag +drpopup, match:class ^(resolve)$, match:float 1
|
|
windowrule = border_size 0, match:tag drpopup
|
|
windowrule = no_shadow on, match:tag drpopup
|
|
windowrule = rounding 0, match:tag drpopup
|
|
windowrule = opacity 1, match:tag drpopup
|
|
EOF
|
|
return
|
|
fi
|
|
|
|
if grep -q "drpopup.*resolve\|tag +drpopup" "$hypr_conf" 2>/dev/null; then
|
|
info "Hyprland rules already configured."
|
|
return
|
|
fi
|
|
|
|
cp "$hypr_conf" "$hypr_conf.backup.$(date +%Y%m%d%H%M%S)"
|
|
|
|
# Hyprland 0.53+ syntax (windowrulev2 was removed). Verified against
|
|
# Omarchy's own default windowrules + Hyprland 0.54.3 binary symbols.
|
|
cat >> "$hypr_conf" << 'EOF'
|
|
|
|
# DaVinci Resolve - Fix floating dialogs (Hyprland 0.53+ syntax)
|
|
# Tag every floating Resolve window for easy targeting of the cosmetic
|
|
# tweaks below. Do NOT add `stay_focused on` here - it locks focus inside
|
|
# modal dialogs (Project Settings, Preferences, Render) so clicks on the
|
|
# main window do nothing, which feels like a trapped cursor.
|
|
windowrule = tag +drpopup, match:class ^(resolve)$, match:float 1
|
|
windowrule = border_size 0, match:tag drpopup
|
|
windowrule = no_shadow on, match:tag drpopup
|
|
windowrule = rounding 0, match:tag drpopup
|
|
windowrule = opacity 1, match:tag drpopup
|
|
EOF
|
|
|
|
success "Hyprland rules added."
|
|
info "Reload with: hyprctl reload && hyprctl configerrors"
|
|
}
|
|
|
|
create_conversion_script() {
|
|
header "Creating Media Conversion Helper"
|
|
|
|
cat > "$HOME/.local/bin/resolve-convert" << 'EOF'
|
|
#!/bin/bash
|
|
# Convert media to DNxHR for DaVinci Resolve Free (Linux)
|
|
|
|
convert_file() {
|
|
local input="$1"
|
|
local output="${2:-${input%.*}_dnxhr.mov}"
|
|
echo "Converting: $input -> $output"
|
|
ffmpeg -i "$input" -c:v dnxhd -profile:v dnxhr_hq -pix_fmt yuv422p -c:a pcm_s16le -y "$output"
|
|
echo "Done: $output"
|
|
}
|
|
|
|
[[ $# -eq 0 ]] && { echo "Usage: resolve-convert input.mp4 [output.mov]"; exit 1; }
|
|
|
|
if [[ $# -eq 2 && ! "$2" =~ \.(mp4|mkv|avi|webm)$ ]]; then
|
|
convert_file "$1" "$2"
|
|
else
|
|
for f in "$@"; do [[ -f "$f" ]] && convert_file "$f"; done
|
|
fi
|
|
EOF
|
|
|
|
chmod +x "$HOME/.local/bin/resolve-convert"
|
|
success "Created: resolve-convert"
|
|
}
|
|
|
|
install_diagnostics() {
|
|
header "Installing Diagnostics"
|
|
|
|
local checker_dir="$HOME/.local/share/davinci-resolve-checker"
|
|
|
|
$SCAN_AUR_HELPER -S --needed --noconfirm python-pylspci 2>/dev/null || true
|
|
|
|
if [[ -d "$checker_dir" ]]; then
|
|
cd "$checker_dir" && git pull --quiet
|
|
else
|
|
git clone --quiet https://github.com/Ashark/davinci-resolve-checker.git "$checker_dir"
|
|
fi
|
|
|
|
ln -sf "$checker_dir/davinci-resolve-checker.py" "$HOME/.local/bin/davinci-resolve-checker"
|
|
chmod +x "$checker_dir/davinci-resolve-checker.py"
|
|
|
|
success "Installed: davinci-resolve-checker"
|
|
}
|
|
|
|
print_summary() {
|
|
echo ""
|
|
echo "============================================================"
|
|
echo -e "${GREEN} Installation Complete!${NC}"
|
|
echo "============================================================"
|
|
echo ""
|
|
echo " Launch: davinci-resolve"
|
|
echo ""
|
|
echo " OpenCL Provider: $OPENCL_PROVIDER"
|
|
echo " Install method: NVIDIA-mirrored (manual extract + RPATH patch to /opt/resolve)"
|
|
echo " Fixes applied: glib symlink replace, RPATH patching, OpenCL decoder disable,"
|
|
echo " audio backend (DeckLink->ALSA), snd-aloop, TLS cert symlink,"
|
|
echo " Qt lockfile cleanup, libcrypt.so.1 fallback"
|
|
if [[ "$OPENCL_PROVIDER" == "rocm-pinned-7.1.1" ]]; then
|
|
echo " + ROCm 7.1.1 pinned from Arch Linux Archive"
|
|
echo " + IgnorePkg in /etc/pacman.conf [options]"
|
|
echo " + HSA_OVERRIDE_GFX_VERSION + ROCR_VISIBLE_DEVICES baked into launcher"
|
|
fi
|
|
echo ""
|
|
echo " Env vars (set before re-running this script):"
|
|
echo " RESOLVE_NO_ALOOP=1 Skip snd-aloop setup (you have a real audio interface)"
|
|
echo " RESOLVE_RESET_CONFIG=1 Force-wipe ~/.local/share/DaVinciResolve/{configs,logs}"
|
|
echo " (use after fixing OpenCL stack to clear crash snapshots)"
|
|
echo ""
|
|
if [[ "$OPENCL_PROVIDER" == "rocm-pinned-7.1.1" ]]; then
|
|
echo " IMPORTANT - ROCm 7.1.1 is PINNED:"
|
|
echo " ROCm 7.2.x breaks DaVinci Resolve (https://github.com/ROCm/ROCm/issues/5982)"
|
|
echo " These packages will NOT update on 'pacman -Syu':"
|
|
echo " rocm-core rocm-device-libs rocm-llvm rocm-opencl-runtime"
|
|
echo " comgr spirv-llvm-translator"
|
|
echo " When ROCm 7.3+ ships with the fix, lift the pin:"
|
|
echo " sudo sed -i '/^IgnorePkg.*rocm-/d' /etc/pacman.conf"
|
|
echo " sudo pacman -Syu"
|
|
echo ""
|
|
fi
|
|
echo " ROCm/diagnostic tools:"
|
|
echo " rocminfo # Show ROCm GPU info (Name: + Marketing Name)"
|
|
echo " rocm-smi # ROCm System Management Interface"
|
|
echo " clinfo -l # Check OpenCL platforms"
|
|
echo " davinci-resolve-checker # Diagnose Resolve issues"
|
|
echo ""
|
|
echo " Free version codec limitation (Linux):"
|
|
echo " No H.264/H.265/MP4 - convert with: resolve-convert video.mp4"
|
|
echo ""
|
|
echo " To upgrade Resolve: download new ZIP to ~/Downloads, re-run this script."
|
|
echo " To uninstall:"
|
|
echo " sudo rm -rf /opt/resolve"
|
|
echo " sudo rm -f /usr/share/applications/{DaVinciResolve,DaVinciControlPanelsSetup,blackmagicraw-*}.desktop"
|
|
echo " sudo rm -f /usr/lib/udev/rules.d/{99-BlackmagicDevices,99-ResolveKeyboardHID,99-DavinciPanel}.rules"
|
|
echo " sudo sed -i '/^IgnorePkg.*rocm-/d' /etc/pacman.conf # lift the pin"
|
|
echo ""
|
|
if [[ -n "$SCAN_GFX_TARGET" ]]; then
|
|
echo " GPU Detection:"
|
|
echo " Detected $SCAN_GFX_TARGET. Launcher pre-configured with:"
|
|
echo " HSA_OVERRIDE_GFX_VERSION (matched to your gfx target)"
|
|
echo " ROCR_VISIBLE_DEVICES=0"
|
|
echo " These were empirically required to make Resolve clCreateContext"
|
|
echo " succeed on AMD even though gfx1100+ targets are 'natively supported'."
|
|
echo ""
|
|
echo " Verify GPU detection: rocminfo | grep -E 'Name:|gfx'"
|
|
echo ""
|
|
fi
|
|
echo "============================================================"
|
|
}
|
|
|
|
# =============================================================================
|
|
# MAIN
|
|
# =============================================================================
|
|
|
|
main() {
|
|
echo ""
|
|
echo "============================================================"
|
|
echo " DaVinci Resolve Installer v4.1"
|
|
echo " Arch Linux + AMD (RDNA2/3/4) + Hyprland"
|
|
echo " NVIDIA-mirrored install path (extract + RPATH to /opt/resolve)"
|
|
echo " ROCm 7.1.1 pinned (working stack for Resolve on AMD, May 2026)"
|
|
echo "============================================================"
|
|
echo ""
|
|
|
|
# Run system scan
|
|
run_system_scan
|
|
display_scan_results
|
|
|
|
# Analyze and check for blockers
|
|
if ! analyze_scan_results; then
|
|
echo ""
|
|
read -p "Continue despite issues? [y/N] " -n 1 -r
|
|
echo
|
|
[[ ! $REPLY =~ ^[Yy]$ ]] && exit 1
|
|
fi
|
|
|
|
# Check AUR helper
|
|
if [[ -z "$SCAN_AUR_HELPER" ]]; then
|
|
error "No AUR helper found. Install yay or paru first."
|
|
fi
|
|
|
|
# Build package list
|
|
build_package_list
|
|
|
|
echo ""
|
|
read -p "Proceed with installation? [Y/n] " -n 1 -r
|
|
echo
|
|
[[ $REPLY =~ ^[Nn]$ ]] && exit 0
|
|
|
|
# Full system upgrade first - Arch is a rolling distro and partial upgrades
|
|
# (pacman -Sy <pkg> without -u) are unsupported and can break the system.
|
|
# This also ensures we get the latest ROCm.
|
|
header "System Update"
|
|
info "Arch is a rolling-release distro - a full system upgrade is recommended"
|
|
info "before installing new packages, to avoid partial-upgrade breakage and"
|
|
info "to pull the latest ROCm release."
|
|
echo ""
|
|
read -p "Run 'sudo pacman -Syu' now? [Y/n] " -n 1 -r
|
|
echo
|
|
if [[ ! $REPLY =~ ^[Nn]$ ]]; then
|
|
sudo pacman -Syu --noconfirm
|
|
# Refresh the cached package list since the upgrade may have changed it
|
|
scan_installed_packages
|
|
success "System updated."
|
|
else
|
|
warn "Skipping system upgrade - proceed at your own risk."
|
|
warn "If pacman complains about stale databases, re-run after 'sudo pacman -Syu'."
|
|
fi
|
|
|
|
# Configure user groups for GPU access
|
|
configure_user_groups
|
|
|
|
# Clean up any leftover extraction dirs from prior failed runs
|
|
cleanup_stale_extracts
|
|
|
|
# Install
|
|
install_pacman_packages
|
|
install_aur_packages
|
|
install_rocm_pinned # downloads ROCm 7.1.1 from ALA + pins it
|
|
install_davinci_resolve
|
|
disable_opencl_decoders
|
|
setup_tls_symlink
|
|
patch_audio_backend
|
|
setup_snd_aloop
|
|
create_launcher
|
|
configure_hyprland
|
|
create_conversion_script
|
|
install_diagnostics
|
|
|
|
# Reset stale Resolve user configs if a prior crash marker exists
|
|
reset_stale_configs
|
|
|
|
# Final sanity check
|
|
verify_opencl
|
|
|
|
print_summary
|
|
}
|
|
|
|
main "$@"
|