255 lines
8.8 KiB
Bash
Executable File
255 lines
8.8 KiB
Bash
Executable File
#!/usr/bin/env nix-shell
|
|
#!nix-shell -i bash -p bash coreutils gnugrep gum git pciutils
|
|
#
|
|
# Based on https://wiki.debian.org/NvidiaGraphicsDrivers?action=AttachFile&do=view&target=nvidia-versions.sh
|
|
#
|
|
# Copyright © 2026 Raphaël Numbus <[email protected]>
|
|
#
|
|
# This package is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation; either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
|
|
# Avoid cryptic failure when running dash on this script
|
|
shopt -s compat31 nocasematch 2>/dev/null || { echo "Error: this script only works with bash." && exit 1; }
|
|
|
|
# Colors
|
|
GREEN='\033[0;32m'
|
|
BLUE='\033[0;34m'
|
|
YELLOW='\033[1;33m'
|
|
RED='\033[0;31m'
|
|
NC='\033[0m' # No Color
|
|
|
|
USER_ID="$(id -u)"
|
|
PCI_IDS_LOCATION="/run/user/${USER_ID}/gpu-detect"
|
|
|
|
declare -A args=(
|
|
["brand"]="all"
|
|
["hw_accel"]="true"
|
|
)
|
|
PCI_IDS=()
|
|
|
|
show_help() {
|
|
gum style --border-foreground="030" --bold --border=normal --padding="0 2" "GPU detection tool for NixOS"
|
|
echo "Usage: gpu-detect [OPTIONS] [PCIID]..."
|
|
echo ""
|
|
echo "Options:"
|
|
echo " -b, --brand BRAND Select GPU brand to detect: all, amd, intel, nvidia (default: all)"
|
|
echo " -hw, --hw_accel BOOL Provide hardware acceleration configuration: true, false (default: true)"
|
|
echo " -h, --help Show this help message and exit"
|
|
echo ""
|
|
echo "For each GPU installed in your system (or matching the specified brand/PCI ID),"
|
|
echo "the program will provide you the needed NixOS configuration."
|
|
exit 0
|
|
}
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case "${1}" in
|
|
--brand|-b)
|
|
if [[ -n "${2}" && ! "${2}" =~ ^- ]]; then
|
|
args["brand"]="${2,,}"
|
|
shift 2
|
|
else
|
|
echo -e "${RED}Error: --brand requires an argument.${NC}"
|
|
exit 1
|
|
fi
|
|
;;
|
|
--hw_accel|-hw)
|
|
if [[ -n "${2}" && ! "${2}" =~ ^- ]]; then
|
|
args["hw_accel"]="${2,,}"
|
|
shift 2
|
|
else
|
|
echo -e "${RED}Error: --hw_accel requires an argument.${NC}"
|
|
exit 1
|
|
fi
|
|
;;
|
|
--help|-h)
|
|
show_help
|
|
;;
|
|
-*)
|
|
echo -e "${RED}Unknown option ${1}${NC}"
|
|
show_help
|
|
;;
|
|
*)
|
|
PCI_IDS+=("${1}")
|
|
shift
|
|
;;
|
|
esac
|
|
done
|
|
|
|
gum style --border-foreground="030" --bold --border=normal --padding="0 2" "GPU detection tool for NixOS"
|
|
|
|
# Get the PCI IDs from the repo
|
|
if [[ ! -d "${PCI_IDS_LOCATION}" ]]; then
|
|
echo -e "${BLUE}Fetching latest PCI IDs database...${NC}"
|
|
mkdir -p "${PCI_IDS_LOCATION}"
|
|
if ! git clone -q -b ids-database https://gittea.dev/numbus/gpu-detect.git "${PCI_IDS_LOCATION}"; then
|
|
# Fallback to local checkout if remote is not available for testing purposes
|
|
if [[ -d "../.git" ]]; then
|
|
git clone -q -b ids-database "file://$(realpath ../)" "${PCI_IDS_LOCATION}" || true
|
|
fi
|
|
fi
|
|
else
|
|
echo -e "${BLUE}Updating PCI IDs database...${NC}"
|
|
if ! git -C "${PCI_IDS_LOCATION}" pull -q; then
|
|
echo -e "${RED}Error: Directory ${PCI_IDS_LOCATION} is not empty and does not contain the repository. Please check the folder and clean up manually.${NC}"
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
nvidia_detect() {
|
|
local PCI_ID="${1}"
|
|
local NVIDIA_VERSION=""
|
|
|
|
local VERSIONS=("unsupported" "legacy_340" "legacy_390" "legacy_470" "legacy_580" "current")
|
|
for version in "${VERSIONS[@]}"; do
|
|
if grep -q -i "${PCI_ID}" "${PCI_IDS_LOCATION}/nvidia/${version}.ids" 2>/dev/null; then
|
|
NVIDIA_VERSION="${version}"
|
|
break
|
|
fi
|
|
done
|
|
|
|
if [[ -z "${NVIDIA_VERSION}" ]]; then
|
|
gum style --foreground="212" "Uh oh. It seems that your card couldn't be detected." "A newer driver may add support for your card later."
|
|
return 1
|
|
fi
|
|
|
|
if [[ "${NVIDIA_VERSION}" == "unsupported" ]]; then
|
|
gum style --foreground="212" "Good news! You have nothing to do, your card runs with the 'nouveau' driver that is integrated in the kernel." "" "It seems you have a very old card! The proprietary NVIDIA drivers have been removed from Nixpkgs therefore it is not possible to install them."
|
|
return 0
|
|
fi
|
|
|
|
local EXTRA_PACKAGES=""
|
|
local HW_ACCEL_CONFIG=""
|
|
if [[ "${args["hw_accel"]}" == "true" ]]; then
|
|
if [[ "${NVIDIA_VERSION}" == "legacy_340" || "${NVIDIA_VERSION}" == "legacy_390" || "${NVIDIA_VERSION}" == "legacy_470" ]]; then
|
|
EXTRA_PACKAGES="libvdpau"
|
|
elif [[ "${NVIDIA_VERSION}" == "legacy_580" || "${NVIDIA_VERSION}" == "current" ]]; then
|
|
EXTRA_PACKAGES="nvidia-vaapi-driver libvdpau"
|
|
fi
|
|
HW_ACCEL_CONFIG="
|
|
hardware.graphics = {
|
|
enable = true;
|
|
extraPackages = with pkgs; [ ${EXTRA_PACKAGES} ];
|
|
};"
|
|
fi
|
|
|
|
local DRIVER_INFO=""
|
|
local NVIDIA_CONFIG=""
|
|
local NIX_PACKAGE_VER="${NVIDIA_VERSION}"
|
|
if [[ "${NVIDIA_VERSION}" == "current" ]]; then
|
|
NIX_PACKAGE_VER="stable"
|
|
fi
|
|
|
|
if [[ "${NVIDIA_VERSION}" == "current" ]]; then
|
|
DRIVER_INFO="An official stable NVIDIA driver release is available for your card."
|
|
NVIDIA_CONFIG="{ config, lib, pkgs, ... }:
|
|
{${HW_ACCEL_CONFIG}
|
|
services.xserver.videoDrivers = [ \"nvidia\" ];
|
|
hardware.nvidia = {
|
|
modesetting.enable = true;
|
|
nvidiaSettings = true;
|
|
open = true;
|
|
package = config.boot.kernelPackages.nvidiaPackages.${NIX_PACKAGE_VER};
|
|
|
|
# Advanced options, tweak if needed
|
|
powerManagement.enable = false; # Experimental: Enable this if you have graphical corruption issues or application crashes after waking up from sleep.
|
|
powerManagement.finegrained = false; # Experimental: Turns off GPU when not in use
|
|
};
|
|
}"
|
|
else
|
|
DRIVER_INFO="An official legacy NVIDIA driver release is available for your card."
|
|
NVIDIA_CONFIG="{ config, lib, pkgs, ... }:
|
|
{${HW_ACCEL_CONFIG}
|
|
services.xserver.videoDrivers = [ \"nvidia\" ];
|
|
hardware.nvidia = {
|
|
modesetting.enable = true;
|
|
nvidiaSettings = true;
|
|
package = config.boot.kernelPackages.nvidiaPackages.${NIX_PACKAGE_VER};
|
|
|
|
# Unsupported options
|
|
powerManagement.enable = false;
|
|
powerManagement.finegrained = false;
|
|
open = false;
|
|
};
|
|
}"
|
|
fi
|
|
|
|
gum style --foreground="212" "${DRIVER_INFO}"
|
|
if [[ "${args["hw_accel"]}" == "true" ]]; then
|
|
gum style "You can add the following code snippet to your NixOS configuration in order to enable the proprietary NVIDIA driver with hardware acceleration support."
|
|
else
|
|
gum style "You can add the following code snippet to your NixOS configuration in order to enable the proprietary NVIDIA driver."
|
|
fi
|
|
|
|
gum format '```nix
|
|
'"${NVIDIA_CONFIG}"'
|
|
```'
|
|
}
|
|
|
|
# Main logic
|
|
if [[ ${#PCI_IDS[@]} -gt 0 ]]; then
|
|
for id in "${PCI_IDS[@]}" ; do
|
|
# Try to parse NVIDIA PCI ID (vendor 10de)
|
|
PCIID=$(echo "$id" | sed -rn 's/^(10de)?:?([0-9a-fA-F]{4})$/10de\2/ip')
|
|
if [ -n "$PCIID" ]; then
|
|
gum style --foreground="030" "Checking driver support for NVIDIA PCI ID [$(echo $PCIID | sed -r 's/(....)(....)/\1:\2/')]"
|
|
nvidia_detect "$PCIID"
|
|
else
|
|
echo -e "${YELLOW}Currently only NVIDIA PCI IDs (10de:XXXX) are supported when passing explicitly.${NC}"
|
|
fi
|
|
done
|
|
else
|
|
if [[ "${args["brand"]}" == "all" || "${args["brand"]}" == "nvidia" ]]; then
|
|
NV_DEVICES=$(lspci -mn 2>/dev/null | awk '{ gsub("\"",""); if (($2 ~ "030[0-2]") && ($3 == "10de" || $3 == "12d2")) { print $1 } }')
|
|
|
|
if [ -n "$NV_DEVICES" ]; then
|
|
gum style --foreground="030" "Detected NVIDIA GPUs:"
|
|
for d in $NV_DEVICES ; do
|
|
lspci -nn -s $d
|
|
done
|
|
|
|
for d in $NV_DEVICES ; do
|
|
gum style --foreground="030" "Checking card: $(lspci -s $d | awk -F: '{print $3}')"
|
|
nvidia_detect "$(lspci -mn -s "$d" | awk '{ gsub("\"",""); print $3 $4 }')"
|
|
done
|
|
else
|
|
if [[ "${args["brand"]}" == "nvidia" ]]; then
|
|
gum style --foreground="212" "No NVIDIA GPU detected."
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
if [[ "${args["brand"]}" == "all" || "${args["brand"]}" == "amd" ]]; then
|
|
AMD_DEVICES=$(lspci -mn 2>/dev/null | awk '{ gsub("\"",""); if (($2 ~ "030[0-2]") && ($3 == "1002")) { print $1 } }')
|
|
if [ -n "$AMD_DEVICES" ]; then
|
|
gum style --foreground="030" "Detected AMD GPUs:"
|
|
for d in $AMD_DEVICES ; do
|
|
lspci -nn -s $d
|
|
done
|
|
gum style --foreground="212" "AMD configuration generation is not fully implemented yet."
|
|
else
|
|
if [[ "${args["brand"]}" == "amd" ]]; then
|
|
gum style --foreground="212" "No AMD GPU detected."
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
if [[ "${args["brand"]}" == "all" || "${args["brand"]}" == "intel" ]]; then
|
|
INTEL_DEVICES=$(lspci -mn 2>/dev/null | awk '{ gsub("\"",""); if (($2 ~ "030[0-2]") && ($3 == "8086")) { print $1 } }')
|
|
if [ -n "$INTEL_DEVICES" ]; then
|
|
gum style --foreground="030" "Detected Intel GPUs:"
|
|
for d in $INTEL_DEVICES ; do
|
|
lspci -nn -s $d
|
|
done
|
|
gum style --foreground="212" "Intel configuration generation is not fully implemented yet."
|
|
else
|
|
if [[ "${args["brand"]}" == "intel" ]]; then
|
|
gum style --foreground="212" "No Intel GPU detected."
|
|
fi
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
exit 0
|