Refactor GPU passthrough selection and setup logic
Some checks failed
Bump build.func Revision / bump-revision (push) Has been cancelled

Replaces direct USB and GPU passthrough configuration in build.func with a unified select_hw_passthrough function. Refactors passthrough.func to add interactive selection for VAAPI and NVIDIA devices, streamlines device detection, and updates userland installation functions for both VAAPI and NVIDIA. Cleans up and simplifies device mapping and group ID logic.
This commit is contained in:
CanbiZ 2025-09-22 14:27:21 +02:00
parent 7dd84a1c99
commit da1c78e295
2 changed files with 145 additions and 130 deletions

View File

@ -2183,26 +2183,8 @@ build_container() {
LXC_CONFIG="/etc/pve/lxc/${CTID}.conf" LXC_CONFIG="/etc/pve/lxc/${CTID}.conf"
# USB passthrough for privileged LXC (CT_TYPE=0)
if [ "$CT_TYPE" == "0" ]; then
cat <<EOF >>"$LXC_CONFIG"
# USB passthrough
lxc.cgroup2.devices.allow: a
lxc.cap.drop:
lxc.cgroup2.devices.allow: c 188:* rwm
lxc.cgroup2.devices.allow: c 189:* rwm
lxc.mount.entry: /dev/serial/by-id dev/serial/by-id none bind,optional,create=dir
lxc.mount.entry: /dev/ttyUSB0 dev/ttyUSB0 none bind,optional,create=file
lxc.mount.entry: /dev/ttyUSB1 dev/ttyUSB1 none bind,optional,create=file
lxc.mount.entry: /dev/ttyACM0 dev/ttyACM0 none bind,optional,create=file
lxc.mount.entry: /dev/ttyACM1 dev/ttyACM1 none bind,optional,create=file
EOF
fi
source <(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/passthrough.func) source <(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/passthrough.func)
usb_handle_passthrough "$CTID" "$CT_TYPE" select_hw_passthrough "$CTID" "$CT_TYPE" "$APP"
vaapi_select_and_apply "$CTID" "$CT_TYPE"
nvidia_passthrough_to_lxc "$CTID" "$CT_TYPE"
# TUN device passthrough # TUN device passthrough
if [ "$ENABLE_TUN" == "yes" ]; then if [ "$ENABLE_TUN" == "yes" ]; then

View File

@ -15,8 +15,61 @@ _whiptail_dims() {
echo "$H $maxW" echo "$H $maxW"
} }
select_hw_passthrough() {
local CTID="$1" CTTYPE="$2" APP="$3"
local LXC_CONFIG="/etc/pve/lxc/${CTID}.conf"
local choices=()
[[ -d /dev/dri ]] && choices+=("VAAPI" "Intel/AMD GPU via VAAPI" OFF)
compgen -G "/dev/nvidia*" >/dev/null && choices+=("NVIDIA" "NVIDIA GPU passthrough" OFF)
[[ ${#choices[@]} -eq 0 ]] && {
msg_info "No GPU devices detected"
return
}
local HEIGHT WIDTH
HEIGHT=12
WIDTH=70
local SELECTED
SELECTED=$(whiptail --title "GPU Passthrough" \
--checklist "Select GPU passthrough for CT $CTID:" $HEIGHT $WIDTH 2 \
"${choices[@]}" 3>&1 1>&2 2>&3) || return
# export flags for install.sh
for sel in $SELECTED; do
case "$sel" in
"\"VAAPI\"")
export ENABLE_VAAPI=1
vaapi_select_and_apply "$CTID" "$CTTYPE"
;;
"\"NVIDIA\"")
export ENABLE_NVIDIA=1
nvidia_passthrough_to_lxc "$CTID" "$CTTYPE"
;;
esac
done
}
# Apps that benefit from GPU passthrough (VAAPI + NVIDIA) # Apps that benefit from GPU passthrough (VAAPI + NVIDIA)
_GPU_APPS=(immich Channels Emby ErsatzTV Frigate Jellyfin Plex Scrypted Tdarr Unmanic Ollama FileFlows "Open WebUI" Tunarr Debian) # Apps that benefit from GPU passthrough (VAAPI + NVIDIA)
_GPU_APPS=(
immich
Channels
Emby
ErsatzTV
Frigate
Jellyfin
Plex
Scrypted
Tdarr
Unmanic
Ollama
FileFlows
"Open WebUI"
Tunarr
Debian
)
# ------------------------------ USB ------------------------------------------- # ------------------------------ USB -------------------------------------------
@ -45,15 +98,11 @@ EOF
_vaapi_gid() { _vaapi_gid() {
local g="$1" gid local g="$1" gid
gid="$(getent group "$g" | cut -d: -f3)" gid="$(getent group "$g" | cut -d: -f3)"
if [[ -z "$gid" ]]; then case "$g" in
case "$g" in video) echo "${gid:-44}" ;;
video) echo 44 ;; render) echo "${gid:-104}" ;;
render) echo 104 ;; *) echo "${gid:-44}" ;;
*) echo 44 ;; esac
esac
else
echo "$gid"
fi
} }
_vaapi_pairs() { _vaapi_pairs() {
@ -68,11 +117,7 @@ _vaapi_pairs() {
seen+=("$id") seen+=("$id")
idx="${id#renderD}" idx="${id#renderD}"
if [[ "$idx" =~ ^[0-9]+$ ]]; then [[ "$idx" =~ ^[0-9]+$ ]] && idx=$((idx - 128)) || idx=0
idx=$((idx - 128))
else
idx=0
fi
card="/dev/dri/card${idx}" card="/dev/dri/card${idx}"
[[ -e "$card" ]] || card="" [[ -e "$card" ]] || card=""
@ -88,7 +133,6 @@ _vaapi_pairs() {
label="$(basename "$real")" label="$(basename "$real")"
[[ -n "$card" ]] && label+=" + $(basename "$card")" [[ -n "$card" ]] && label+=" + $(basename "$card")"
label+=" ${name}" label+=" ${name}"
printf "%s:%s\t%s\n" "$real" "$card" "$label" printf "%s:%s\t%s\n" "$real" "$card" "$label"
done done
shopt -u nullglob shopt -u nullglob
@ -98,42 +142,30 @@ vaapi_select_and_apply() {
local CTID="$1" CTTYPE="$2" local CTID="$1" CTTYPE="$2"
local LXC_CONFIG="/etc/pve/lxc/${CTID}.conf" local LXC_CONFIG="/etc/pve/lxc/${CTID}.conf"
local pairs=() items=() maxlen=0 n h w
mapfile -t pairs < <(_vaapi_pairs) mapfile -t pairs < <(_vaapi_pairs)
((${#pairs[@]} == 0)) && {
if ((${#pairs[@]} == 0)); then
msg_warn "No VAAPI devices detected skipping." msg_warn "No VAAPI devices detected skipping."
return 0 return
fi }
local items=() maxlen=0
for p in "${pairs[@]}"; do for p in "${pairs[@]}"; do
local devs="${p%%$'\t'*}" local devs="${p%%$'\t'*}" label="${p#*$'\t'}"
local label="${p#*$'\t'}"
items+=("$devs" "$label" "OFF") items+=("$devs" "$label" "OFF")
((${#label} > maxlen)) && maxlen=${#label} ((${#label} > maxlen)) && maxlen=${#label}
done done
n=$((${#items[@]} / 3)) read -r h w < <(_whiptail_dims $((${#items[@]} / 3)) "$maxlen")
read -r h w < <(_whiptail_dims "$n" "$maxlen")
whiptail --title "VAAPI passthrough" --msgbox "\
VAAPI passthrough will be enabled.
Privileged CT = full DRM access
Unprivileged CT = may be limited." 12 "$w"
local SELECTED local SELECTED
SELECTED="$( SELECTED="$(whiptail --title "VAAPI Device Selection" \
whiptail --title "VAAPI Device Selection" \ --checklist "Select VAAPI devices for CT $CTID:" "$h" "$w" 6 \
--checklist "Select GPU / VAAPI device(s) to passthrough:" "$h" "$w" "$((n > 6 ? 6 : n))" \ "${items[@]}" 3>&1 1>&2 2>&3)" || {
"${items[@]}" 3>&1 1>&2 2>&3
)" || {
msg_warn "VAAPI selection cancelled." msg_warn "VAAPI selection cancelled."
return 0 return
} }
[[ -z "$SELECTED" ]] && { [[ -z "$SELECTED" ]] && {
msg_warn "No devices selected skipping." msg_warn "No VAAPI devices selected."
return 0 return
} }
local DID_MOUNT_DRI=0 idx=0 local DID_MOUNT_DRI=0 idx=0
@ -144,109 +176,110 @@ Unprivileged CT = may be limited." 12 "$w"
for d in "$path" "$card"; do for d in "$path" "$card"; do
[[ -n "$d" && -e "$d" ]] || continue [[ -n "$d" && -e "$d" ]] || continue
if [[ "$CTTYPE" == "0" ]]; then if [[ "$CTTYPE" == "0" ]]; then
if [[ "$DID_MOUNT_DRI" -eq 0 && -d /dev/dri ]]; then [[ $DID_MOUNT_DRI -eq 0 && -d /dev/dri ]] && {
echo "lxc.mount.entry: /dev/dri /dev/dri none bind,optional,create=dir" >>"$LXC_CONFIG" echo "lxc.mount.entry: /dev/dri /dev/dri none bind,optional,create=dir" >>"$LXC_CONFIG"
DID_MOUNT_DRI=1 DID_MOUNT_DRI=1
fi }
if mm=$(stat -c '%t:%T' "$d" 2>/dev/null | awk -F: '{printf "%d:%d","0x"$1,"0x"$2}'); then if mm=$(stat -c '%t:%T' "$d" | awk -F: '{printf "%d:%d","0x"$1,"0x"$2}'); then
echo "lxc.cgroup2.devices.allow: c $mm rwm" >>"$LXC_CONFIG" echo "lxc.cgroup2.devices.allow: c $mm rwm" >>"$LXC_CONFIG"
echo "lxc.mount.entry: $d $d none bind,optional,create=file" >>"$LXC_CONFIG" echo "lxc.mount.entry: $d $d none bind,optional,create=file" >>"$LXC_CONFIG"
else
msg_warn "Could not stat $d skipping."
fi fi
else else
local gid gid=$([[ "$d" =~ renderD ]] && _vaapi_gid render || _vaapi_gid video)
if [[ "$d" =~ renderD ]]; then gid="$(_vaapi_gid render)"; else gid="$(_vaapi_gid video)"; fi
echo "dev${idx}: $d,gid=${gid}" >>"$LXC_CONFIG" echo "dev${idx}: $d,gid=${gid}" >>"$LXC_CONFIG"
idx=$((idx + 1)) idx=$((idx + 1))
fi fi
done done
done done
[[ "$CTTYPE" == "0" ]] && cat <<'EOF' >>"$LXC_CONFIG"
# fallback for card0/card1 flip # VAAPI fallback
if [[ "$CTTYPE" == "0" ]]; then
cat <<'EOF' >>"$LXC_CONFIG"
# VAAPI fallback: bind /dev/dri and allow 226:* to survive node flips
lxc.mount.entry: /dev/dri /dev/dri none bind,optional,create=dir lxc.mount.entry: /dev/dri /dev/dri none bind,optional,create=dir
lxc.cgroup2.devices.allow: c 226:* rwm lxc.cgroup2.devices.allow: c 226:* rwm
EOF EOF
fi
}
vaapi_inside_setup() {
local CTID="$1" CTTYPE="$2" APP="$3"
local is_gpu_app=false
for a in "${_GPU_APPS[@]}"; do [[ "$APP" == "$a" ]] && is_gpu_app=true && break; done
[[ "$CTTYPE" == "0" || "$is_gpu_app" == "true" ]] || return 0
msg_info "Installing VAAPI userland inside CT $CTID"
pct exec "$CTID" -- bash -lc '
. /etc/os-release
case "$VERSION_CODENAME" in
trixie|noble)
apt-get update
apt-get install -y intel-media-va-driver-non-free ocl-icd-libopencl1 \
mesa-opencl-icd mesa-va-drivers libvpl2 vainfo intel-gpu-tools
;;
*)
apt-get update
apt-get install -y va-driver-all ocl-icd-libopencl1 \
mesa-opencl-icd mesa-va-drivers vainfo intel-gpu-tools
;;
esac
if [[ "'"$CTTYPE"'" == "0" ]]; then
adduser "$(id -un)" video || true
adduser "$(id -un)" render || true
fi
'
msg_ok "VAAPI setup done in CT $CTID"
} }
# ----------------------------- NVIDIA ----------------------------------------- # ----------------------------- NVIDIA -----------------------------------------
nvidia_passthrough_to_lxc() { nvidia_passthrough_to_lxc() {
local CTID="$1" CTTYPE="${2:-0}" local CTID="$1" CTTYPE="$2"
local LXC_CONFIG="/etc/pve/lxc/${CTID}.conf" local LXC_CONFIG="/etc/pve/lxc/${CTID}.conf"
local found=0 dev mm local found=0
for dev in /dev/nvidia0 /dev/nvidia1 /dev/nvidiactl /dev/nvidia-uvm /dev/nvidia-uvm-tools /dev/nvidia-modeset; do for dev in /dev/nvidia*; do
[[ -e "$dev" ]] || continue [[ -e "$dev" ]] || continue
found=1 found=1
if mm="$(stat -c '%t:%T' "$dev" 2>/dev/null | awk -F: '{printf "%d:%d","0x"$1,"0x"$2}')"; then if mm="$(stat -c '%t:%T' "$dev" | awk -F: '{printf "%d:%d","0x"$1,"0x"$2}')"; then
echo "lxc.cgroup2.devices.allow: c $mm rwm" >>"$LXC_CONFIG" echo "lxc.cgroup2.devices.allow: c $mm rwm" >>"$LXC_CONFIG"
echo "lxc.mount.entry: $dev $dev none bind,optional,create=file" >>"$LXC_CONFIG" echo "lxc.mount.entry: $dev $dev none bind,optional,create=file" >>"$LXC_CONFIG"
fi fi
done done
((found == 0)) && {
msg_warn "No NVIDIA devices found."
return
}
if [[ "$found" -eq 0 ]]; then [[ -d /dev/dri && "$CTTYPE" == "0" ]] && echo "lxc.mount.entry: /dev/dri /dev/dri none bind,optional,create=dir" >>"$LXC_CONFIG"
msg_warn "No /dev/nvidia* devices found on host; skipping NVIDIA passthrough."
return 0
fi
if [[ -d /dev/dri && "$CTTYPE" == "0" ]]; then
echo "lxc.mount.entry: /dev/dri /dev/dri none bind,optional,create=dir" >>"$LXC_CONFIG"
fi
msg_ok "NVIDIA devices mapped to CT ${CTID}" msg_ok "NVIDIA devices mapped to CT ${CTID}"
} }
nvidia_inside_setup() { install_vaapi_userland_interactive() {
local CTID="$1" CTTYPE="$2" APP="$3" . /etc/os-release
if [[ "$VERSION_CODENAME" == "trixie" ]]; then
read -r -p "${TAB3}Do you need the intel-media-va-driver-non-free driver for HW encoding (Debian 13 only)? <y/N> " prompt
if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then
msg_info "Installing Intel Hardware Acceleration (non-free)"
cat <<'EOF' >/etc/apt/sources.list.d/non-free.sources
Types: deb deb-src
URIs: http://deb.debian.org/debian
Suites: trixie
Components: non-free non-free-firmware
local is_gpu_app=false Types: deb deb-src
for a in "${_GPU_APPS[@]}"; do [[ "$APP" == "$a" ]] && is_gpu_app=true && break; done URIs: http://deb.debian.org/debian-security
[[ "$CTTYPE" == "0" || "$is_gpu_app" == "true" ]] || return 0 Suites: trixie-security
Components: non-free non-free-firmware
compgen -G "/dev/nvidia*" >/dev/null || return 0 Types: deb deb-src
msg_info "Installing NVIDIA userland inside CT $CTID" URIs: http://deb.debian.org/debian
pct exec "$CTID" -- bash -lc ' Suites: trixie-updates
. /etc/os-release Components: non-free non-free-firmware
apt-get update EOF
apt-get install -y nvidia-driver nvidia-utils libnvidia-encode1 libcuda1 $STD apt-get update
if [[ "'"$CTTYPE"'" == "0" ]]; then $STD apt-get install -y \
adduser "$(id -un)" video || true intel-media-va-driver-non-free \
ocl-icd-libopencl1 \
mesa-opencl-icd \
mesa-va-drivers \
libvpl2 \
vainfo \
intel-gpu-tools
msg_ok "Installed Intel Hardware Acceleration (non-free)"
return
fi fi
' fi
msg_ok "NVIDIA setup done in CT $CTID"
msg_info "Installing Intel Hardware Acceleration (open packages)"
$STD apt-get update
$STD apt-get install -y \
va-driver-all \
ocl-icd-libopencl1 \
mesa-opencl-icd \
mesa-va-drivers \
vainfo \
intel-gpu-tools
msg_ok "Installed Intel Hardware Acceleration (open packages)"
}
install_nvidia_userland_interactive() {
msg_info "Installing NVIDIA Userland"
$STD apt-get update
$STD apt-get install -y \
nvidia-driver \
nvidia-utils \
libnvidia-encode1 \
libcuda1 || {
msg_error "Failed to install NVIDIA packages"
return 1
}
msg_ok "Installed NVIDIA Userland"
} }