From 633ca3edeeffa8e02482e2260eb782f4ee9b7334 Mon Sep 17 00:00:00 2001 From: CanbiZ <47820557+MickLesk@users.noreply.github.com> Date: Mon, 29 Sep 2025 10:48:25 +0200 Subject: [PATCH] Refactor GPU passthrough logic in build.func Simplifies and streamlines GPU passthrough configuration for LXC containers, consolidating device detection, selection, and userland package installation. Reduces code duplication, improves readability, and adds direct verification steps for VAAPI and NVIDIA support after installation. --- misc/build.func | 270 +++++++++++++----------------------------------- 1 file changed, 73 insertions(+), 197 deletions(-) diff --git a/misc/build.func b/misc/build.func index cd31f9a5..69fe74b5 100644 --- a/misc/build.func +++ b/misc/build.func @@ -2170,16 +2170,13 @@ build_container() { # Get device GID dynamically get_device_gid() { local group="$1" - local gid - gid=$(getent group "$group" 2>/dev/null | cut -d: -f3) - if [[ -z "$gid" ]]; then - case "$group" in - video) gid=44 ;; - render) gid=104 ;; - *) gid=44 ;; - esac - fi - echo "$gid" + gid=$(getent group "$group" | cut -d: -f3) + [[ -n "$gid" ]] && echo "$gid" && return + case "$group" in + video) echo 44 ;; + render) echo 104 ;; + *) echo 44 ;; + esac } # Check if app needs GPU @@ -2192,24 +2189,18 @@ build_container() { } # Detect available GPU devices + is_gpu_app() { + local app="${1,,}" + for gpu in "${GPU_APPS[@]}"; do + [[ "$gpu" == "$app" ]] && return 0 + done + return 1 + } + detect_gpu_devices() { - VAAPI_DEVICES=() - NVIDIA_DEVICES=() - - # VAAPI / Intel / AMD - for device in /dev/dri/renderD* /dev/dri/card*; do - [[ -e "$device" ]] || continue - VAAPI_DEVICES+=("$device") - done - - # NVIDIA - for device in /dev/nvidia*; do - [[ -e "$device" ]] || continue - NVIDIA_DEVICES+=("$device") - done - - msg_debug "Detected VAAPI devices: ${VAAPI_DEVICES[*]:-(none)}" - msg_debug "Detected NVIDIA devices: ${NVIDIA_DEVICES[*]:-(none)}" + VAAPI_DEVICES=(); NVIDIA_DEVICES=() + for d in /dev/dri/renderD* /dev/dri/card*; do [[ -e $d ]] && VAAPI_DEVICES+=("$d"); done + for d in /dev/nvidia*; do [[ -e $d ]] && NVIDIA_DEVICES+=("$d"); done } # Configure USB passthrough for privileged containers @@ -2233,142 +2224,64 @@ lxc.mount.entry: /dev/ttyACM1 dev/ttyACM1 none bind,optional,create= EOF msg_ok "USB passthrough configured" } - - # Configure VAAPI device - configure_vaapi_device() { - local device="$1" - local dev_index="$2" - + configure_vaapi_device() { + local dev="$1" idx="$2" if [[ "$CT_TYPE" == "0" ]]; then - # Privileged container - local major minor - major=$(stat -c '%t' "$device") - minor=$(stat -c '%T' "$device") - major=$((0x$major)) - minor=$((0x$minor)) - echo "lxc.cgroup2.devices.allow: c $major:$minor rwm" >>"$LXC_CONFIG" - echo "lxc.mount.entry: $device dev/$(basename "$device") none bind,optional,create=file" >>"$LXC_CONFIG" + major=$(stat -c '%t' "$dev"); minor=$(stat -c '%T' "$dev") + echo "lxc.cgroup2.devices.allow: c $((0x$major)):$((0x$minor)) rwm" >>"$LXC_CONFIG" + echo "lxc.mount.entry: $dev dev/$(basename "$dev") none bind,optional,create=file" >>"$LXC_CONFIG" else - # Unprivileged container - local gid - if [[ "$device" =~ renderD ]]; then - gid=$(get_device_gid "render") - else - gid=$(get_device_gid "video") - fi - echo "dev${dev_index}: $device,gid=$gid" >>"$LXC_CONFIG" + [[ "$dev" =~ renderD ]] && gid=$(get_device_gid "render") || gid=$(get_device_gid "video") + echo "dev$idx: $dev,gid=$gid" >>"$LXC_CONFIG" fi } - # Configure NVIDIA devices configure_nvidia_devices() { - for device in "${NVIDIA_DEVICES[@]}"; do + for dev in "${NVIDIA_DEVICES[@]}"; do if [[ "$CT_TYPE" == "0" ]]; then - local major minor - major=$(stat -c '%t' "$device") - minor=$(stat -c '%T' "$device") - major=$((0x$major)) - minor=$((0x$minor)) - echo "lxc.cgroup2.devices.allow: c $major:$minor rwm" >>"$LXC_CONFIG" - echo "lxc.mount.entry: $device dev/$(basename "$device") none bind,optional,create=file" >>"$LXC_CONFIG" + major=$(stat -c '%t' "$dev"); minor=$(stat -c '%T' "$dev") + echo "lxc.cgroup2.devices.allow: c $((0x$major)):$((0x$minor)) rwm" >>"$LXC_CONFIG" + echo "lxc.mount.entry: $dev dev/$(basename "$dev") none bind,optional,create=file" >>"$LXC_CONFIG" else - msg_warn "NVIDIA passthrough to unprivileged container may require additional configuration" + msg_warn "NVIDIA passthrough on unprivileged CT may fail" fi done - - if [[ -d /dev/dri ]] && [[ "$CT_TYPE" == "0" ]]; then - echo "lxc.mount.entry: /dev/dri dev/dri none bind,optional,create=dir" >>"$LXC_CONFIG" - fi + [[ -d /dev/dri && "$CT_TYPE" == "0" ]] && echo "lxc.mount.entry: /dev/dri dev/dri none bind,optional,create=dir" >>"$LXC_CONFIG" } - # Main GPU configuration logic configure_gpu_passthrough() { detect_gpu_devices + local should=false + if [[ "$CT_TYPE" == "0" ]] || is_gpu_app "$APP"; then should=true; fi + [[ "$should" == "false" ]] && return - # Check if we should configure GPU - local should_configure=false - if [[ "$CT_TYPE" == "0" ]] || is_gpu_app "$APP"; then - should_configure=true + if [[ ${#VAAPI_DEVICES[@]} -eq 0 && ${#NVIDIA_DEVICES[@]} -eq 0 ]]; then + msg_info "No GPU devices found"; return fi - if [[ "$should_configure" == "false" ]]; then - return 0 - fi + local choices=() selected=() + [[ ${#VAAPI_DEVICES[@]} -gt 0 ]] && choices+=("VAAPI" "Intel/AMD GPU" "OFF") + [[ ${#NVIDIA_DEVICES[@]} -gt 0 ]] && choices+=("NVIDIA" "NVIDIA GPU" "OFF") - # No GPU devices available - if [[ ${#VAAPI_DEVICES[@]} -eq 0 ]] && [[ ${#NVIDIA_DEVICES[@]} -eq 0 ]]; then - msg_info "No GPU devices detected on host" - return 0 - fi - - # Build selection options - local choices=() - local SELECTED_GPUS=() - - if [[ ${#VAAPI_DEVICES[@]} -gt 0 ]]; then - choices+=("VAAPI" "Intel/AMD GPU (${#VAAPI_DEVICES[@]} devices)" "OFF") - fi - - if [[ ${#NVIDIA_DEVICES[@]} -gt 0 ]]; then - choices+=("NVIDIA" "NVIDIA GPU (${#NVIDIA_DEVICES[@]} devices)" "OFF") - fi - - # Auto-select if only one type available if [[ ${#choices[@]} -eq 3 ]]; then - SELECTED_GPUS=("${choices[0]}") - msg_info "Auto-configuring ${choices[0]} GPU passthrough" - elif [[ ${#choices[@]} -gt 3 ]]; then - # Show selection dialog - local selected - selected=$(whiptail --title "GPU Passthrough Selection" \ - --checklist "Multiple GPU types detected. Select which to pass through:" \ - 12 60 $((${#choices[@]} / 3)) \ - "${choices[@]}" 3>&1 1>&2 2>&3) || { - msg_info "GPU passthrough skipped" - return 0 - } - - for item in $selected; do - SELECTED_GPUS+=("${item//\"/}") - done + selected=("VAAPI") + elif [[ ${#choices[@]} -eq 6 ]]; then + read -rp "Multiple GPUs found (VAAPI/NVIDIA). Which passthrough? " sel + [[ "$sel" =~ VAAPI|vaapi ]] && selected=("VAAPI") + [[ "$sel" =~ NVIDIA|nvidia ]] && selected=("NVIDIA") fi - # Apply configuration for selected GPUs - local dev_index=0 - for gpu_type in "${SELECTED_GPUS[@]}"; do - case "$gpu_type" in - VAAPI) - msg_info "Configuring VAAPI passthrough (${#VAAPI_DEVICES[@]} devices)" - for device in "${VAAPI_DEVICES[@]}"; do - configure_vaapi_device "$device" "$dev_index" - : "${dev_index:=0}" - dev_index=$((dev_index + 1)) - done - if [[ "$CT_TYPE" == "0" ]] && [[ -d /dev/dri ]]; then - echo "lxc.mount.entry: /dev/dri dev/dri none bind,optional,create=dir" >>"$LXC_CONFIG" - fi - export ENABLE_VAAPI=1 - ;; - NVIDIA) - msg_info "Configuring NVIDIA passthrough" - configure_nvidia_devices - export ENABLE_NVIDIA=1 - ;; + local idx=0 + for s in "${selected[@]}"; do + case "$s" in + VAAPI) for d in "${VAAPI_DEVICES[@]}"; do configure_vaapi_device "$d" "$idx"; idx=$((idx+1)); done; export ENABLE_VAAPI=1 ;; + NVIDIA) configure_nvidia_devices; export ENABLE_NVIDIA=1 ;; esac done - - [[ ${#SELECTED_GPUS[@]} -gt 0 ]] && msg_ok "GPU passthrough configured" - + [[ ${#selected[@]} -gt 0 ]] && msg_ok "GPU passthrough configured" } - # ------------------------------------------------------------------------------ - # Apply all hardware passthrough configurations - # ------------------------------------------------------------------------------ - - # USB passthrough (automatic for privileged) configure_usb_passthrough - - # GPU passthrough (based on container type and app) configure_gpu_passthrough # TUN device passthrough @@ -2438,67 +2351,30 @@ EOF fi fi - # # Install GPU userland packages - # install_gpu_userland() { - # local gpu_type="$1" + install_gpu_userland() { + local gpu="$1" + if [[ "$var_os" == "alpine" ]]; then + case "$gpu" in + VAAPI) pct exec "$CTID" -- apk add mesa-dri-gallium mesa-va-gallium intel-media-driver libva-utils ;; + NVIDIA) msg_warn "NVIDIA drivers not in Alpine repos" ;; + esac + else + case "$gpu" in + VAAPI) pct exec "$CTID" -- bash -c "apt-get update && apt-get install -y intel-media-va-driver-non-free mesa-va-drivers vainfo" ;; + NVIDIA) pct exec "$CTID" -- bash -c "apt-get update && apt-get install -y nvidia-driver nvidia-utils libnvidia-encode1" ;; + esac + fi + } - # if [ "$var_os" == "alpine" ]; then - # case "$gpu_type" in - # VAAPI) - # msg_info "Installing VAAPI packages in Alpine container" - # pct exec "$CTID" -- ash -c ' - # apk add --no-cache \ - # mesa-dri-gallium \ - # mesa-va-gallium \ - # intel-media-driver \ - # libva-utils >/dev/null 2>&1 - # ' || msg_warn "Some VAAPI packages may not be available in Alpine" - # ;; - # NVIDIA) - # msg_warn "NVIDIA drivers are not readily available in Alpine Linux" - # ;; - # esac - # else - # case "$gpu_type" in - # VAAPI) - # msg_info "Installing VAAPI userland packages" - # pct exec "$CTID" -- bash -c ' - # . /etc/os-release || true - # if [[ "${VERSION_CODENAME:-}" == "trixie" ]]; then - # cat >/etc/apt/sources.list.d/non-free.sources </dev/null 2>&1 - # DEBIAN_FRONTEND=noninteractive apt-get install -y \ - # intel-media-va-driver-non-free \ - # mesa-va-drivers \ - # libvpl2 \ - # vainfo \ - # ocl-icd-libopencl1 \ - # mesa-opencl-icd \ - # intel-gpu-tools >/dev/null 2>&1 - # ' && msg_ok "VAAPI userland installed" || msg_warn "Some VAAPI packages failed to install" - # ;; - # NVIDIA) - # msg_info "Installing NVIDIA userland packages" - # pct exec "$CTID" -- bash -c ' - # apt-get update >/dev/null 2>&1 - # DEBIAN_FRONTEND=noninteractive apt-get install -y \ - # nvidia-driver \ - # nvidia-utils \ - # libnvidia-encode1 \ - # libcuda1 >/dev/null 2>&1 - # ' && msg_ok "NVIDIA userland installed" || msg_warn "Some NVIDIA packages failed to install" - # ;; - # esac - # fi - # } - - # Customize container + if [[ "${ENABLE_VAAPI:-0}" == "1" ]]; then + install_gpu_userland "VAAPI" + pct exec "$CTID" -- bash -c "chgrp video /dev/dri && chmod 755 /dev/dri && chmod 660 /dev/dri/*" + pct exec "$CTID" -- vainfo >/dev/null 2>&1 && msg_ok "VAAPI verified" || msg_warn "VAAPI failed" + fi + if [[ "${ENABLE_NVIDIA:-0}" == "1" ]]; then + install_gpu_userland "NVIDIA" + pct exec "$CTID" -- nvidia-smi >/dev/null 2>&1 && msg_ok "NVIDIA verified" || msg_warn "NVIDIA failed" + fi msg_info "Customizing LXC Container" # # Install GPU userland if configured