DaVinci-Resolve-AMD-Omarchy/install-davinci-resolve.sh
28allday d80b376e99 Initial commit: DaVinci Resolve installer for Arch Linux + AMD RDNA 4
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 12:30:52 +00:00

1870 lines
61 KiB
Bash
Executable file

#!/bin/bash
# =============================================================================
# DaVinci Resolve Free - Arch Linux + AMD RX 9000 + Hyprland Install Script
# =============================================================================
#
# Version 3.0 - Davincibox-style fixes for better compatibility
# Validated against Arch Wiki, AUR, davincibox, and community docs (Dec 2025)
#
# Features:
# - Pre-installation system scan to detect configuration
# - Smart package selection based on existing setup
# - AMD RX 9000 series (RDNA 4 / gfx1201) GPU support via ROCm
# - Choice of OpenCL provider: rocm-full (recommended) or opencl-amd (AUR)
# - Patchelf fix for glib issues (cleaner than LD_PRELOAD)
# - Disables problematic BlackmagicRaw OpenCL decoders
# - Removes conflicting OpenCL packages (rusticl breaks ROCm)
# - Hyprland compatibility (XWayland required)
# - Hybrid GPU support (Intel/AMD iGPU + discrete GPU)
#
# Based on techniques from:
# - https://github.com/zelikos/davincibox
# - https://wiki.archlinux.org/title/DaVinci_Resolve
#
# Usage:
# chmod +x install-davinci-resolve.sh
# ./install-davinci-resolve.sh
#
# =============================================================================
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: "opencl-amd" (AUR) or "rocm-full" (official Arch ROCm stack)
# opencl-amd: Uses AUR package (7.1.1+), includes both ROCm and ORCA - RECOMMENDED
# rocm-full: Uses official Arch repos (6.4.4+), full ROCm stack with HIP
#
# NOTE: Arch Wiki recommends opencl-amd for DaVinci Resolve
# "DaVinci Resolve seems to need opencl-amd and doesn't work with rocm-opencl-runtime"
# Change to "rocm-full" if you need HIP support or experience issues
OPENCL_PROVIDER="opencl-amd"
# =============================================================================
# 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_DRIVERS_LOADED=()
SCAN_PRIMARY_GPU_INDEX=0
# 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
if echo "$gpu_line" | grep -qi "AMD\|ATI\|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
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 -qi "Intel"; then
vendor="Intel"
gpu_type="integrated"
SCAN_HAS_IGPU=true
SCAN_HAS_INTEL_IGPU=true
rdna_ver="N/A"
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 for AMD GPUs
if [[ "$vendor" == "AMD" ]]; then
SCAN_GPU_RDNA_VERSIONS+=("$rdna_ver")
else
SCAN_GPU_RDNA_VERSIONS+=("")
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]}"
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
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++))
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++))
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, launch with: DRI_PRIME=1 davinci-resolve"
((warnings++))
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=1 davinci-resolve"
echo " The launcher script will be configured for this."
((warnings++))
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++))
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++))
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++))
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++))
elif [[ "$SCAN_GPU_VENDOR" == "Intel" ]]; then
echo -e "${YELLOW}[WARNING]${NC} Only Intel GPU detected. DaVinci Resolve has limited Intel support."
((warnings++))
else
echo -e "${YELLOW}[WARNING]${NC} GPU vendor not recognized. This script is optimized for AMD GPUs."
((warnings++))
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++))
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++))
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++))
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++))
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++))
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++))
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=()
# Core graphics packages
# Note: libva-mesa-driver and mesa-vdpau are now merged into mesa package
local core_graphics=(
"mesa"
"glu"
)
for pkg in "${core_graphics[@]}"; do
if is_pkg_installed "$pkg"; then
SKIP_PACKAGES+=("$pkg")
else
PACMAN_PACKAGES+=("$pkg")
fi
done
# OpenCL/ROCm - based on OPENCL_PROVIDER configuration
if [[ "$OPENCL_PROVIDER" == "rocm-full" ]]; then
# Full ROCm stack from official Arch repos (recommended for RDNA4)
info "Using full ROCm stack (official Arch repos)"
# Check if already installed and working
if [[ "$SCAN_AMD_OPENCL_WORKING" == true && "$SCAN_OPENCL_PROVIDER" == rocm-full* ]]; then
info "ROCm already configured correctly"
SKIP_PACKAGES+=("rocm-opencl-runtime" "rocm-hip-runtime" "rocm-core")
else
# Core ROCm packages from official repos
local rocm_packages=(
"rocm-core"
"rocm-opencl-runtime"
"rocm-hip-runtime"
"hsa-rocr"
"rocminfo"
"rocm-smi-lib"
)
for pkg in "${rocm_packages[@]}"; do
if is_pkg_installed "$pkg"; then
SKIP_PACKAGES+=("$pkg")
else
PACMAN_PACKAGES+=("$pkg")
fi
done
fi
# Remove conflicting AUR package if present
if is_pkg_installed "opencl-amd"; then
warn "opencl-amd (AUR) will be replaced with rocm-opencl-runtime"
fi
else
# AUR opencl-amd (legacy option)
info "Using opencl-amd (AUR package)"
if [[ "$SCAN_AMD_OPENCL_WORKING" == true && "$SCAN_OPENCL_PROVIDER" == "opencl-amd" ]]; then
info "OpenCL already configured correctly with opencl-amd"
SKIP_PACKAGES+=("opencl-amd")
else
if ! is_pkg_installed "ocl-icd"; then
PACMAN_PACKAGES+=("ocl-icd")
else
SKIP_PACKAGES+=("ocl-icd")
fi
AUR_PACKAGES+=("opencl-amd")
fi
fi
# System libraries (includes davincibox dependencies mapped to Arch packages)
# Note: gtk2 moved to AUR on Arch (late 2024)
local system_libs=(
"libxcrypt-compat"
"fuse2"
"fuse3"
"libc++"
"libc++abi"
"patchelf"
# Additional libraries from davincibox
"alsa-lib"
"apr"
"apr-util"
"libglvnd"
"libice"
"libsm"
"librsvg"
"libxcursor"
"libxfixes"
"libxi"
"libxinerama"
"libxkbcommon-x11"
"libxkbfile"
"libxrandr"
"libxtst"
"libxxf86vm"
"lshw"
"mtdev"
"nss"
"libpulse"
"python-gobject"
"gdk-pixbuf2"
)
for pkg in "${system_libs[@]}"; do
if is_pkg_installed "$pkg"; then
SKIP_PACKAGES+=("$pkg")
else
PACMAN_PACKAGES+=("$pkg")
fi
done
# Qt packages
# Note: qt5-webengine and qt5-websockets moved to AUR on Arch (Qt5 deprecated in favor of Qt6)
local qt_packages=(
"qt5-x11extras"
"qt5-svg"
"qt5-quickcontrols2"
"qt5-multimedia"
)
# DaVinci Resolve runtime dependencies (from AUR PKGBUILD)
local resolve_deps=(
"python-numpy"
"onetbb" # Was 'tbb', renamed on Arch
"xmlsec"
"gst-plugins-bad-libs"
"luajit"
)
for pkg in "${qt_packages[@]}"; do
if is_pkg_installed "$pkg"; then
SKIP_PACKAGES+=("$pkg")
else
PACMAN_PACKAGES+=("$pkg")
fi
done
for pkg in "${resolve_deps[@]}"; do
if is_pkg_installed "$pkg"; then
SKIP_PACKAGES+=("$pkg")
else
PACMAN_PACKAGES+=("$pkg")
fi
done
# Display packages (includes xcb-util packages from davincibox)
local display_packages=(
"xorg-xwayland"
"xdg-desktop-portal"
"xdg-desktop-portal-gtk"
# XCB utilities from davincibox
"xcb-util"
"xcb-util-cursor"
"xcb-util-image"
"xcb-util-keysyms"
"xcb-util-renderutil"
"xcb-util-wm"
# GPU switching for hybrid systems
"switcheroo-control"
)
for pkg in "${display_packages[@]}"; do
if is_pkg_installed "$pkg"; then
SKIP_PACKAGES+=("$pkg")
else
PACMAN_PACKAGES+=("$pkg")
fi
done
# Audio packages - smart selection based on current audio server
if [[ "$SCAN_AUDIO_SERVER" == *"PipeWire"* ]]; then
info "PipeWire detected - using pipewire-pulse for audio"
if ! is_pkg_installed "pipewire-pulse"; then
PACMAN_PACKAGES+=("pipewire-pulse")
else
SKIP_PACKAGES+=("pipewire-pulse")
fi
# Also need ALSA bridge for some Resolve functionality
if ! is_pkg_installed "pipewire-alsa"; then
PACMAN_PACKAGES+=("pipewire-alsa")
fi
else
info "PulseAudio/other detected - using pulseaudio-alsa"
if ! is_pkg_installed "pulseaudio-alsa"; then
PACMAN_PACKAGES+=("pulseaudio-alsa")
else
SKIP_PACKAGES+=("pulseaudio-alsa")
fi
fi
# Diagnostic tools
local diag_tools=(
"clinfo"
"mesa-utils"
"expac"
"python-distro"
"unzip"
)
for pkg in "${diag_tools[@]}"; do
if is_pkg_installed "$pkg"; then
SKIP_PACKAGES+=("$pkg")
else
PACMAN_PACKAGES+=("$pkg")
fi
done
# AUR packages (packages moved from official repos)
# gtk2 - moved to AUR late 2024
if ! is_pkg_installed "gtk2"; then
AUR_PACKAGES+=("gtk2")
else
SKIP_PACKAGES+=("gtk2")
fi
# qt5-webengine - moved to AUR (Qt5 deprecated)
# Use binary version to avoid 30+ min compile time
if ! is_pkg_installed "qt5-webengine" && ! is_pkg_installed "qt5-webengine-bin"; then
AUR_PACKAGES+=("qt5-webengine-bin")
else
SKIP_PACKAGES+=("qt5-webengine")
fi
# qt5-websockets - moved to AUR (Qt5 deprecated)
if ! is_pkg_installed "qt5-websockets"; then
AUR_PACKAGES+=("qt5-websockets")
else
SKIP_PACKAGES+=("qt5-websockets")
fi
if ! is_pkg_installed "libpng12"; then
AUR_PACKAGES+=("libpng12")
else
SKIP_PACKAGES+=("libpng12")
fi
# ffmpeg4.4 is now in official repos (extra)
if ! is_pkg_installed "ffmpeg4.4"; then
PACMAN_PACKAGES+=("ffmpeg4.4")
else
SKIP_PACKAGES+=("ffmpeg4.4")
fi
# DaVinci Resolve itself
if [[ "$SCAN_RESOLVE_INSTALLED" == false ]]; then
AUR_PACKAGES+=("davinci-resolve")
fi
# 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
# Handle libpng12 GPG key
if [[ " ${AUR_PACKAGES[*]} " =~ " libpng12 " ]]; then
info "Importing GPG key for libpng12..."
gpg --recv-keys F54984BFA16C640F 2>/dev/null || true
fi
# Install AUR packages (except davinci-resolve which needs special handling)
local aur_without_resolve=()
for pkg in "${AUR_PACKAGES[@]}"; do
if [[ "$pkg" != "davinci-resolve" ]]; then
aur_without_resolve+=("$pkg")
fi
done
if [[ ${#aur_without_resolve[@]} -gt 0 ]]; then
info "Installing AUR dependencies..."
$SCAN_AUR_HELPER -S --needed --noconfirm "${aur_without_resolve[@]}"
fi
success "AUR packages installed."
}
install_davinci_resolve() {
if [[ "$SCAN_RESOLVE_INSTALLED" == true ]]; then
info "DaVinci Resolve already installed. Skipping installation."
info "Will apply workarounds and configuration updates."
return 0
fi
header "Installing DaVinci Resolve"
# Find installer (handle filenames with spaces properly)
local downloads_dir="$HOME/Downloads"
local resolve_run="" resolve_zip=""
while IFS= read -r -d '' file; do
resolve_run="$file"
done < <(find "$downloads_dir" -maxdepth 1 -name "DaVinci_Resolve_*_Linux.run" -type f -print0 2>/dev/null | sort -zV)
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)
# PKGBUILD expects the ZIP file, not the extracted .run
# If we only have .run, we can't use the AUR PKGBUILD easily
if [[ -z "$resolve_zip" && -n "$resolve_run" ]]; then
warn "Only .run file found, but PKGBUILD expects .zip"
warn "Please download the ZIP file from Blackmagic website"
return 1
fi
if [[ -z "$resolve_zip" ]]; then
echo ""
warn "DaVinci Resolve ZIP not found in ~/Downloads"
echo ""
echo "Please download it:"
echo " 1. Go to: https://www.blackmagicdesign.com/products/davinciresolve"
echo " 2. Click 'Download' → 'DaVinci Resolve' (Free)"
echo " 3. Select 'Linux' and save 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"
# Check version for RDNA 4 compatibility
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
# Build via AUR
local build_dir
# Use home directory for build (tmpfs /tmp may be too small)
build_dir=$(mktemp -d -p "$HOME/.cache" davinci-build.XXXXXX)
local original_dir="$PWD"
info "Building in $build_dir..."
# Cleanup function for build directory
cleanup_build() {
cd "$original_dir" 2>/dev/null || cd ~
rm -rf "$build_dir" 2>/dev/null
}
trap cleanup_build EXIT
cd "$build_dir"
git clone https://aur.archlinux.org/davinci-resolve.git
cd davinci-resolve
# Copy the ZIP file (PKGBUILD expects ZIP, not .run)
# Rename to match expected filename: DaVinci_Resolve_${pkgver}_Linux.zip
local expected_zip="DaVinci_Resolve_${resolve_version}_Linux.zip"
cp "$resolve_zip" "$expected_zip"
# Fix Arch package renames in PKGBUILD
# tbb → onetbb (Intel TBB renamed on Arch)
sed -i "s/'tbb'/'onetbb'/g" PKGBUILD
# Update PKGBUILD version if needed
local version_updated=false
if [[ -n "$resolve_version" ]]; then
local pkgbuild_ver=$(grep "^pkgver=" PKGBUILD | cut -d'=' -f2)
if [[ "$resolve_version" != "$pkgbuild_ver" ]]; then
info "Updating PKGBUILD version to $resolve_version..."
sed -i "s/^pkgver=.*/pkgver=$resolve_version/" PKGBUILD
version_updated=true
# Use updpkgsums if available, otherwise we'll skip checksums during build
if command -v updpkgsums &>/dev/null; then
info "Updating checksums..."
updpkgsums
version_updated=false # checksums are now correct
else
info "Will skip checksum verification (version mismatch, updpkgsums not available)..."
fi
fi
fi
info "Building package (this takes several minutes)..."
if [[ "$version_updated" == true ]]; then
makepkg -si --noconfirm --skipchecksums
else
makepkg -si --noconfirm
fi
# Cleanup
cleanup_build
trap - EXIT
success "DaVinci Resolve installed."
}
apply_patchelf_fix() {
# Davincibox-style fix: use patchelf to add system library dependencies
# This is cleaner than LD_PRELOAD and survives across sessions
header "Applying Patchelf Fix (Davincibox Method)"
local resolve_bin="/opt/resolve/bin"
if [[ ! -d "$resolve_bin" ]]; then
warn "Resolve bin directory not found. Skipping patchelf fix."
return
fi
if ! command -v patchelf &>/dev/null; then
warn "patchelf not installed. Falling back to library move method."
apply_glib_fix_fallback
return
fi
# Check if already patched by looking for added dependencies
if patchelf --print-needed "$resolve_bin/resolve" 2>/dev/null | grep -q "libglib-2.0.so.0"; then
info "Patchelf fix already applied."
return
fi
info "Patching DaVinci Resolve binaries with system library dependencies..."
# Determine library path (Arch uses /usr/lib, Fedora uses /usr/lib64)
local lib_path="/usr/lib"
[[ -d "/usr/lib64" && -f "/usr/lib64/libglib-2.0.so.0" ]] && lib_path="/usr/lib64"
# Libraries to add as dependencies (forces use of system libs over bundled)
# Using full paths as davincibox does
local libs_to_add=(
"${lib_path}/libglib-2.0.so.0"
"${lib_path}/libgio-2.0.so.0"
"${lib_path}/libgmodule-2.0.so.0"
"${lib_path}/libgdk_pixbuf-2.0.so.0"
)
# Verify libraries exist
for lib in "${libs_to_add[@]}"; do
if [[ ! -f "$lib" ]]; then
warn "Library not found: $lib"
warn "Falling back to library names only..."
libs_to_add=(
"libglib-2.0.so.0"
"libgio-2.0.so.0"
"libgmodule-2.0.so.0"
"libgdk_pixbuf-2.0.so.0"
)
break
fi
done
# Patch all executables in bin directory using find (like davincibox)
info "Running: find $resolve_bin -executable -type f -exec patchelf ..."
local patch_count=0
while IFS= read -r -d '' binary; do
# Skip if not an ELF binary
file "$binary" 2>/dev/null | grep -q "ELF" || continue
local patch_args=""
for lib in "${libs_to_add[@]}"; do
patch_args+=" --add-needed $lib"
done
if sudo patchelf $patch_args "$binary" 2>/dev/null; then
((patch_count++))
fi
done < <(find "$resolve_bin" -executable -type f -print0 2>/dev/null)
local patched=$patch_count
local failed=0
if [[ $patched -gt 0 ]]; then
success "Patchelf fix applied to binaries."
else
warn "Patchelf fix may have failed. Applying fallback..."
apply_glib_fix_fallback
fi
}
apply_glib_fix_fallback() {
# Fallback: move bundled glib libraries (original method)
local resolve_libs="/opt/resolve/libs"
if [[ ! -d "$resolve_libs" ]]; then
warn "Resolve libs directory not found. Skipping."
return
fi
# Check if already fixed
if [[ -d "$resolve_libs/disabled-libraries" ]] && \
[[ ! -f "$resolve_libs/libglib-2.0.so.0" ]]; then
info "Glib fix (fallback) already applied."
return
fi
info "Moving bundled glib libraries (fallback method)..."
sudo mkdir -p "$resolve_libs/disabled-libraries"
# Use find to avoid glob pattern issues when no files match
while IFS= read -r -d '' lib; do
sudo mv "$lib" "$resolve_libs/disabled-libraries/" 2>/dev/null || true
done < <(find "$resolve_libs" -maxdepth 1 -type f \( -name 'libglib-2.0.so*' -o -name 'libgio-2.0.so*' -o -name 'libgmodule-2.0.so*' \) -print0 2>/dev/null)
success "Glib fix (fallback) applied."
}
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
}
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
}
setup_studio_usb_dongle() {
# For DaVinci Resolve Studio with USB license dongle
# Davincibox mentions vendor ID 096e for USB dongle access
header "Checking Studio USB Dongle Support"
local udev_rule_file="/etc/udev/rules.d/75-davinci-resolve-dongle.rules"
local udev_rule='SUBSYSTEM=="usb", ATTR{idVendor}=="096e", MODE="0666"'
# Check if Studio version
if [[ -f "/opt/resolve/bin/resolve" ]]; then
# Check if it's Studio by looking for specific files or just offer the option
if pacman -Qq davinci-resolve-studio &>/dev/null 2>&1 || \
[[ -f "/opt/resolve/Developer/Scripting/README.txt" ]]; then
info "DaVinci Resolve Studio detected"
if [[ ! -f "$udev_rule_file" ]]; then
read -p "Set up USB dongle udev rule for Studio license? [y/N] " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
echo "$udev_rule" | sudo tee "$udev_rule_file" > /dev/null
sudo udevadm control --reload-rules
sudo udevadm trigger
success "USB dongle udev rule installed."
fi
else
info "USB dongle udev rule already exists."
fi
else
info "DaVinci Resolve Free detected - USB dongle rule not needed."
fi
else
info "DaVinci Resolve not yet installed - skipping USB dongle setup."
fi
}
create_launcher() {
header "Creating Launcher"
local launcher_dir="$HOME/.local/bin"
mkdir -p "$launcher_dir"
# Check for switcherooctl (davincibox method for hybrid GPU)
local has_switcheroo=false
if command -v switcherooctl &>/dev/null && systemctl is-active --quiet switcheroo-control 2>/dev/null; then
has_switcheroo=true
fi
# Determine GPU launch method for hybrid systems
local gpu_launch_method=""
local prime_config=""
if [[ "$SCAN_IS_HYBRID" == true ]]; then
if [[ "$has_switcheroo" == true ]]; then
# Davincibox method: use switcherooctl for GPU selection
gpu_launch_method="switcheroo"
info "Using switcherooctl for GPU selection (davincibox method)"
elif [[ "$SCAN_HAS_AMD_DGPU" == true ]]; then
# Fallback: AMD discrete GPU - use DRI_PRIME
gpu_launch_method="dri_prime"
prime_config='
# Hybrid GPU: Force discrete AMD GPU
export DRI_PRIME=1'
elif [[ "$SCAN_HAS_NVIDIA_DGPU" == true ]]; then
# Fallback: NVIDIA discrete GPU - 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
fi
# ROCm environment configuration
local rocm_config=""
if [[ "$OPENCL_PROVIDER" == "rocm-full" ]]; then
rocm_config='
# ROCm environment (full stack from official Arch repos)
export ROCM_PATH=/opt/rocm
export PATH="$ROCM_PATH/bin:$PATH"
export LD_LIBRARY_PATH="$ROCM_PATH/lib:$ROCM_PATH/lib64:$LD_LIBRARY_PATH"
# Enable RDNA4 support (gfx1201)
export HSA_OVERRIDE_GFX_VERSION=11.0.1
# ROCm OpenCL configuration
export OCL_ICD_VENDORS=/etc/OpenCL/vendors'
fi
# Create main launcher based on GPU method
if [[ "$gpu_launch_method" == "switcheroo" ]]; then
# Davincibox-style launcher using switcherooctl
cat > "$launcher_dir/davinci-resolve" << EOF
#!/bin/bash
# DaVinci Resolve Launcher with workarounds
# Generated by install script on $(date)
# OpenCL Provider: $OPENCL_PROVIDER
# GPU Selection: switcherooctl (davincibox method)
# Fixes applied: patchelf (davincibox method)
# Qt configuration for XWayland
export QT_QPA_PLATFORM=xcb
export QT_AUTO_SCREEN_SCALE_FACTOR=1
${rocm_config}
# Increase file descriptor limit for large projects
ulimit -n 65535 2>/dev/null
# Use switcherooctl for discrete GPU selection (davincibox method)
exec switcherooctl launch /opt/resolve/bin/resolve "\$@"
EOF
else
# Standard launcher with DRI_PRIME/NVIDIA offload
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)
# 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
fi
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
# Create desktop entry
mkdir -p "$HOME/.local/share/applications"
# Determine Exec line based on hybrid status
local exec_line="$HOME/.local/bin/davinci-resolve %U"
cat > "$HOME/.local/share/applications/davinci-resolve.desktop" << EOF
[Desktop Entry]
Version=1.0
Type=Application
Name=DaVinci Resolve
Comment=Professional video editing
Exec=$exec_line
Icon=DV_Resolve
Terminal=false
Categories=AudioVideo;Video;
StartupWMClass=resolve
EOF
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"
echo ""
info "Hybrid GPU detected - launcher configured to use discrete GPU"
if [[ "$gpu_launch_method" == "switcheroo" ]]; then
echo " Using: switcherooctl launch (davincibox method)"
elif [[ "$SCAN_HAS_AMD_DGPU" == true ]]; then
echo " Using: DRI_PRIME=1 (AMD discrete)"
elif [[ "$SCAN_HAS_NVIDIA_DGPU" == true ]]; then
echo " Using: __NV_PRIME_RENDER_OFFLOAD=1 (NVIDIA discrete)"
fi
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:"
echo ""
cat << 'EOF'
windowrulev2 = tag +drpopup, class:^(resolve)$, floating:1
windowrulev2 = stayfocused, tag:drpopup
windowrulev2 = noborder, tag:drpopup
windowrulev2 = opaque, 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)"
cat >> "$hypr_conf" << 'EOF'
# DaVinci Resolve - Fix floating dialogs
windowrulev2 = tag +drpopup, class:^(resolve)$, floating:1
windowrulev2 = stayfocused, tag:drpopup
windowrulev2 = bordersize 0, tag:drpopup
windowrulev2 = noborder, tag:drpopup
windowrulev2 = noshadow, tag:drpopup
windowrulev2 = rounding 0, tag:drpopup
windowrulev2 = opaque, tag:drpopup
EOF
success "Hyprland rules added."
info "Reload with: hyprctl reload"
}
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 " Fixes applied: patchelf (davincibox method), OpenCL decoder disable"
echo ""
if [[ "$OPENCL_PROVIDER" == "rocm-full" ]]; then
echo " ROCm tools:"
echo " rocminfo # Show ROCm GPU info"
echo " rocm-smi # ROCm System Management Interface"
echo " clinfo --list # Check OpenCL platforms"
else
echo " Troubleshooting:"
echo " clinfo --list # Check OpenCL"
fi
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 " After Resolve updates, re-run this script or manually:"
echo " # Re-apply patchelf fix to new binaries"
echo " for bin in /opt/resolve/bin/*; do"
echo " sudo patchelf --add-needed libglib-2.0.so.0 \"\$bin\" 2>/dev/null"
echo " done"
echo ""
if [[ "$SCAN_IS_RDNA4" == true ]]; then
echo " RDNA4 Note:"
echo " If Resolve doesn't detect GPU, try adjusting HSA_OVERRIDE_GFX_VERSION"
echo " in ~/.local/bin/davinci-resolve (currently set to 11.0.1)"
echo " Common values: 11.0.0 (gfx1100), 11.0.1 (gfx1201)"
echo ""
fi
echo "============================================================"
}
# =============================================================================
# MAIN
# =============================================================================
main() {
echo ""
echo "============================================================"
echo " DaVinci Resolve Installer v3.0"
echo " Arch Linux + AMD GPU (RDNA4) + Hyprland"
echo " With Davincibox-style fixes (patchelf, decoder disable)"
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
# Configure user groups for GPU access
configure_user_groups
# Install
install_pacman_packages
install_aur_packages
install_davinci_resolve
apply_patchelf_fix
disable_opencl_decoders
setup_studio_usb_dongle
create_launcher
configure_hyprland
create_conversion_script
install_diagnostics
print_summary
}
main "$@"