#!/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 "$@"