From c1217bcea30b94b165105f4482967f57726be852 Mon Sep 17 00:00:00 2001 From: Rick Peters Date: Thu, 1 Oct 2026 15:20:02 +0200 Subject: [PATCH] feat: NVIDIA fix only for RTX 20 series or newer, with the VRAM booster's chwd legacy check (vram_nvidia_legacy_id) --- CHANGELOG.md | 1 + TECHNICAL.md | 6 ++++-- lib/nvidia.sh | 23 ++++++++++++++++++++--- lib/vram-booster.sh | 10 ++++++++-- tests/nvidia-hardware-test.sh | 10 ++++++++-- tests/nvidia-test.sh | 13 +++++++++++-- 6 files changed, 52 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ab84904..72cd481 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ one per merged pull request. - **fix: NVIDIA fix on Limine edits the KERNEL_CMDLINE[default] line (an appended += line ended up as literal text on the kernel command line, found in a VM); the modules are only loaded early when every installed kernel has them, and a Limine boot entry without the parameters is an error** - **test: tests/nvidia-hardware-test.sh for a real NVIDIA PC: check (read-only state of the detection, the live nvidia_drm modeset/fbdev, versions), apply, and visual (was the gaming mode picture clean), with a report file to paste** - **fix: the NVIDIA modules are loaded early only while every installed kernel has them, decided again at every kernel or driver change by a pacman hook (steamify-nvidia-initramfs): a later kernel without the modules (another kernel, a failed DKMS build, a downgrade) no longer makes its initramfs and Limine boot entry fail** +- **feat: the NVIDIA fix is only for RTX 20 series or newer, decided like the VRAM booster does (vram_nvidia_legacy_id: chwd's legacy card lists); older cards are left alone** ## 2.9.6 - 2026-09-30 diff --git a/TECHNICAL.md b/TECHNICAL.md index 0b3b9b7..bb17342 100644 --- a/TECHNICAL.md +++ b/TECHNICAL.md @@ -210,8 +210,10 @@ missing `-headers` package, which makes DKMS build the driver for it. gamescope drives the display itself through DRM/KMS, which with NVIDIA needs kernel modesetting and the framebuffer driver, and the driver loaded early; -without them gaming mode can show a corrupted image. With an NVIDIA GPU and -its driver installed (`lib/nvidia.sh`), the SteamOS conversion adds +without them gaming mode can show a corrupted image. With a supported NVIDIA GPU (RTX 20 series or newer, decided like the VRAM +booster does: a card on chwd's legacy lists `/var/lib/chwd/ids/nvidia-*.ids` +is older and left alone, `vram_nvidia_legacy_id`; without those lists every +card counts) and its driver installed (`lib/nvidia.sh`), the SteamOS conversion adds `nvidia-drm.modeset=1 nvidia-drm.fbdev=1` to the kernel command line (Limine, systemd-boot or GRUB; the file is backed up first) and `/etc/mkinitcpio.conf.d/90-steamify-nvidia.conf` (`MODULES+=(nvidia diff --git a/lib/nvidia.sh b/lib/nvidia.sh index df5021a..79518d7 100644 --- a/lib/nvidia.sh +++ b/lib/nvidia.sh @@ -4,7 +4,8 @@ # through DRM/KMS; with NVIDIA that needs kernel modesetting and the # framebuffer driver (nvidia-drm.modeset=1 nvidia-drm.fbdev=1) and the # driver in the initramfs, or the screen shows a corrupted image. -# Does nothing without an NVIDIA GPU that has its driver installed. +# Does nothing without a supported NVIDIA GPU (RTX 20 series or newer) that has +# its driver installed. # Sourced by steamify.sh; not meant to be run on its own. NVIDIA_PARAMS="nvidia-drm.modeset=1 nvidia-drm.fbdev=1" @@ -16,15 +17,31 @@ NVIDIA_HOOK=${NVIDIA_HOOK:-/etc/pacman.d/hooks/85-steamify-nvidia-initramfs.hook NVIDIA_DRM_DIR=${NVIDIA_DRM_DIR:-/sys/class/drm} nvidia_present() { - # An NVIDIA GPU (PCI vendor 0x10de, display class) and its kernel driver. + # A supported NVIDIA GPU: PCI vendor 0x10de, display class, its kernel + # driver installed, and not older than the RTX 20 series, decided like the + # VRAM booster does (vram_nvidia_legacy_id: chwd's legacy card lists, every + # other card runs NVIDIA's open modules). Older cards are left alone. local d for d in "$NVIDIA_DRM_DIR"/card[0-9]*/device; do [[ "$(cat "$d/vendor" 2>/dev/null)" == 0x10de ]] || continue - [[ "$(cat "$d/class" 2>/dev/null)" == 0x03* ]] && modinfo nvidia_drm >/dev/null 2>&1 && return 0 + [[ "$(cat "$d/class" 2>/dev/null)" == 0x03* ]] || continue + vram_nvidia_legacy_id "$(cat "$d/device" 2>/dev/null)" && continue + modinfo nvidia_drm >/dev/null 2>&1 && return 0 done return 1 } +nvidia_legacy_gpu() { + # 0 when the only NVIDIA GPU(s) are older than RTX 20 (reported, not fixed). + local d found=0 + for d in "$NVIDIA_DRM_DIR"/card[0-9]*/device; do + [[ "$(cat "$d/vendor" 2>/dev/null)" == 0x10de && "$(cat "$d/class" 2>/dev/null)" == 0x03* ]] || continue + vram_nvidia_legacy_id "$(cat "$d/device" 2>/dev/null)" || return 1 + found=1 + done + [[ $found == 1 ]] +} + nvidia_boot_file() { # Same boot loaders as the kernel command line elsewhere (lib/hdmi-refresh.sh). hdmi_boot_file diff --git a/lib/vram-booster.sh b/lib/vram-booster.sh index 8336d08..fc421a8 100644 --- a/lib/vram-booster.sh +++ b/lib/vram-booster.sh @@ -44,6 +44,13 @@ vram_nvidia() { # 470xx, 390xx); every other NVIDIA card runs the open kernel modules. VRAM_CHWD_IDS=/var/lib/chwd/ids +vram_nvidia_legacy_id() { + # vram_nvidia_legacy_id : 0 when chwd + # lists the card for a closed legacy branch, i.e. it is older than the + # RTX 20 series. Also what lib/nvidia.sh uses to decide if a card is supported. + grep -qwi "${1#0x}" "$VRAM_CHWD_IDS"/nvidia-*.ids 2>/dev/null +} + vram_nvidia_case() { # Why an NVIDIA card's VRAM isn't registered, so the menu can say what to # do: "update" (open modules older than 615), "switch " @@ -62,8 +69,7 @@ vram_nvidia_case() { esac for d in /sys/bus/pci/devices/*; do [[ "$(cat "$d/vendor" 2>/dev/null)" == 0x10de && "$(cat "$d/class" 2>/dev/null)" == 0x03* ]] || continue - id="$(cat "$d/device")"; id="${id#0x}" - grep -qwi "$id" "$VRAM_CHWD_IDS"/nvidia-*.ids 2>/dev/null && { echo legacy; return; } + vram_nvidia_legacy_id "$(cat "$d/device")" && { echo legacy; return; } done for p in 580xx 470xx 390xx; do pacman -Q "nvidia-$p-dkms" >/dev/null 2>&1 && { echo "switch nvidia-dkms-$p"; return; } diff --git a/tests/nvidia-hardware-test.sh b/tests/nvidia-hardware-test.sh index 7f2dc50..8bcde84 100644 --- a/tests/nvidia-hardware-test.sh +++ b/tests/nvidia-hardware-test.sh @@ -7,7 +7,7 @@ # Every run appends to ~/steamify-nvidia-report.txt: paste that file when asking for help. cd "$(dirname "$0")/.." || exit 1 REPORT="${NVIDIA_REPORT:-$HOME/steamify-nvidia-report.txt}" -source lib/common.sh; source lib/hdmi-refresh.sh; source lib/nvidia.sh +source lib/common.sh; source lib/hdmi-refresh.sh; source lib/vram-booster.sh; source lib/nvidia.sh mode="${1:-check}" fail=0 say() { echo "$*" | tee -a "$REPORT"; } @@ -31,7 +31,13 @@ report_system() { check_state() { say "-- Steamify's view" - if nvidia_present; then pass "an NVIDIA GPU with its driver is detected"; else bad "no NVIDIA GPU/driver detected: the fix does nothing here"; fi + if nvidia_present; then pass "a supported NVIDIA GPU (RTX 20 series or newer) with its driver is detected" + elif nvidia_legacy_gpu; then bad "the NVIDIA GPU is older than RTX 20 (on chwd's legacy lists in $VRAM_CHWD_IDS): the fix is not applied" + else bad "no NVIDIA GPU with its driver detected: the fix does nothing here"; fi + for c in /sys/class/drm/card[0-9]*/device; do + [[ "$(cat "$c/vendor" 2>/dev/null)" == 0x10de ]] && note "NVIDIA PCI device id $(cat "$c/device") $(vram_nvidia_legacy_id "$(cat "$c/device")" && echo '(on a chwd legacy list)' || echo '(not on a legacy list: RTX 20 or newer)')" + done + ls "$VRAM_CHWD_IDS"/nvidia-*.ids >/dev/null 2>&1 || note "no chwd legacy lists found: every NVIDIA card counts as supported" local p for p in $NVIDIA_PARAMS; do if grep -qw -- "$p" /proc/cmdline; then pass "$p is on the running kernel's command line" diff --git a/tests/nvidia-test.sh b/tests/nvidia-test.sh index 550df10..4f17498 100644 --- a/tests/nvidia-test.sh +++ b/tests/nvidia-test.sh @@ -7,7 +7,7 @@ T="$(mktemp -d)"; trap 'rm -rf "$T"' EXIT fail=0 check() { if eval "$2"; then echo "ok $1"; else echo "FAIL $1"; fail=1; fi; } -SCRIPT_DIR="$PWD"; source lib/common.sh; source lib/hdmi-refresh.sh; source lib/nvidia.sh +SCRIPT_DIR="$PWD"; source lib/common.sh; source lib/hdmi-refresh.sh; source lib/vram-booster.sh; source lib/nvidia.sh sudo() { "$@"; } info() { :; }; ok() { :; }; warn() { :; }; err() { echo "ERR $*"; } backup_file() { [[ -f "$1.bak" ]] || cp "$1" "$1.bak"; } @@ -24,7 +24,16 @@ NVIDIA_SCRIPT="$T/libexec/steamify-nvidia-initramfs"; NVIDIA_HOOK="$T/hooks/85-s NVIDIA_MODULES_DIR="$T/mods" NVIDIA_LIMINE_CONF="$T/none/limine.conf"; NVIDIA_SDBOOT_DIR="$T/none/entries"; NVIDIA_GRUB_CFG="$T/none/grub.cfg" # not generated here: not checked -FAKE_DRIVER=1; check "finds the NVIDIA card as card1 beside an iGPU" nvidia_present +mkdir -p "$T/chwd"; VRAM_CHWD_IDS="$T/chwd" +FAKE_DRIVER=1; check "finds the NVIDIA card as card1 beside an iGPU (no legacy lists)" nvidia_present +printf '1c03\n1b80\n' > "$T/chwd/nvidia-580.ids" # a GTX 1060 and a GTX 1080: chwd's 580xx legacy list +check "RTX 5080 (2c02) is not on a legacy list: supported" nvidia_present +echo 0x1c03 > "$T/drm/card1/device/device" +check "GTX 1060 (on chwd's legacy list, older than RTX 20): not supported" '! nvidia_present' +check "...and reported as a legacy GPU" nvidia_legacy_gpu +echo 0x2c02 > "$T/drm/card1/device/device"; check "RTX 5080 is not a legacy GPU" '! nvidia_legacy_gpu' +printf '2c02\n' > "$T/chwd/nvidia-580.ids"; check "a card id that is on a legacy list is skipped, whatever it is" '! nvidia_present' +printf '1c03\n' > "$T/chwd/nvidia-580.ids" FAKE_DRIVER=0; check "skips when the driver isn't installed" '! nvidia_present' FAKE_DRIVER=1; NVIDIA_DRM_DIR="$T/none"; check "skips without an NVIDIA GPU" '! nvidia_present' NVIDIA_DRM_DIR="$T/drm"