Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion plugins-claude/stl-game-config/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "stl-game-config",
"version": "1.2.2",
"version": "1.2.3",
"description": "Inspect, lint, and configure Steam games via SteamTinkerLaunch — live system/config reporting with JSON output, config linting, and template-based generation",
"author": {
"name": "Logan Gagne"
Expand Down
60 changes: 40 additions & 20 deletions plugins-claude/stl-game-config/scripts/system-info.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,51 @@ set -e
# sysfs DRM root; overridable so tests can supply fixture cards
DRM_ROOT="${STL_DRM_ROOT:-/sys/class/drm}"

# Detect the vendor of the GPU used for gaming. card0 is often the CPU's iGPU
# (e.g. Ryzen iGPU as card0, discrete NVIDIA as card1), so rank every card:
# NVIDIA > discrete AMD > Intel > AMD iGPU. An amdgpu device with under 2 GiB
# of VRAM is treated as an iGPU (its VRAM is a small BIOS carve-out).
# Map a PCI vendor ID to a vendor name; empty for anything else
vendor_name() {
case "$1" in
0x10de) echo "nvidia" ;;
0x1002) echo "amd" ;;
0x8086) echo "intel" ;;
esac
}

# Detect the vendor of the GPU used for gaming. Vulkan labels each device as
# discrete or integrated, so prefer the first discrete GPU, then the first
# integrated one (software renderers such as llvmpipe are ignored). card0 is
# often the CPU's iGPU, so it is never assumed to be the gaming GPU.
detect_gpu_vendor() {
local card vendor vram score best_score=0 best=""
local devices type t id vendor card best_score=0 best="" score
if command -v vulkaninfo &>/dev/null; then
# One "<deviceType> <vendorID>" line per GPU in the summary; the timeout
# keeps a hung ICD from blocking the whole report
devices=$(timeout 10 vulkaninfo --summary 2>/dev/null | awk '
/^GPU[0-9]+:/ { if (t) print t, v; t = v = "" }
/^[[:space:]]+vendorID[[:space:]]*=/ { v = $3 }
/^[[:space:]]+deviceType[[:space:]]*=/ { t = $3 }
END { if (t) print t, v }')
for type in PHYSICAL_DEVICE_TYPE_DISCRETE_GPU PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU; do
while read -r t id; do
[ "$t" = "$type" ] || continue
vendor=$(vendor_name "$id")
if [ -n "$vendor" ]; then
echo "$vendor"
return
fi
done <<<"$devices"
done
fi

# Fallback without Vulkan: rank sysfs DRM cards by vendor, NVIDIA > AMD >
# Intel (sysfs has no discrete/integrated flag)
for card in "$DRM_ROOT"/card[0-9]*; do
# Skip connector entries such as card0-DP-1
[[ "$(basename "$card")" =~ ^card[0-9]+$ ]] || continue
vendor=$(cat "$card/device/vendor" 2>/dev/null) || continue
vendor=$(vendor_name "$(cat "$card/device/vendor" 2>/dev/null)")
case "$vendor" in
0x10de) score=4 vendor=nvidia ;;
0x1002)
vram=$(cat "$card/device/mem_info_vram_total" 2>/dev/null) || vram=0
if [ "${vram:-0}" -ge 2147483648 ]; then score=3; else score=1; fi
vendor=amd
;;
0x8086) score=2 vendor=intel ;;
nvidia) score=3 ;;
amd) score=2 ;;
intel) score=1 ;;
*) continue ;;
esac
if [ "$score" -gt "$best_score" ]; then
Expand All @@ -42,13 +69,6 @@ detect_gpu_vendor() {
echo "nvidia"
return
fi

# Fallback: check Vulkan devices
if command -v vulkaninfo &>/dev/null; then
vulkaninfo --summary 2>/dev/null | grep -qi "NVIDIA" && echo "nvidia" && return
vulkaninfo --summary 2>/dev/null | grep -qi "AMD" && echo "amd" && return
vulkaninfo --summary 2>/dev/null | grep -qi "Intel" && echo "intel" && return
fi
echo "unknown"
}

Expand Down
2 changes: 1 addition & 1 deletion plugins-copilot/stl-game-config/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "stl-game-config",
"version": "1.2.2",
"version": "1.2.3",
"description": "Inspect, lint, and configure Steam games via SteamTinkerLaunch — live system/config reporting with JSON output, config linting, and template-based generation",
"author": {
"name": "Logan Gagne"
Expand Down
60 changes: 41 additions & 19 deletions tests/stl-game-config/test-system-info.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
# HDR: a PATH-injected kscreen-doctor mock prints fixture JSON for -j, so the
# result depends only on the fixture: HDR state of the primary (priority 1)
# enabled output, false on anything unparseable or non-KDE.
# GPU: STL_DRM_ROOT points at a fixture tree of cardN/device/vendor files.
# GPU: a PATH-injected vulkaninfo mock prints fixture devices; STL_DRM_ROOT
# points at a fixture tree of cardN/device/vendor files for the fallback.

set -euo pipefail

Expand Down Expand Up @@ -55,23 +56,35 @@ assert_hdr "empty output" false ''
assert_hdr "non-KDE compositor" false \
'{"outputs":[{"name":"DP-1","enabled":true,"priority":1,"hdr":true}]}' GNOME

# Empty vulkaninfo and GPU-less nvidia-smi mocks so the no-card fallbacks are
# hermetic; NVIDIA_SMI_GPUS=1 makes nvidia-smi report a GPU
printf '#!/usr/bin/env bash\n' >"$MOCK_DIR/vulkaninfo"
# vulkaninfo mock: prints a --summary device list built from VULKAN_DEVICES
# ("TYPE:vendorID ...", e.g. "INTEGRATED_GPU:0x1002 DISCRETE_GPU:0x10de"),
# nothing when unset. nvidia-smi mock lists no GPU unless NVIDIA_SMI_GPUS=1.
cat >"$MOCK_DIR/vulkaninfo" <<'EOF'
#!/usr/bin/env bash
[ -n "${VULKAN_DEVICES:-}" ] || exit 0
printf 'Devices:\n========\n'
i=0
for d in $VULKAN_DEVICES; do
printf 'GPU%d:\n' "$i"
printf '\tvendorID = %s\n' "${d#*:}"
printf '\tdeviceType = PHYSICAL_DEVICE_TYPE_%s\n' "${d%%:*}"
printf '\tdeviceName = mock device %d\n' "$i"
i=$((i + 1))
done
EOF
printf '#!/usr/bin/env bash\n[ "${NVIDIA_SMI_GPUS:-0}" = 1 ]\n' >"$MOCK_DIR/nvidia-smi"
chmod +x "$MOCK_DIR/vulkaninfo" "$MOCK_DIR/nvidia-smi"

# assert_gpu <label> <want> <card-spec>...
# Each card-spec is name:vendor[:vram_bytes], e.g. card0:0x1002:536870912
# Each card-spec is name:vendor, e.g. card0:0x1002 (sysfs fallback fixtures)
assert_gpu() {
local label="$1" want="$2" drm got spec name vendor vram
local label="$1" want="$2" drm got spec name vendor
shift 2
drm=$(mktemp -d -p "$MOCK_DIR")
for spec in "$@"; do
IFS=: read -r name vendor vram <<<"$spec"
IFS=: read -r name vendor <<<"$spec"
mkdir -p "$drm/$name/device"
echo "$vendor" >"$drm/$name/device/vendor"
[ -n "$vram" ] && echo "$vram" >"$drm/$name/device/mem_info_vram_total"
done
got=$(PATH="$MOCK_DIR:$PATH" STL_DRM_ROOT="$drm" XDG_SESSION_TYPE=x11 \
bash "$SCRIPT" | jq -r '.gpu_vendor')
Expand All @@ -86,18 +99,27 @@ assert_gpu() {
fi
}

echo "── detect_gpu_vendor ──"
assert_gpu "AMD iGPU as card0, NVIDIA dGPU as card1" nvidia \
card0:0x1002:536870912 card1:0x10de
assert_gpu "Intel iGPU as card0, discrete AMD as card1" amd \
card0:0x8086 card1:0x1002:17163091968
assert_gpu "AMD iGPU as card0, Intel Arc as card1" intel \
card0:0x1002:536870912 card1:0x8086
assert_gpu "AMD iGPU only" amd card0:0x1002:536870912
assert_gpu "connector entries are ignored" nvidia \
echo "── detect_gpu_vendor: Vulkan device type ──"
VULKAN_DEVICES="INTEGRATED_GPU:0x1002 DISCRETE_GPU:0x10de" \
assert_gpu "AMD iGPU listed first, discrete NVIDIA wins" nvidia
VULKAN_DEVICES="INTEGRATED_GPU:0x8086 DISCRETE_GPU:0x1002" \
assert_gpu "Intel iGPU listed first, discrete AMD wins" amd
VULKAN_DEVICES="INTEGRATED_GPU:0x1002 DISCRETE_GPU:0x8086" \
assert_gpu "AMD iGPU listed first, discrete Intel Arc wins" intel
VULKAN_DEVICES="CPU:0x10005 INTEGRATED_GPU:0x1002" \
assert_gpu "llvmpipe ignored, integrated GPU used when no discrete" amd
VULKAN_DEVICES="DISCRETE_GPU:0x10de" \
assert_gpu "Vulkan result overrides sysfs ranking" nvidia card0:0x1002

echo "── detect_gpu_vendor: fallbacks without Vulkan ──"
assert_gpu "sysfs: AMD card0, NVIDIA card1" nvidia card0:0x1002 card1:0x10de
assert_gpu "sysfs: Intel card0, AMD card1" amd card0:0x8086 card1:0x1002
assert_gpu "sysfs: connector entries are ignored" nvidia \
card0:0x10de card0-DP-1:0x8086
assert_gpu "no DRM cards, no vulkan match" unknown
NVIDIA_SMI_GPUS=1 assert_gpu "no DRM cards, nvidia-smi lists a GPU" nvidia
VULKAN_DEVICES="CPU:0x10005" \
assert_gpu "only a software renderer in Vulkan falls back to sysfs" intel card0:0x8086
assert_gpu "no Vulkan, no DRM cards" unknown
NVIDIA_SMI_GPUS=1 assert_gpu "no Vulkan, no DRM cards, nvidia-smi lists a GPU" nvidia

echo ""
echo "PASS: $PASS FAIL: $FAIL"
Expand Down
Loading