fix(installer): improve GPU detection to avoid false positives (#254)

* fix(installer): improve GPU detection to avoid false positives

- Filter out software renderers (llvmpipe, swiftshader, lavapipe, etc.)
  when checking Vulkan compatibility - these are CPU implementations
  and should not affect hardware GPU detection
- Skip Vulkan compatibility check for NVIDIA GPUs since they use CUDA
  instead of Vulkan for acceleration
- Reorder backend priority: CUDA > Vulkan > CPU
- Only show incompatible GPU warning for actual Vulkan-based GPUs
  (AMD/Intel) that lack VK_KHR_16bit_storage support

Fixes issue where RTX 5080 + llvmpipe combination was incorrectly
flagged as incompatible due to llvmpipe lacking 16-bit storage support.

* fix(installer): recommend GPU even without dev libraries installed

The installer installs dev libraries (libvulkan-dev, glslc) in
install_system_dependencies(), which runs AFTER the backend selection.
So we should recommend GPU if there's a compatible GPU regardless
of whether dev libraries are currently installed.

Changes:
- NVIDIA GPU detected → recommend CUDA (even without nvcc)
- Vulkan-compatible GPU → recommend Vulkan (even without libvulkan-dev)
- Only fall back to CPU if no compatible GPU detected or GPU is
  genuinely incompatible (old Intel Gen7)
This commit is contained in:
Jatin K Malik
2026-02-22 21:03:54 -08:00
committed by GitHub
parent 58b635b8b9
commit 8d898de5e8
+103 -44
View File
@@ -483,8 +483,12 @@ detect_vulkan() {
# These GPUs will fail with "device does not support 16-bit storage" error
# Affected: Intel Gen7 and older (Ivy Bridge, Haswell, Sandy Bridge)
# See: https://github.com/jatinkrmalik/vocalinux/issues/238
#
# IMPORTANT: This check filters out software renderers (llvmpipe, etc.) and only
# evaluates real hardware GPUs. Modern AMD, Intel (Gen8+), and NVIDIA GPUs all
# support VK_KHR_16bit_storage, so this mainly catches very old Intel Gen7 GPUs.
check_vulkan_gpu_compatibility() {
# List of known incompatible GPU patterns
# List of known incompatible GPU patterns (old Intel Gen7 and older)
local INCOMPATIBLE_PATTERNS=(
"Ivy Bridge"
"Haswell"
@@ -500,55 +504,95 @@ check_vulkan_gpu_compatibility() {
"SNB"
)
# Software renderers and virtual devices to skip (not real hardware GPUs)
# These are CPU-based implementations that shouldn't affect compatibility detection
local SOFTWARE_RENDERER_PATTERNS=(
"llvmpipe"
"swiftshader"
"lavapipe"
"zink"
"virtio"
"venus"
)
# Check if vulkaninfo is available
if ! command -v vulkaninfo >/dev/null 2>&1; then
echo "unknown:vulkaninfo not available"
return 1
fi
# Get all device names from vulkaninfo
local DEVICE_NAMES_RAW
DEVICE_NAMES_RAW=$(vulkaninfo --summary 2>/dev/null | awk -F'=' '/deviceName/ {gsub(/^[ \t]+|[ \t]+$/, "", $2); if ($2 != "") print $2}')
local DEVICE_NAMES_LABEL=""
# Separate hardware GPUs from software renderers
local HARDWARE_GPUS=""
local HARDWARE_GPU_COUNT=0
while IFS= read -r device_name; do
[ -z "$device_name" ] && continue
if [ -n "$DEVICE_NAMES_LABEL" ]; then
DEVICE_NAMES_LABEL="${DEVICE_NAMES_LABEL}, ${device_name}"
else
DEVICE_NAMES_LABEL="$device_name"
local is_software=false
for pattern in "${SOFTWARE_RENDERER_PATTERNS[@]}"; do
if echo "$device_name" | grep -iq "$pattern"; then
is_software=true
break
fi
done
if [ "$is_software" = false ]; then
if [ -n "$HARDWARE_GPUS" ]; then
HARDWARE_GPUS="${HARDWARE_GPUS}, ${device_name}"
else
HARDWARE_GPUS="$device_name"
fi
((HARDWARE_GPU_COUNT++))
fi
done <<< "$DEVICE_NAMES_RAW"
# If no hardware GPUs found, we can't determine compatibility
if [ -z "$HARDWARE_GPUS" ]; then
echo "unknown:No hardware GPU found (only software renderers)"
return 1
fi
# Get Vulkan features and check for VK_KHR_16bit_storage
# Modern GPUs (AMD, Intel Gen8+, NVIDIA) all support this extension
local FEATURES_OUTPUT
FEATURES_OUTPUT=$(vulkaninfo --features 2>/dev/null)
if [ -n "$FEATURES_OUTPUT" ]; then
if echo "$FEATURES_OUTPUT" | grep -Eq "VK_KHR_16bit_storage|storageBuffer16BitAccess[[:space:]]*=[[:space:]]*true|uniformAndStorageBuffer16BitAccess[[:space:]]*=[[:space:]]*true|storagePushConstant16[[:space:]]*=[[:space:]]*true"; then
if [ -z "$DEVICE_NAMES_LABEL" ]; then
DEVICE_NAMES_LABEL="Vulkan GPU (VK_KHR_16bit_storage)"
fi
echo "compatible:${DEVICE_NAMES_LABEL}"
# Check for VK_KHR_16bit_storage extension or equivalent features
if echo "$FEATURES_OUTPUT" | grep -q "VK_KHR_16bit_storage"; then
echo "compatible:${HARDWARE_GPUS}"
return 0
fi
if [ -z "$DEVICE_NAMES_LABEL" ]; then
DEVICE_NAMES_LABEL="Vulkan GPU"
# Alternative: check for 16-bit storage features directly
if echo "$FEATURES_OUTPUT" | grep -Eq "storageBuffer16BitAccess[[:space:]]*=[[:space:]]*true|uniformAndStorageBuffer16BitAccess[[:space:]]*=[[:space:]]*true"; then
echo "compatible:${HARDWARE_GPUS}"
return 0
fi
echo "incompatible:${DEVICE_NAMES_LABEL} (missing VK_KHR_16bit_storage)"
return 1
fi
if [ -z "$DEVICE_NAMES_RAW" ]; then
echo "unknown:Could not detect GPU name"
return 1
fi
# If Vulkan features check didn't confirm support, check against known incompatible patterns
# This handles systems where vulkaninfo --features doesn't show the extension
local INCOMPATIBLE_GPUS=""
local HAS_COMPATIBLE_GPU=false
local INCOMPATIBLE_LABEL=""
while IFS= read -r device_name; do
[ -z "$device_name" ] && continue
# Skip software renderers
local is_software=false
for pattern in "${SOFTWARE_RENDERER_PATTERNS[@]}"; do
if echo "$device_name" | grep -iq "$pattern"; then
is_software=true
break
fi
done
[ "$is_software" = true ] && continue
# Check against known incompatible patterns
local is_incompatible=false
for pattern in "${INCOMPATIBLE_PATTERNS[@]}"; do
if echo "$device_name" | grep -iq "$pattern"; then
@@ -558,23 +602,24 @@ check_vulkan_gpu_compatibility() {
done
if [ "$is_incompatible" = true ]; then
if [ -n "$INCOMPATIBLE_LABEL" ]; then
INCOMPATIBLE_LABEL="${INCOMPATIBLE_LABEL}, ${device_name}"
if [ -n "$INCOMPATIBLE_GPUS" ]; then
INCOMPATIBLE_GPUS="${INCOMPATIBLE_GPUS}, ${device_name}"
else
INCOMPATIBLE_LABEL="$device_name"
INCOMPATIBLE_GPUS="$device_name"
fi
else
# GPU doesn't match known incompatible patterns - assume compatible
HAS_COMPATIBLE_GPU=true
fi
done <<< "$DEVICE_NAMES_RAW"
if [ "$HAS_COMPATIBLE_GPU" = true ]; then
echo "compatible:${DEVICE_NAMES_LABEL}"
echo "compatible:${HARDWARE_GPUS}"
return 0
fi
if [ -n "$INCOMPATIBLE_LABEL" ]; then
echo "incompatible:${INCOMPATIBLE_LABEL}"
if [ -n "$INCOMPATIBLE_GPUS" ]; then
echo "incompatible:${INCOMPATIBLE_GPUS}"
return 1
fi
@@ -600,41 +645,55 @@ detect_whispercpp_backends() {
fi
# Check Vulkan GPU compatibility (Gen7 and older Intel GPUs lack 16-bit storage support)
# Skip this check for NVIDIA GPUs since they use CUDA, not Vulkan
local VULKAN_COMPATIBLE="unknown"
local VULKAN_COMPAT_REASON=""
if [[ "$HAS_VULKAN" == "yes" ]]; then
if [[ "$HAS_VULKAN" == "yes" && "$HAS_NVIDIA_GPU" != "yes" ]]; then
local COMPAT_RESULT
COMPAT_RESULT=$(check_vulkan_gpu_compatibility)
VULKAN_COMPATIBLE=$(echo "$COMPAT_RESULT" | cut -d':' -f1)
VULKAN_COMPAT_REASON=$(echo "$COMPAT_RESULT" | cut -d':' -f2-)
elif [[ "$HAS_NVIDIA_GPU" == "yes" ]]; then
# NVIDIA GPUs use CUDA, so Vulkan compatibility is irrelevant
VULKAN_COMPATIBLE="not_applicable"
VULKAN_COMPAT_REASON="NVIDIA GPU uses CUDA"
fi
# Determine recommendation
# Determine recommendation (Priority: CUDA > Vulkan > CPU)
# IMPORTANT: The installer WILL install dev libraries (libvulkan-dev, glslc, CUDA) later,
# so we recommend GPU if there's a compatible GPU regardless of current library status.
local RECOMMENDED_BACKEND="cpu"
local RECOMMENDED_REASON=""
local CAN_BUILD_GPU=false
# Only recommend Vulkan if GPU is compatible
if [[ "$HAS_VULKAN" == "yes" && "$HAS_VULKAN_DEV" == "true" && "$VULKAN_COMPATIBLE" == "compatible" ]]; then
RECOMMENDED_BACKEND="vulkan"
RECOMMENDED_REASON="Vulkan GPU detected with dev libraries"
CAN_BUILD_GPU=true
elif [[ "$HAS_NVIDIA_GPU" == "yes" && "$HAS_CUDA_DEV" == "true" ]]; then
# NVIDIA GPU - best option, uses CUDA
if [[ "$HAS_NVIDIA_GPU" == "yes" ]]; then
RECOMMENDED_BACKEND="cuda"
RECOMMENDED_REASON="NVIDIA GPU with CUDA toolkit"
if [[ "$HAS_CUDA_DEV" == "true" ]]; then
RECOMMENDED_REASON="NVIDIA GPU with CUDA toolkit installed"
else
RECOMMENDED_REASON="NVIDIA GPU detected (CUDA toolkit will be installed)"
fi
CAN_BUILD_GPU=true
# Vulkan-compatible GPU (AMD, Intel Gen8+) - second choice
elif [[ "$HAS_VULKAN" == "yes" && "$VULKAN_COMPATIBLE" == "compatible" ]]; then
RECOMMENDED_BACKEND="vulkan"
if [[ "$HAS_VULKAN_DEV" == "true" ]]; then
RECOMMENDED_REASON="Vulkan GPU detected with dev libraries"
else
RECOMMENDED_REASON="Vulkan GPU detected (dev libraries will be installed)"
fi
CAN_BUILD_GPU=true
# Vulkan GPU but compatibility unknown - allow GPU build as fallback
elif [[ "$HAS_VULKAN" == "yes" && "$VULKAN_COMPATIBLE" == "unknown" ]]; then
RECOMMENDED_BACKEND="vulkan"
RECOMMENDED_REASON="Possible Vulkan GPU (will verify during build)"
CAN_BUILD_GPU=true
# Incompatible Vulkan GPU (old Intel Gen7) - CPU only
elif [[ "$VULKAN_COMPATIBLE" == "incompatible" ]]; then
RECOMMENDED_BACKEND="cpu"
RECOMMENDED_REASON="Incompatible GPU ($VULKAN_COMPAT_REASON) - CPU mode recommended"
CAN_BUILD_GPU=false
elif [[ "$HAS_VULKAN" == "yes" || "$HAS_NVIDIA_GPU" == "yes" ]]; then
RECOMMENDED_BACKEND="cpu"
if [[ "$HAS_VULKAN" == "yes" ]]; then
RECOMMENDED_REASON="GPU detected but dev libraries missing (will use CPU)"
else
RECOMMENDED_REASON="NVIDIA GPU detected but CUDA not installed (will use CPU)"
fi
CAN_BUILD_GPU=false
else
RECOMMENDED_BACKEND="cpu"
RECOMMENDED_REASON="No compatible GPU detected"