Refactor VAAPI passthrough to external script
Some checks failed
Bump build.func Revision / bump-revision (push) Has been cancelled

Replaces the inlined VAAPI passthrough logic in misc/build.func with calls to an external passthrough.func script, streamlining and centralizing hardware passthrough handling. Adds a new misc/passthrough.func file and introduces a hwaccel_setup_in_ct helper in misc/tools.func for hardware acceleration setup inside containers.
This commit is contained in:
CanbiZ 2025-09-22 13:17:20 +02:00
parent 1f8a76e8e2
commit 8aae603267
3 changed files with 81 additions and 314 deletions

View File

@ -2199,320 +2199,10 @@ lxc.mount.entry: /dev/ttyACM1 dev/ttyACM1 none bind,optional,create=
EOF EOF
fi fi
# VAAPI passthrough for privileged containers or known apps source <(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/passthrough.func)
VAAPI_APPS=( usb_handle_passthrough "$CTID" "$CT_TYPE"
"immich" "Channels" "Emby" "ErsatzTV" "Frigate" "Jellyfin" vaapi_handle_passthrough "$CTID" "$CT_TYPE" "$APP"
"Plex" "Scrypted" "Tdarr" "Unmanic" "Ollama" "FileFlows" nvidia_handle_passthrough "$CTID" "$CT_TYPE" "$APP"
"Open WebUI" "Debian" "Tunarr"
)
is_vaapi_app=false
for vaapi_app in "${VAAPI_APPS[@]}"; do
if [[ "$APP" == "$vaapi_app" ]]; then
is_vaapi_app=true
break
fi
done
if [[ "$CT_TYPE" == "0" || "$is_vaapi_app" == "true" ]]; then
# Standard: dont include fb0 unless explicitly wanted
vaapi_select_and_apply "$CTID" "$CT_TYPE" || msg_warn "VAAPI setup skipped/partial."
fi
# --- VAAPI: helper to resolve GID dynamically
_vaapi_gid() {
local g="$1" gid
gid="$(getent group "$g" | cut -d: -f3)"
if [[ -z "$gid" ]]; then
case "$g" in
video) echo 44 ;; # default fallback
render) echo 104 ;; # default fallback
*) echo 44 ;;
esac
else
echo "$gid"
fi
}
# --- VAAPI: detect devices, dedupe, pretty labels
_vaapi_pairs() {
local seen=() by real id idx card pci pci_info name
shopt -s nullglob
for by in /dev/dri/by-path/*-render /dev/dri/renderD*; do
[[ -e "$by" ]] || continue
real="$(readlink -f "$by" || true)"
[[ -e "$real" ]] || continue
id="$(basename "$real")"
if [[ " ${seen[*]} " == *" $id "* ]]; then
continue
fi
seen+=("$id")
idx="${id#renderD}"
if [[ "$idx" =~ ^[0-9]+$ ]]; then
idx=$((idx - 128))
else
idx=0
fi
card="/dev/dri/card${idx}"
[[ -e "$card" ]] || card=""
if [[ "$by" == *"/by-path/"* ]]; then
pci="$(basename "$by" | sed -E 's/^pci-([0-9a-fA-F:.]+)-render/\1/')"
pci_info="$(lspci -nn 2>/dev/null | grep -i "${pci#0000:}" || true)"
name="${pci_info#*: }"
[[ -z "$name" ]] && name="GPU ${pci}"
else
name="DRM $(basename "$real")"
fi
label="$(basename "$real")"
[[ -n "$card" ]] && label+=" + $(basename "$card")"
label+=" ${name}"
printf "%s:%s\t%s\n" "$real" "$card" "$label"
done
shopt -u nullglob
}
# --- VAAPI: whiptail dimension helper
_whiptail_dims() {
local n="$1" L="$2"
local maxW=$((L + 8))
((maxW < 70)) && maxW=70
((maxW > 100)) && maxW=100
local H=$((10 + n * 2))
((H > 22)) && H=22
echo "$H $maxW"
}
# --- VAAPI: main selector and config writer
vaapi_select_and_apply() {
local CTID="$1" CTTYPE="$2"
local LXC_CONFIG="/etc/pve/lxc/${CTID}.conf"
local pairs=() items=() maxlen=0 n h w
mapfile -t pairs < <(_vaapi_pairs)
if ((${#pairs[@]} == 0)); then
msg_warn "No VAAPI devices detected skipping passthrough."
return 0
fi
for p in "${pairs[@]}"; do
local devs="${p%%$'\t'*}"
local label="${p#*$'\t'}"
items+=("$devs" "$label" "OFF")
((${#label} > maxlen)) && maxlen=${#label}
done
n=$((${#items[@]} / 3))
read -r h w < <(_whiptail_dims "$n" "$maxlen")
if [[ "$CTTYPE" == "0" ]]; then
whiptail --title "VAAPI passthrough" --msgbox "\
VAAPI passthrough will be enabled.
• Privileged CT: full DRM access
• You may need to install drivers inside the container
(e.g. intel-media-driver, vainfo)." 12 "$w"
else
whiptail --title "VAAPI passthrough (unprivileged)" --msgbox "\
Unprivileged CT: VAAPI may be limited.
If it fails, consider using a privileged container.
You may still need drivers inside the CT." 12 "$w"
fi
local SELECTED
SELECTED="$(
whiptail --title "VAAPI Device Selection" \
--checklist "Select GPU / VAAPI device(s) to passthrough:" "$h" "$w" "$((n > 6 ? 6 : n))" \
"${items[@]}" 3>&1 1>&2 2>&3
)" || {
msg_warn "VAAPI selection cancelled."
return 0
}
[[ -z "$SELECTED" ]] && {
msg_warn "No devices selected skipping passthrough."
return 0
}
local DID_MOUNT_DRI=0 idx=0
for dev in $SELECTED; do
dev="${dev%\"}"
dev="${dev#\"}"
IFS=":" read -r path card <<<"$dev"
for d in "$path" "$card"; do
[[ -n "$d" && -e "$d" ]] || continue
if [[ "$CTTYPE" == "0" ]]; then
if [[ "$DID_MOUNT_DRI" -eq 0 && -d /dev/dri ]]; then
echo "lxc.mount.entry: /dev/dri /dev/dri none bind,optional,create=dir" >>"$LXC_CONFIG"
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
echo "lxc.cgroup2.devices.allow: c $mm rwm" >>"$LXC_CONFIG"
echo "lxc.mount.entry: $d $d none bind,optional,create=file" >>"$LXC_CONFIG"
else
msg_warn "Could not stat $d skipping."
fi
else
local gid
if [[ "$d" =~ renderD ]]; then
gid="$(_vaapi_gid render)"
else
gid="$(_vaapi_gid video)"
fi
echo "dev${idx}: $d,gid=${gid}" >>"$LXC_CONFIG"
idx=$((idx + 1))
fi
done
done
# Fallback if card0/card1 flip causes missing nodes
if [[ "$CTTYPE" == "0" ]]; then
cat <<'EOF' >>"$LXC_CONFIG"
# VAAPI fallback: bind /dev/dri if specific nodes are missing
lxc.mount.entry: /dev/dri /dev/dri none bind,optional,create=dir
lxc.cgroup2.devices.allow: c 226:* rwm
EOF
fi
}
# if [[ "$CT_TYPE" == "0" || "$is_vaapi_app" == "true" ]]; then
# VAAPI_DEVICES=()
# SINGLE_VAAPI_DEVICE=""
# seen_ids=()
# for bypath in /dev/dri/by-path/*-render /dev/dri/renderD*; do
# [[ -e "$bypath" ]] || continue
# dev_render=$(readlink -f "$bypath") || continue
# id=$(basename "$dev_render")
# [[ " ${seen_ids[*]} " == *" $id "* ]] && continue
# seen_ids+=("$id")
# card_index="${id#renderD}"
# card="/dev/dri/card${card_index}"
# combo_devices=("$dev_render")
# if [[ "${#combo_devices[@]}" -eq 1 && -e /dev/dri/card0 ]]; then
# combo_devices+=("/dev/dri/card0")
# fi
# #echo "combo_devices=${combo_devices[*]}"
# pci_addr=$(basename "$bypath" | cut -d- -f1 --complement | sed 's/-render//' || true)
# pci_info=$(lspci -nn | grep "${pci_addr#0000:}" || true)
# name="${pci_info#*: }"
# [[ -z "$name" ]] && name="Unknown GPU ($pci_addr)"
# label="$(basename "$dev_render")"
# [[ -e "$card" ]] && label+=" + $(basename "$card")"
# label+=" $name"
# msg_debug "[VAAPI DEBUG] Adding VAAPI combo: ${combo_devices[*]} ($label)"
# VAAPI_DEVICES+=("$(
# IFS=:
# echo "${combo_devices[*]}"
# )" "$label" "OFF")
# done
# [[ -e /dev/fb0 ]] && VAAPI_DEVICES+=("/dev/fb0" "fb0 - Framebuffer" "OFF")
# GID_VIDEO=$(getent group video | cut -d: -f3)
# GID_RENDER=$(getent group render | cut -d: -f3)
# [[ -z "$GID_VIDEO" ]] && GID_VIDEO=44 && msg_warn "'video' group not found, falling back to GID 44"
# [[ -z "$GID_RENDER" ]] && GID_RENDER=104 && msg_warn "'render' group not found, falling back to GID 104"
# if [[ "${#VAAPI_DEVICES[@]}" -eq 0 ]]; then
# msg_warn "No VAAPI-compatible devices found."
# elif [[ "${#VAAPI_DEVICES[@]}" -eq 3 ]]; then
# #msg_info "Only one VAAPI-compatible device found enabling passthrough."
# IFS=":" read -ra devices <<<"${VAAPI_DEVICES[0]//\"/}"
# IDX=0
# DID_MOUNT_DRI=0
# for d in "${devices[@]}"; do
# if [[ "$CT_TYPE" == "0" ]]; then
# if [[ "$DID_MOUNT_DRI" -eq 0 && -d /dev/dri ]]; then
# echo "lxc.mount.entry: /dev/dri /dev/dri none bind,optional,create=dir" >>"$LXC_CONFIG"
# DID_MOUNT_DRI=1
# fi
# if ! major_minor=$(stat -c '%t:%T' "$d" 2>/dev/null | awk -F: '{ printf "%d:%d", "0x"$1, "0x"$2 }'); then
# msg_warn "Could not stat $d skipping."
# continue
# fi
# echo "lxc.cgroup2.devices.allow: c $major_minor rwm" >>"$LXC_CONFIG"
# echo "lxc.mount.entry: $d $d none bind,optional,create=file" >>"$LXC_CONFIG"
# else
# GID=$([[ "$d" =~ render ]] && echo "$GID_RENDER" || echo "$GID_VIDEO")
# echo "dev${IDX}: $d,gid=${GID}" >>"$LXC_CONFIG"
# IDX=$((IDX + 1))
# fi
# done
# else
# if [[ "$CT_TYPE" == "0" ]]; then
# whiptail --title "VAAPI passthrough" --msgbox "\
# ✅ VAAPI passthrough has been enabled
# GPU hardware acceleration will be available inside the container
# (e.g., for Jellyfin, Plex, Frigate, etc.)
# Note: You may need to install drivers manually inside the container,
# such as 'intel-media-driver', 'libva2', or 'vainfo'." 15 74
# else
# whiptail --title "VAAPI passthrough (limited)" --msgbox "\
# ⚠️ VAAPI passthrough in unprivileged containers may be limited
# Some drivers (e.g., iHD) require privileged access to DRM subsystems.
# If VAAPI fails, consider switching to a privileged container.
# Note: You may need to install drivers manually inside the container,
# such as 'intel-media-driver', 'libva2', or 'vainfo'." 15 74
# fi
# SELECTED_DEVICES=$(whiptail --title "VAAPI Device Selection" \
# --checklist "Select VAAPI device(s) / GPU(s) to passthrough:" 20 100 6 \
# "${VAAPI_DEVICES[@]}" 3>&1 1>&2 2>&3)
# if [[ $? -ne 0 ]]; then
# exit_script
# msg_error "VAAPI passthrough selection cancelled by user."
# fi
# if [[ -n "$SELECTED_DEVICES" ]]; then
# IDX=0
# DID_MOUNT_DRI=0
# for dev in $SELECTED_DEVICES; do
# dev="${dev%\"}"
# dev="${dev#\"}" # strip quotes
# IFS=":" read -ra devices <<<"$dev"
# msg_debug "[VAAPI DEBUG] Autopassthrough for devices: ${devices[*]}"
# for d in "${devices[@]}"; do
# if [[ "$CT_TYPE" == "0" ]]; then
# if [[ "$DID_MOUNT_DRI" -eq 0 && -d /dev/dri ]]; then
# echo "lxc.mount.entry: /dev/dri /dev/dri none bind,optional,create=dir" >>"$LXC_CONFIG"
# DID_MOUNT_DRI=1
# fi
# if ! major_minor=$(stat -c '%t:%T' "$d" 2>/dev/null | awk -F: '{ printf "%d:%d", "0x"$1, "0x"$2 }'); then
# msg_warn "Could not stat $d skipping."
# continue
# fi
# echo "lxc.cgroup2.devices.allow: c $major_minor rwm" >>"$LXC_CONFIG"
# echo "lxc.mount.entry: $d $d none bind,optional,create=file" >>"$LXC_CONFIG"
# else
# GID=$([[ "$d" =~ render ]] && echo "$GID_RENDER" || echo "$GID_VIDEO")
# echo "dev${IDX}: $d,gid=${GID}" >>"$LXC_CONFIG"
# IDX=$((IDX + 1))
# fi
# done
# done
# else
# msg_warn "No VAAPI devices selected passthrough skipped."
# fi
# fi
# fi
# TUN device passthrough # TUN device passthrough
if [ "$ENABLE_TUN" == "yes" ]; then if [ "$ENABLE_TUN" == "yes" ]; then

0
misc/passthrough.func Normal file
View File

View File

@ -2091,3 +2091,80 @@ check_for_gh_release() {
return 1 return 1
fi fi
} }
# ------------------------------------------------------------------------------
# Hardware acceleration setup inside container
# Works with: Debian 12 (bookworm), Debian 13 (trixie), Ubuntu 24.04 (noble)
# Usage: hwaccel_setup_in_ct <CTTYPE 0|1> [--nonfree-intel]
# ------------------------------------------------------------------------------
hwaccel_setup_in_ct() {
local CTTYPE="$1" NONFREE=0
[[ "$2" == "--nonfree-intel" ]] && NONFREE=1
# Detect OS info inside the container
local ID VERSION_CODENAME
if [[ -r /etc/os-release ]]; then
. /etc/os-release
fi
ID="${ID:-debian}"
VERSION_CODENAME="${VERSION_CODENAME:-bookworm}"
msg_info "Setting up hardware acceleration for ${ID^} ($VERSION_CODENAME)"
case "$ID" in
debian | ubuntu)
if ((NONFREE)) && [[ "$VERSION_CODENAME" =~ (trixie|noble) ]]; then
# Debian 13 / Ubuntu 24.04 → non-free Intel driver
cat >/etc/apt/sources.list.d/non-free.sources <<'SRC'
Types: deb deb-src
URIs: http://deb.debian.org/debian
Suites: trixie
Components: non-free non-free-firmware
Types: deb deb-src
URIs: http://deb.debian.org/debian-security
Suites: trixie-security
Components: non-free non-free-firmware
Types: deb deb-src
URIs: http://deb.debian.org/debian
Suites: trixie-updates
Components: non-free non-free-firmware
SRC
$STD apt-get update
$STD apt-get install -y \
intel-media-va-driver-non-free \
ocl-icd-libopencl1 \
mesa-opencl-icd \
mesa-va-drivers \
libvpl2 \
vainfo \
intel-gpu-tools
else
# Debian 12 (bookworm) and fallback for Debian 13/Ubuntu 24.04 without non-free
$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
fi
;;
*)
msg_warn "Unsupported distribution ($ID $VERSION_CODENAME) skipping HW accel setup"
return 0
;;
esac
# Add current user to video/render groups (only for privileged CTs)
if [[ "$CTTYPE" == "0" ]]; then
$STD adduser "$(id -un)" video || true
$STD adduser "$(id -un)" render || true
fi
msg_ok "Hardware acceleration is ready"
}