Compare commits

..
52 Commits
Author SHA1 Message Date
theupriser cab1a9792f Merge pull request #78 from theupriser/release/2.11.1
Sync git.upriser.nl mirror / sync (push) Skipped
Single-file build / bundle (push) Successful in 12s
Release 2.11.1: README screenshots for the 2.11 menu
2026-10-02 15:03:56 +02:00
theupriser 708df2f7d8 Merge pull request #77 from theupriser/bugfix/readme-screenshots
Sync git.upriser.nl mirror / sync (push) Skipped
Single-file build / bundle (push) Successful in 13s
docs: new README screenshots (2.11 menu), the silent option and the icons in the README
2026-10-02 15:03:27 +02:00
theupriser cef5c8d175 docs: changelog hash for the README screenshots 2026-10-02 15:01:49 +02:00
theupriser d70aeb8ac8 docs: new README screenshots (2.11 menu on a Steam Machine and an NVIDIA PC), the silent option and the icons in the README 2026-10-02 15:01:49 +02:00
theupriser 40d468cf83 chore: bump VERSION to 2.11.1 2026-10-02 14:45:32 +02:00
theupriser 2bd6e98ce0 Merge pull request #76 from theupriser/release/2.11.0
Single-file build / bundle (push) Successful in 15s
Sync git.upriser.nl mirror / sync (push) Skipped
Release 2.11.0: Start Steam silently in desktop mode, Steam Deck icons under the conversion, installer fixes
2026-10-02 14:39:46 +02:00
theupriser 93a26a0d16 Merge pull request #75 from theupriser/chore/tests-to-dev
Sync git.upriser.nl mirror / sync (push) Skipped
Single-file build / bundle (push) Successful in 15s
chore: the tests live in steamify-cachyos-dev; changelog hashes for 2.11.0
2026-10-02 14:38:12 +02:00
theupriser f05078d932 docs: changelog hashes for 2.11.0, and the tests move
Sync git.upriser.nl mirror / sync (push) Skipped
2026-10-02 14:37:42 +02:00
theupriser 4d387b2f86 chore: the tests live in steamify-cachyos-dev, remove tests/ 2026-10-02 14:37:02 +02:00
theupriser 19089a1eda Merge pull request #74 from theupriser/feature/silent-steam-start
Sync git.upriser.nl mirror / sync (push) Skipped
Single-file build / bundle (push) Successful in 12s
feat: Start Steam silently in desktop mode (opt-in), Steam Deck icons under the conversion, installer fixes
2026-10-02 14:34:56 +02:00
theupriser 2f7b53f64b fix: the Steam Machine serial number step is not fatal in the installer chroot (read-only /sys); the tmpfiles.d file applies at boot
Sync git.upriser.nl mirror / sync (push) Skipped
2026-10-02 12:22:20 +02:00
theupriser bd8f387cf5 fix: STEAMIFY_NO_DOWNLOAD finds the bundle through BASH_SOURCE (a bundle has no SCRIPT_DIR: the install failed with an unbound variable)
Sync git.upriser.nl mirror / sync (push) Skipped
2026-10-02 11:38:25 +02:00
theupriser 45a23aff34 feat: STEAMIFY_NO_DOWNLOAD: the first login runs the ISO's Steamify bundle instead of the newest release
Sync git.upriser.nl mirror / sync (push) Skipped
2026-10-02 11:11:18 +02:00
theupriser f3810a9fdd fix: the SteamOS theme drops the blank Discover pin from the taskbar (also on the first login of an ISO install)
Sync git.upriser.nl mirror / sync (push) Skipped
2026-10-02 10:52:04 +02:00
theupriser 188799e951 fix: the SteamOS conversion no longer lists the silent start in what it changes (it is its own opt-in option)
Sync git.upriser.nl mirror / sync (push) Skipped
2026-10-02 10:43:25 +02:00
theupriser 079e725ba8 feat: "Start Steam silently in desktop mode" is opt-in (it was always on); an existing systemd unit counts as on and is migrated by the update
Sync git.upriser.nl mirror / sync (push) Skipped
2026-10-02 10:16:40 +02:00
theupriser 7869b472be feat: Steam Deck/Machine icons is a sub-option of the SteamOS conversion (it only changes gaming mode)
Sync git.upriser.nl mirror / sync (push) Skipped
2026-10-02 10:15:59 +02:00
theupriser fbdad5a785 feat: the silent option is Steam's own autostart entry (~/.config/autostart/steam.desktop with -silent), so its "Run Steam when my computer starts" follows it; the systemd unit is gone
Sync git.upriser.nl mirror / sync (push) Skipped
2026-10-02 09:28:03 +02:00
theupriser 349492423e feat: "Start Steam silently in desktop mode" is always shown, also on a Steam Machine
Sync git.upriser.nl mirror / sync (push) Skipped
2026-10-02 09:10:26 +02:00
theupriser 613149a807 docs: changelog for the silent start option
Sync git.upriser.nl mirror / sync (push) Skipped
2026-10-01 23:04:18 +02:00
theupriser 2e51d1d3f3 feat: "Start Steam silently" sub-option for the SteamOS conversion (silent) and Gaming on NVIDIA (nvsilent) 2026-10-01 23:04:18 +02:00
theupriser e5110ada40 chore: bump VERSION to 2.11.0 2026-10-01 23:02:37 +02:00
theupriser 1074514b83 Merge pull request #73 from theupriser/release/2.10.0
Single-file build / bundle (push) Successful in 14s
Sync git.upriser.nl mirror / sync (push) Skipped
Release 2.10.0
2026-10-01 21:55:23 +02:00
theupriser 2c004322af Merge pull request #72 from theupriser/bugfix/changelog-2.10.0-trim
Sync git.upriser.nl mirror / sync (push) Skipped
Single-file build / bundle (push) Successful in 24s
docs: trim the 2.10.0 changelog
2026-10-01 21:54:20 +02:00
theupriser 3915e1a96f docs: trim the 2.10.0 changelog to the user-facing changes 2026-10-01 21:54:13 +02:00
theupriser 098dc3d0d8 chore: remove .no-release-yet, 2.10.0 is ready 2026-10-01 21:54:11 +02:00
theupriser 48352b5601 Merge bugfix/nvidia-shellcheck into release/2.10.0
Sync git.upriser.nl mirror / sync (push) Skipped
Single-file build / bundle (push) Successful in 11s
2026-10-01 21:43:21 +02:00
theupriser 05b8f11c19 docs: changelog hashes for 2.10.0 2026-10-01 21:43:21 +02:00
theupriser 8b96e2d8a9 fix: shellcheck of the bundle: nvidia_enable's local args clashed with an array of another module (renamed unit_args) 2026-10-01 21:43:21 +02:00
theupriser f1fb18ec81 docs: changelog for 2.10.0, one entry per commit with its hash 2026-10-01 21:41:02 +02:00
theupriser 1987fa903b Merge feature/extended-controller-support into release/2.10.0 2026-10-01 21:29:42 +02:00
theupriser b7dc931a4f Merge feature/nvidia-gaming-fix into release/2.10.0
# Conflicts:
#	CHANGELOG.md
2026-10-01 21:29:42 +02:00
theupriser 3d20a7edb0 chore: Version 2.10.0 2026-10-01 21:29:34 +02:00
theupriser f1983a9caf docs: README screenshots for the Steam Machine and for NVIDIA PCs, side by side 2026-10-01 21:24:36 +02:00
theupriser 01a77b7dc7 feat: new opt-in options show the new badge without being ticked 2026-10-01 21:11:51 +02:00
theupriser 83248a8478 feat: extended controller support: Xbox wireless dongle (xone) and Xbox Bluetooth (xpadneo) 2026-10-01 21:11:51 +02:00
theupriser 5811f5c8a4 fix: Add as non-Steam game isn't offered on NVIDIA PCs (no gaming mode there)
Sync git.upriser.nl mirror / sync (push) Skipped
2026-10-01 21:11:46 +02:00
theupriser 71bb2e7aca chore: Version 2.10.0 2026-10-01 21:05:05 +02:00
theupriser d0e4d8cf79 feat: Big Picture on NVIDIA starts on an empty Plasma session, so restored windows don't cover it 2026-10-01 19:19:51 +02:00
theupriser d1373e28a6 feat: single user mode on NVIDIA PCs: SDDM autologin into the Plasma session, without the conversion 2026-10-01 19:13:46 +02:00
theupriser d6db4f6f2d feat: "Gaming on NVIDIA" replaces the SteamOS conversion on NVIDIA PCs
gamescope's gaming mode shows a corrupted picture on NVIDIA (NVIDIA bug 5240452), also nested in KDE and in a KWin-only
session. With an NVIDIA GPU the conversion (gaming, boot, single, glyphs) is hidden unless already on, and nvidia takes its
place: Steam installed when missing and started at login on the Plasma desktop (user unit), with the sub-option bigpicture
for Big Picture or the normal window. The kernel parameters and early NVIDIA modules (RTX 20 series or newer) are kept as
part of it. tests/nvidia-test.sh covers the component and the menu rules against a fake GPU.
2026-10-01 19:04:58 +02:00
theupriser a5e9015d93 fix: NVIDIA fix handles Limine's += command line, underscore spelling; hardware test sets SCRIPT_DIR 2026-10-01 17:19:23 +02:00
theupriser ae238ff383 chore: .no-release-yet: this NVIDIA branch is not ready to be released
Sync git.upriser.nl mirror / sync (push) Skipped
2026-10-01 15:40:02 +02:00
theupriser c1217bcea3 feat: NVIDIA fix only for RTX 20 series or newer, with the VRAM booster's chwd legacy check (vram_nvidia_legacy_id) 2026-10-01 15:20:02 +02:00
theupriser f3d67fbe52 fix: never install an empty NVIDIA hook or script (a failed patch_file piped into install succeeded with no input) 2026-10-01 15:07:16 +02:00
theupriser 84cf0959e4 feat: NVIDIA modules in the initramfs only while every kernel has them, decided again by a pacman hook at every kernel change 2026-10-01 14:42:06 +02:00
theupriser 7caefb7da6 test: nvidia-hardware-test.sh to check, apply and visually verify the NVIDIA fix on a real PC 2026-10-01 13:20:01 +02:00
theupriser 453656a0a2 fix: NVIDIA fix checks the edit and the generated boot entries for every boot loader (limine.conf, systemd-boot entries, grub.cfg) 2026-10-01 13:07:07 +02:00
theupriser 6aa1377e16 fix: NVIDIA fix on Limine edits the existing cmdline line; early modules only when every kernel has them
Found by running it in a VM: the appended += line became literal text on the
kernel command line, and a kernel without the modules made limine-mkinitcpio
skip its boot entry.
2026-10-01 12:48:56 +02:00
theupriser 6bcae8af18 test: NVIDIA fix against a fake RTX 5080, stub modinfo and temp boot loader files 2026-10-01 11:07:32 +02:00
theupriser 3cbeb58211 docs: AGENTS.md: never work on main or a release branch, hardware-specific fixes, git identity 2026-10-01 10:54:49 +02:00
theupriser 83561bb214 feat: NVIDIA fix for gaming mode (kernel parameters and early modules)
Untested on hardware; .no-release-yet keeps it out of the release.
2026-10-01 10:54:27 +02:00
29 changed files with 524 additions and 591 deletions

No files matched your search

-4
View File
@@ -1,4 +0,0 @@
This branch is not ready to be released: do not merge it into the release branch.
When the feature is complete and tested, ask the user whether it may be released;
on a yes, delete this file, then open the pull request into the release branch.
Open work and how to pick it up: TODO-nvidia.md. Research notes: NVIDIA-RESEARCH.md. How to test on the NVIDIA PC: NVIDIA-INSTRUCTIONS.md.
+14 -11
View File
@@ -48,19 +48,19 @@ gamescope and the Plasma desktop. Primary target: the Valve Steam Machine
`<id>_available` is checked via `component_available` (e.g. `machine` `<id>_available` is checked via `component_available` (e.g. `machine`
only on Fremont). Turn-on order is `COMPONENTS` order, turn-off reverse; only on Fremont). Turn-on order is `COMPONENTS` order, turn-off reverse;
`gaming` must stay first. Dependencies live in `toggle_component`. `gaming` must stay first. Dependencies live in `toggle_component`.
- **Hardware-specific fixes** that belong to a component but aren't a menu - **NVIDIA** (`lib/nvidia.sh`): gamescope's session is broken on NVIDIA, so the SteamOS conversion (`gaming`, `boot`, `single`,
row (e.g. `lib/nvidia.sh`: NVIDIA's kernel parameters and early modules `glyphs`) is hidden there (unless already on) and `nvidia` + its sub-option `bigpicture` ("Gaming on NVIDIA") replace it:
for gaming mode, called from `gaming_enable`/`gaming_disable`) detect the Steam on the Plasma desktop, started at login. Never reintroduce a gamescope session for NVIDIA without re-testing on the
hardware themselves, change only what's missing, and undo it on disable. hardware (notes: steamify-cachyos-dev, `nvidia/`). It can't be tested without the hardware: keep the branch behind
Add them to the source loop in `steamify.sh` and the table in `.no-release-yet` until it was.
`TECHNICAL.md`. They can't be tested without the hardware: say so in the
changelog and keep the branch behind `.no-release-yet` until it was.
- **Feature versions.** Set `FEATURE_VERSION[<id>]` (`lib/menu.sh`) to the new - **Feature versions.** Set `FEATURE_VERSION[<id>]` (`lib/menu.sh`) to the new
`VERSION` whenever what `<id>_enable` sets up changes (a new component gets `VERSION` whenever what `<id>_enable` sets up changes (a new component gets
one too): installs recorded with an older version one too): installs recorded with an older version
are ticked and re-applied ("update" in the plan and the app). New default are ticked and re-applied ("update" in the plan and the app). New default
options are ticked for installs whose parent (top-level: `gaming`) is on options are ticked for installs whose parent (top-level: `gaming`) is on
(`feature_new`, shown as "new"). (`feature_new`, shown as "new"). New opt-in options (`NO_PRESELECT`) get the
same "new" badge without being ticked (`feature_new_optin`). Both count "Gaming
on NVIDIA" as a parent where the conversion isn't offered.
Options shown but left unticked in a confirmed run are recorded as Options shown but left unticked in a confirmed run are recorded as
`off` (`feature_record_unticked`), or `feature_new` would tick them again. `off` (`feature_record_unticked`), or `feature_new` would tick them again.
Status still comes from the system; don't add ad-hoc `<id>_repair` checks Status still comes from the system; don't add ad-hoc `<id>_repair` checks
@@ -156,9 +156,12 @@ gamescope and the Plasma desktop. Primary target: the Valve Steam Machine
a warning when `VERSION` is a version that's already released (so a a warning when `VERSION` is a version that's already released (so a
release branch that forgot its bump shows it on every PR). release branch that forgot its bump shows it on every PR).
- A release that adds, removes or renames a menu row also retakes the - A release that adds, removes or renames a menu row also retakes the
README screenshot (`assets/screenshot-menu.png`): the app from the README screenshots (`assets/screenshot-menu-steam-machine.png` and
branch on a Steam Machine, every row visible (window 1280 wide, tall `assets/screenshot-menu-nvidia.png`, side by side in the README): the app from the branch on a Steam Machine and on a PC
enough), the header showing the new `VERSION`, scaled to 1600 px wide. with an NVIDIA card, every row visible and each window only as tall as its options need, the header showing the new
`VERSION`, 1600 px wide. Size the window with a KWin script (match the `steamify-ui` class exactly: a title match also hits
Konsole and editor windows) and crop the full-screen capture to the client rectangle; mind the display scale (the Steam
Machine runs at 1.75).
- Users install through `releases/latest/download/steamify.sh` - Users install through `releases/latest/download/steamify.sh`
(GitHub's newest release). The `latest` tag and release follow the newest (GitHub's newest release). The `latest` tag and release follow the newest
version tag too (moved, asset replaced, when a new version is released), version tag too (moved, asset replaced, when a new version is released),
+19 -7
View File
@@ -5,14 +5,26 @@ All notable changes, per version and per commit. Versions follow
`steamify.sh`. Versions before 0.7.0 were numbered afterwards, `steamify.sh`. Versions before 0.7.0 were numbered afterwards,
one per merged pull request. one per merged pull request.
## 2.9.7 - 2026-10-01 ## 2.11.1 - 2026-10-02
- **feat: the SteamOS conversion fixes a corrupted gaming mode screen with an NVIDIA GPU: nvidia-drm.modeset=1 and fbdev=1 on the kernel command line, NVIDIA modules in the initramfs (lib/nvidia.sh)** - `d70aeb8` **docs: new README screenshots of the app (2.11 menu) on a Steam Machine and on an NVIDIA PC, and the README names the opt-in "Start Steam silently in desktop mode" and the icons as an option of the conversion**
- **test: tests/nvidia-test.sh runs the NVIDIA fix against a fake RTX 5080 beside an iGPU, a stub modinfo and temp copies of the Limine, systemd-boot and GRUB files (no root, VM or hardware); NVIDIA_DRM_DIR points detection at a fake sysfs tree** ## 2.11.0 - 2026-10-01
- **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** - `2e51d1d`, `3494924`, `fbdad5a`, `079e725`, `188799e` **feat: "Start Steam silently" sub-option: under the SteamOS conversion (`silent`, opt-in now: it was always on before; an existing one is moved from its systemd unit to the autostart entry by the "update") and under Gaming on NVIDIA (`nvsilent`, opt-in, not together with Big Picture); the SteamOS one is called "Start Steam silently in desktop mode" and is always shown, also on a Steam Machine; it is Steam's own autostart entry (`~/.config/autostart/steam.desktop`), so Steam's setting "Run Steam when my computer starts" follows it**
- **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** - `2f7b53f` **fix: the Steam Machine's serial number step no longer fails inside the ISO's installer (`/sys` is read-only in its chroot; the tmpfiles.d file applies at the next boot anyway), which made `machine` report an error and the install log end with `exit: 1`**
- **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** - `45a23af`, `bd8f387` **feat: `STEAMIFY_NO_DOWNLOAD` (the ISO's `steamify.nodownload` kernel parameter): the installed system's first login runs the Steamify bundle of the ISO instead of downloading the newest release (to test an unreleased Steamify)**
- `f3810a9` **fix: the SteamOS theme no longer leaves a blank Discover pin in the taskbar (Plasma's default taskbar pins Discover, which CachyOS doesn't install); the taskbar gets CachyOS's own pins (System Settings, files, browser), also on the ISO's first login**
- `7869b47` **feat: "Steam Deck/Machine icons" (`glyphs`) is a sub-option of the SteamOS conversion, like "Start Steam silently in desktop mode": it only changes gaming mode**
- `4d387b2` **chore: the Steamify unit tests (`controllers-test.sh`, `nvidia-test.sh`) and the NVIDIA hardware test live in steamify-cachyos-dev (`tests/`) now; `tests/` is removed here**
## 2.10.0 - 2026-10-01
- `d6db4f6` **feat: "Gaming on NVIDIA" (nvidia) replaces the SteamOS conversion on PCs with an NVIDIA GPU, where gamescope's gaming mode shows a corrupted picture (NVIDIA bug 5240452): Steam is installed when missing and starts at login on the Plasma desktop; the sub-option "Steam starts in Big Picture" (bigpicture) starts it in Big Picture, unticked in its normal window, on an empty Plasma session so windows of the last session don't cover it. On a supported card (RTX 20 series or newer) it also sets the NVIDIA kernel parameters and early modules. The conversion and its options are hidden there unless already on**
- `d1373e2` **feat: single user mode also works on NVIDIA PCs, without the SteamOS conversion**
- `5811f5c` **fix: "Add as non-Steam game" isn't offered on NVIDIA PCs (shown when already on, so it can be turned off)**
- `83248a8` **feat: Extended controller support (extended_controller_support, off by default): the Xbox wireless dongle (xone) and Xbox controllers over Bluetooth with rumble and battery level (xpadneo), built for every installed kernel; off removes only what Steamify installed**
- `01a77b7` **feat: a new opt-in option (unticked by default) shows the "new" badge in the menu and the app**
- `f1983a9` **docs: README screenshots of the 2.10.0 app, side by side: on a Steam Machine and on a PC with an NVIDIA card**
## 2.9.6 - 2026-09-30 ## 2.9.6 - 2026-09-30
-86
View File
@@ -1,86 +0,0 @@
# Testing the NVIDIA fix on a real PC
For the PC with an RTX 5080 (or any RTX 20 series or newer card) that shows a corrupted picture when
gaming mode (gamescope) starts. Branch `feature/nvidia-gaming-fix`, not released. Background and open
work: `TODO-nvidia.md`; research with sources: `NVIDIA-RESEARCH.md`.
## What the fix does
With a supported NVIDIA GPU (RTX 20 series or newer, same check as the VRAM booster) and its driver installed it
- adds `nvidia-drm.modeset=1 nvidia-drm.fbdev=1` to the kernel command line (Limine, systemd-boot or GRUB;
the file is backed up as `<file>.bak-gamescope-wizard`),
- loads the NVIDIA modules in the initramfs, but only while every installed kernel has them (a pacman hook,
`/etc/pacman.d/hooks/85-steamify-nvidia-initramfs.hook`, decides again at every kernel change),
- rebuilds the initramfs and boot entries and checks that the parameters really are in them.
It takes effect after a reboot. Older cards (GTX 10 series and older) are left alone.
## Before you start
- CachyOS with the NVIDIA driver installed (`nvidia-open`), a user with sudo, `git`.
- Be at the PC and able to see the screen: the last step needs your eyes.
- Know the way back (below) in case the PC doesn't boot to a picture: a TTY (Ctrl+Alt+F3) or the boot menu's
other kernel entry.
## Steps
1. Get the code:
```
git clone -b feature/nvidia-gaming-fix https://github.com/theupriser/steamify-cachyos
cd steamify-cachyos
```
(An existing checkout: `git fetch && git checkout feature/nvidia-gaming-fix && git pull`.)
2. Look first, change nothing:
```
bash tests/nvidia-hardware-test.sh check
```
3. Apply the fix (asks for your sudo password), then **reboot**:
```
bash tests/nvidia-hardware-test.sh apply
```
4. After the reboot, check again:
```
bash tests/nvidia-hardware-test.sh check
```
5. Start gaming mode, look at the screen, then (from the desktop or a TTY):
```
bash tests/nvidia-hardware-test.sh visual
```
It asks whether the picture was clean and for one line on what you saw.
6. Send back `~/steamify-nvidia-report.txt` (every run adds to it), or start a new session in the checkout and
say "read TODO-nvidia.md and the report".
(`./steamify.sh` from the same checkout also applies the fix, automatically, as part of the SteamOS conversion:
there is no menu option for it yet. The script above shows more.)
## Reading `check`
| Line | Good result | If not |
|---|---|---|
| `PASS a supported NVIDIA GPU ... is detected` | your 5080 | `FAIL ... older than RTX 20`: the card is skipped on purpose. `FAIL no NVIDIA GPU with its driver`: driver not installed (nouveau?) |
| `NVIDIA PCI device id 0x... (not on a legacy list ...)` | RTX 20 or newer | on a legacy list: older card |
| `no chwd legacy lists found` | (note only) | the check cannot tell old from new cards; every card counts as supported. Tell me, it's open item 4 in `TODO-nvidia.md` |
| `PASS nvidia-drm.modeset=1 is on the running kernel's command line` (and `fbdev=1`) | after step 3 and the reboot | "in the boot loader's file but not booted yet": reboot, or the boot entry used is another one |
| `PASS nvidia_drm modeset = Y` (and `fbdev = Y`) | after the reboot | `unreadable`: it needs sudo, enter the password |
| `... early-load drop-in is used / skipped` | note only: skipped means a kernel without the NVIDIA modules is installed | nothing to do |
## Reading the result
- Parameters on, `modeset = Y`, `fbdev = Y`, picture clean: the fix works.
- Parameters on and `Y`, picture still corrupted: not this fix. The report has the gamescope and NVIDIA log lines and
the versions of `nvidia-open`, `nvidia-utils`, `gamescope` and `gamescope-session-cachyos`: the cause is probably the
gamescope/driver combination for Blackwell (see `NVIDIA-RESEARCH.md`).
- No picture at all after the reboot: undo it (next section) from a TTY or the other kernel entry, and send the report.
## Undo
Turning the SteamOS conversion off in the wizard removes the fix too. On its own, from the checkout:
```
SCRIPT_DIR=$PWD bash -c 'source lib/common.sh; source lib/hdmi-refresh.sh; source lib/vram-booster.sh; source lib/nvidia.sh; nvidia_disable'
```
It removes the parameters, the early-load file, the pacman hook and its script, and rebuilds the boot entries (reboot after).
By hand: delete ` nvidia-drm.modeset=1 nvidia-drm.fbdev=1` from `/etc/default/limine` (`KERNEL_CMDLINE[default]`),
`/etc/sdboot-manage.conf` (`LINUX_OPTIONS`) or `/etc/default/grub` (`GRUB_CMDLINE_LINUX_DEFAULT`), or restore the
`.bak-gamescope-wizard` copy next to it; remove `/etc/mkinitcpio.conf.d/90-steamify-nvidia.conf`,
`/etc/pacman.d/hooks/85-steamify-nvidia-initramfs.hook` and `/usr/local/libexec/steamify-nvidia-initramfs`; then
`sudo limine-mkinitcpio` (Limine) or `sudo mkinitcpio -P` and `sudo sdboot-manage gen` / `sudo grub-mkconfig -o /boot/grub/grub.cfg`.
## What is and isn't proven
Proven in VMs (QEMU/KVM, CachyOS ISO 260809): the parameters land and survive a reboot on Limine, systemd-boot and GRUB;
disabling restores the original; on Limine the pacman hook keeps the early-load file right across kernel reinstalls
(with fake NVIDIA modules). Not proven: that the fix cures the 5080's picture, the real NVIDIA modules in the
initramfs, DKMS hook order, systemd-boot/GRUB with a pacman transaction, and the RTX 20+ check against a real chwd list.
Unit test (no hardware): `bash tests/nvidia-test.sh`.
-65
View File
@@ -1,65 +0,0 @@
# NVIDIA and gamescope: research notes (branch `feature/nvidia-gaming-fix`)
Written 2026-10-01 for the NVIDIA fix (`lib/nvidia.sh`). Delete with `TODO-nvidia.md` and
`.no-release-yet` when the feature is released, or move what is still useful to `TECHNICAL.md`.
"Verified" means seen in this session (a VM run or a fetched page); the rest is from search results or memory.
## The user's PC
RTX 5080 (Blackwell). Blackwell only works with NVIDIA's open kernel modules (`nvidia-open`), driver 570+.
The corrupted picture at gaming mode start is not diagnosed yet: the fix adds kernel parameters, the real cause
may be the gamescope/driver combination. `tests/nvidia-hardware-test.sh` collects the facts.
## What the fix changes and why (reasoning, not proven for gamescope)
- gamescope runs the display itself through DRM/KMS. With NVIDIA that needs `nvidia-drm.modeset=1`; `nvidia-drm.fbdev=1`
gives the console a framebuffer from `nvidia-drm`, so the hand-off from the console to gamescope is clean.
- Loading the NVIDIA modules in the initramfs (early KMS) only changes how early boot looks (native resolution,
splash, passphrase prompt), not speed. It is not needed for gamescope, which starts after login (believed, not proven).
- No source found that mentions these parameters for gamescope; the fix is a standard NVIDIA/Wayland setup, applied
automatically. Whether it cures the 5080's picture is only known after `tests/nvidia-hardware-test.sh`.
## Which cards (decision 2026-10-01: RTX 20 series or newer only, same check as the VRAM booster)
The code skips a card whose PCI id is on chwd's legacy lists (`vram_nvidia_legacy_id`); the notes below are why older
cards are not promised.
- Open kernel modules: Turing (RTX 20, GTX 16) and newer only; they need the GSP processor first built into Turing.
Maxwell, Pascal and Volta (GTX 900/10 series, Titan V) only work with the proprietary driver, whose legacy branch
is 580. Source: [NVIDIA README, open kernel modules](https://download.nvidia.com/XFree86/Linux-x86_64/560.35.03/README/kernel_open.html),
[NVIDIA datacenter driver guide, kernel modules](https://docs.nvidia.com/datacenter/tesla/driver-installation-guide/kernel-modules.html).
- `nvidia-drm.modeset` and `fbdev` are options of the `nvidia-drm` module in both flavours, so the fix applies to
any card whose driver provides `nvidia_drm` (what `nvidia_present` tests: GPU vendor 0x10de + `modinfo nvidia_drm`).
Whether gamescope then works on an older card is a different question, and no source says the fix helps there.
- Not NVIDIA's proprietary driver: nouveau has no `nvidia_drm`, so the fix does nothing. The CachyOS handheld ISO boots
GTX 10xx and older with nouveau until the NVIDIA driver is installed
([CachyOS forum](https://discuss.cachyos.org/t/information-experimental-cachyos-handheld-edition/203)).
## Known gamescope problems that are not this fix
- **GTX 1050 Ti (Pascal), driver 580.119.02, gamescope newer than 3.16.16:** the CachyOS handheld session fails to start when
a display is on the GPU's HDMI port (back to the TTY, loop). Workarounds: downgrade `gamescope` and `lib32-gamescope`
to 3.16.16, or use the motherboard's video port. Fixed upstream? unknown.
[CachyOS forum](https://discuss.cachyos.org/t/no-display-on-cachyos-handheld-edition-on-nvidia-with-gamescope-3-16-16/20935)
- **VRS on PCs:** CachyOS' gamescope-session enables variable rate shading (`STEAM_USE_DYNAMIC_VRS=1`,
`RADV_FORCE_VRS_CONFIG_FILE`, `echo 1x1 > ...` in `/usr/lib/steamos/gamescope-session`). It broke rendering (missing
floors/lighting, bad post-processing) on a PC with an AMD RX 6800 XT. RADV is AMD's driver: not the NVIDIA corruption.
Workaround: comment those three lines, or per game `env -u RADV_FORCE_VRS_CONFIG_FILE STEAM_USE_DYNAMIC_VRS=0 %command%`.
[CachyOS forum](https://discuss.cachyos.org/t/cachyos-gamescope-session-asset-missing-vrs-fix/34971)
- gamescope's DRM backend needs Vulkan DRM format modifiers; with the open Mesa driver NVK that came in Mesa 24.1
([GamingOnLinux](https://www.gamingonlinux.com/2024/05/nvk-driver-gets-drm-format-modifiers-to-work-with-gamescope-in-mesa-24-1)).
The proprietary driver had format-modifier trouble with gamescope too (GitHub issues
[ValveSoftware/gamescope#1662](https://github.com/ValveSoftware/gamescope/issues/1662),
[#1516](https://github.com/ValveSoftware/gamescope/issues/1516): titles seen only, not read).
## What was verified in VMs (QEMU/KVM, CachyOS ISO 260809)
- Kernel parameters land and survive a reboot on Limine, systemd-boot and GRUB; disable restores the original.
- Limine's tool is a compiled program: an appended `KERNEL_CMDLINE[default]+=" ..."` line was pasted into the kernel
command line as text; the fix edits the existing `KERNEL_CMDLINE[default]="..."` line.
- `mkinitcpio` fails on a MODULES entry a kernel lacks; `limine-mkinitcpio` then skips that kernel's initramfs and boot
entry (parameters included); systemd-boot/GRUB image: "may not be complete" (not run with failing modules).
- Real CachyOS/Limine pacman hooks: `10-limine-snapper-lock`, `60-limine-mkinitcpio-remove-pre`, `60-mkinitcpio-remove`,
`80-limine-efi-deploy`, `90-limine-mkinitcpio-remove-post`, `90-mkinitcpio-install`; Steamify's hook is `85-`
(DKMS's is `71-dkms-install`, not installed in the VM). A mirror older than the ISO "downgrades" kernels on reinstall.
- The hook keeps the early-load drop-in right across kernel changes (see `TODO-nvidia.md`).
## Still unknown (needs the hardware)
- Does the fix cure the 5080's corrupted picture? Which gamescope/driver versions does the PC have?
- Does it help, harm or do nothing on Maxwell/Pascal/Volta cards? No older card available yet.
- Real NVIDIA modules in the initramfs (VMs only had renamed fake modules); DKMS hook order on a PC with
`nvidia-open-dkms`.
+26 -3
View File
@@ -1,6 +1,14 @@
# Steamify CachyOS # Steamify CachyOS
![The Steamify app's menu on a Steam Machine](assets/screenshot-menu.png) The Steamify app's menu. On a Steam Machine (or any PC with an AMD or Intel
graphics card) it offers the full SteamOS conversion, on the left. On a PC with
an NVIDIA graphics card gamescope's gaming mode shows a corrupted picture, so the
menu offers **Gaming on NVIDIA** instead (Steam on the desktop, started at login,
optionally in Big Picture), on the right.
| On a Steam Machine | On a PC with an NVIDIA graphics card |
|---|---|
| ![The Steamify app's menu on a Steam Machine](assets/screenshot-menu-steam-machine.png) | ![The Steamify app's menu on a PC with an NVIDIA graphics card](assets/screenshot-menu-nvidia.png) |
Turn a CachyOS desktop PC into a SteamOS-style console: it boots straight Turn a CachyOS desktop PC into a SteamOS-style console: it boots straight
into Steam's Big Picture (gamescope), and you can switch to the KDE Plasma into Steam's Big Picture (gamescope), and you can switch to the KDE Plasma
@@ -19,14 +27,24 @@ Steam Machine.
on the desktop too. on the desktop too.
- **Boot into: gamescope / desktop** - where the PC starts. Gaming mode is - **Boot into: gamescope / desktop** - where the PC starts. Gaming mode is
the default. the default.
- **Start Steam silently in desktop mode** (off by default) - Steam starts
at login on the desktop, in the tray without a window. It is Steam's own
autostart entry, so Steam's setting "Run Steam when my computer starts"
follows it (the Linux Steam client has no silent option of its own).
- Steam's **System** settings show the SteamOS release Steamify follows - Steam's **System** settings show the SteamOS release Steamify follows
as OS Version (e.g. `steamos-3.9`), `steam-machine` as OS Codename and as OS Version (e.g. `steamos-3.9`), `steam-machine` as OS Codename and
Steamify's version as OS Variant. The OS name stays CachyOS Steamify's version as OS Variant. The OS name stays CachyOS
([details](TECHNICAL.md#what-steams-system-settings-show)). ([details](TECHNICAL.md#what-steams-system-settings-show)).
- **NVIDIA graphics cards:** gamescope's gaming mode shows a corrupted
picture there (an open NVIDIA driver bug), so the conversion isn't
offered. **Gaming on NVIDIA** takes its place: Steam on the desktop,
installed if it's missing and started at login, in **Big Picture** or its
normal window as you choose
([details](TECHNICAL.md#gaming-on-nvidia)).
2. **SteamOS theme** - the Vapor look of SteamOS for the desktop, with 2. **SteamOS theme** - the Vapor look of SteamOS for the desktop, with
**Add to Steam** in right-click menus **Add to Steam** in right-click menus
([details](TECHNICAL.md#steamos-desktop-look)). ([details](TECHNICAL.md#steamos-desktop-look)).
3. **Steam Deck/Machine icons** - Steam Deck button icons in gaming mode. 3. **Steam Deck/Machine icons** - Steam Deck button icons in gaming mode (an option of the SteamOS conversion).
4. **Single user mode** - like SteamOS: never a login or lock screen, and no 4. **Single user mode** - like SteamOS: never a login or lock screen, and no
KDE wallet password prompts (e.g. from Brave). Typing a password with a KDE wallet password prompts (e.g. from Brave). Typing a password with a
controller is no fun controller is no fun
@@ -37,7 +55,7 @@ Steam Machine.
With **Add as non-Steam game** (on by default) it's in your Steam library With **Add as non-Steam game** (on by default) it's in your Steam library
too: started from Steam it gets your controller (a Steam Controller only too: started from Steam it gets your controller (a Steam Controller only
talks to Steam), in gaming mode as well. Steam closes for a moment while talks to Steam), in gaming mode as well. Steam closes for a moment while
it's added, so that's done from the desktop. it's added, so that's done from the desktop. Not offered on PCs with an NVIDIA graphics card, which have no gaming mode.
6. **Update notifications** - on by default: a notification and a tray icon 6. **Update notifications** - on by default: a notification and a tray icon
when there's a new Steamify, with Open Steamify and Skip this version. It when there's a new Steamify, with Open Steamify and Skip this version. It
never updates anything by itself never updates anything by itself
@@ -56,6 +74,11 @@ Steam Machine.
the Steam Machine) or a USB CEC adapter; most graphics cards, NVIDIA the Steam Machine) or a USB CEC adapter; most graphics cards, NVIDIA
included, don't have it. See [CEC.md](CEC.md) for which PCs do, and how to included, don't have it. See [CEC.md](CEC.md) for which PCs do, and how to
add it to your own build ([details](TECHNICAL.md#hdmi-cec)). add it to your own build ([details](TECHNICAL.md#hdmi-cec)).
9. **Extended controller support** (off by default) - the Xbox wireless
dongle (xone) and Xbox controllers over Bluetooth with rumble, the right
button mapping and the battery level (xpadneo). Both are installed from the
CachyOS repo and built for every installed kernel
([details](TECHNICAL.md#extended-controller-support)).
## Steam Machine ## Steam Machine
+69 -35
View File
@@ -43,6 +43,14 @@ user wallet, with anything saved in it meanwhile, is kept as
`kdewallet.kwl.steamify-single-user` and used again the next time it's on. `kdewallet.kwl.steamify-single-user` and used again the next time it's on.
Passwords aren't shared between the two wallets. Passwords aren't shared between the two wallets.
**Without the conversion (NVIDIA PCs, where gamescope's session is broken)** nothing else logs in by itself, so single user mode
does that too: `single_login_enable` (`lib/single-user.sh`) switches to SDDM and writes
`/etc/sddm.conf.d/zzz-steamify-autologin.conf` (`User=`, `Session=plasma.desktop`, `Relogin=true`; named to sort after
`steam-set-session`'s `zz-steamos-autologin.conf`, which may still say gamescope from an earlier conversion), and drops any
`[Autologin]` from `/etc/sddm.conf`. Turning it off removes the file and goes back to plasma-login-manager. With the
conversion on, the conversion does the login as before. Ticking single user mode only ticks the conversion where the
conversion is offered.
**SDDM** is what SteamOS uses, and CachyOS's `steam-set-session` supports it **SDDM** is what SteamOS uses, and CachyOS's `steam-set-session` supports it
directly: it writes `/etc/sddm.conf.d/zz-steamos-autologin.conf`, which SDDM directly: it writes `/etc/sddm.conf.d/zz-steamos-autologin.conf`, which SDDM
honours. The script installs and enables `sddm` (active from the next boot), honours. The script installs and enables `sddm` (active from the next boot),
@@ -100,9 +108,11 @@ tools write to the conf.d fragment into the base config.
(never `zz-steamos-autologin.conf`, which CachyOS's tools own), and (never `zz-steamos-autologin.conf`, which CachyOS's tools own), and
installs `/usr/local/bin/sync-steamos-session.sh` plus installs `/usr/local/bin/sync-steamos-session.sh` plus
`sync-steamos-session.path`/`.service`; `sync-steamos-session.path`/`.service`;
- `KWIN_IM_SHOW_ALWAYS=1` for the virtual keyboard and a - `KWIN_IM_SHOW_ALWAYS=1` for the virtual keyboard; the sub-option `silent`
`steam-desktop-autostart` systemd user service that starts Steam silently ("Start Steam silently in desktop mode", opt-in, always shown) writes
in Plasma only; `~/.config/autostart/steam.desktop` (the system steam.desktop with `-silent` in its Exec line). That is the
file Steam's own setting "Run Steam when my computer starts" creates and removes, so the setting shows it. An older
`steam-desktop-autostart` user unit is removed;
- the **Return to Gaming Mode** shortcut; on plasma-login-manager with a - the **Return to Gaming Mode** shortcut; on plasma-login-manager with a
narrow sudoers rule (`/etc/sudoers.d/gamescope-session-switch`) so it can narrow sudoers rule (`/etc/sudoers.d/gamescope-session-switch`) so it can
restart the login manager without a password prompt. restart the login manager without a password prompt.
@@ -116,7 +126,8 @@ The conversion also sets what Steam's System settings show, see
**Steam Deck/Machine icons:** `STEAM_GAMEPADUI_ARGS="-gamepadui -steamos3"` **Steam Deck/Machine icons:** `STEAM_GAMEPADUI_ARGS="-gamepadui -steamos3"`
in `~/.config/environment.d/` (and gamescope-session's own environment in `~/.config/environment.d/` (and gamescope-session's own environment
file), which makes Steam show Steam Deck button glyphs in gaming mode. file), which makes Steam show Steam Deck button glyphs in gaming mode. It is a sub-option of the SteamOS conversion (`gaming`):
it does nothing without gaming mode, ticking it ticks the conversion and turning the conversion off turns it off.
## SteamOS desktop look ## SteamOS desktop look
@@ -206,33 +217,53 @@ or upgraded. A newly added kernel doesn't come with its headers, so
`ensure-kernel-headers.service` checks at every boot and installs any `ensure-kernel-headers.service` checks at every boot and installs any
missing `-headers` package, which makes DKMS build the driver for it. missing `-headers` package, which makes DKMS build the driver for it.
## NVIDIA fix for gaming mode ## Extended controller support
gamescope drives the display itself through DRM/KMS, which with NVIDIA needs `extended_controller_support` (`lib/controllers.sh`, top-level, off by default, 2.10.0) installs two kernel drivers from CachyOS's own
kernel modesetting and the framebuffer driver, and the driver loaded early; repo (no AUR): `xone-dkms` with `xone-dongle-firmware` for the Xbox wireless dongle (the kernel has no driver for it; wired
without them gaming mode can show a corrupted image. With a supported NVIDIA GPU (RTX 20 series or newer, decided like the VRAM Xbox controllers go through the same driver), and `xpadneo-dkms` for Xbox One/Series controllers over Bluetooth (without it
booster does: a card on chwd's legacy lists `/var/lib/chwd/ids/nvidia-*.ids` they work as plain gamepads but miss rumble including the triggers, the right button mapping and the battery level). Both are
is older and left alone, `vram_nvidia_legacy_id`; without those lists every DKMS modules, built for every installed kernel, so `install_kernel_headers` (`lib/steam-machine.sh`) makes sure each kernel has its
card counts) and its driver installed (`lib/nvidia.sh`), the SteamOS conversion adds headers first. A PC that already has the AUR's `xone-dkms-git` keeps it: it provides the same driver and conflicts with the repo's
`nvidia-drm.modeset=1 nvidia-drm.fbdev=1` to the kernel command line (Limine, `xone-dkms`. Status is the three packages being installed. Off removes only what Steamify installed (state
systemd-boot or GRUB; the file is backed up first) and `extended_controller_support`, `installed_pkgs`); the headers stay. The drivers load when the device shows up: the dongle is
`/etc/mkinitcpio.conf.d/90-steamify-nvidia.conf` (`MODULES+=(nvidia plugged in again, or the controller reconnected. Its test is in steamify-cachyos-dev (`tests/controllers-test.sh`).
nvidia_modeset nvidia_uvm nvidia_drm)`), then rebuilds the initramfs and boot
entries. The early-load drop-in is only there while every installed kernel has the ## Gaming on NVIDIA
NVIDIA modules (mkinitcpio fails on a missing module, and `limine-mkinitcpio`
then skips that kernel's boot entry, parameters included). That is decided again gamescope's own gaming mode shows a corrupted picture on NVIDIA graphics cards: NVIDIA's open bug 5240452 (flicker and
at every kernel or driver change by a pacman hook artifacts in the DRM session at modes above 2560x1440@120, seen up to driver 595 and on RTX 3070 Ti, 4090, 5090 and 5080;
(`/etc/pacman.d/hooks/85-steamify-nvidia-initramfs.hook`, after DKMS builds, no fix known). The kernel parameters `nvidia-drm.modeset=1`/`fbdev=1` and loading the NVIDIA modules early don't change it
before the initramfs is built) running `/usr/local/libexec/steamify-nvidia-initramfs`: (the driver already reports both `Y`), and gamescope started nested inside KDE artifacts too when KWin hands its fullscreen
another kernel without the modules, a failed DKMS build or a downgrade removes window straight to the display. What does work on an RTX 5080: Steam's Big Picture (`steam -gamepadui`) as a normal window of
the drop-in, and it comes back once every kernel has them again. the Plasma desktop session, smooth and clean.
On Limine the parameters go into the existing `KERNEL_CMDLINE[default]="..."`
line: an extra appended `+=` line is pasted into the command line as text. So with an NVIDIA GPU (PCI vendor 0x10de, display class, its driver providing `nvidia_drm`: `nvidia_present`) the SteamOS
Only what's missing is changed; it applies after a reboot. Turning conversion (`gaming`, and its options `boot`, `single`, `glyphs`) isn't offered, unless it is already on (so it can be turned
the conversion off removes both, the hook and its script. `tests/nvidia-test.sh` tests it against a fake GPU off). `nvidia` ("Gaming on NVIDIA", `lib/nvidia.sh`) takes its place, hidden while the conversion is on (both would start
and fake boot loader files; `tests/nvidia-hardware-test.sh check|apply|visual` is for a Steam at login): it installs `steam` when missing (recorded in state `nvidia`, removed again only then) and enables the user
real NVIDIA PC (read-only check, the real apply, and a prompt for whether the picture unit `steamify-steam-autostart.service` (`services/`, `ExecStart=/usr/bin/steam @ARGS@`, Plasma only). Its sub-option
was clean), and writes `~/steamify-nvidia-report.txt`. `bigpicture` ("Steam starts in Big Picture", ticked along with it) rewrites the unit with `-gamepadui` and sets
`ksmserverrc [General] loginMode=emptySession` (`kset`, undone with `krevert bigpicture`), so windows of the last session
(Discord, a browser) aren't restored on top of Big Picture; unticked, Steam starts in its normal window. The opt-in sub-option `nvsilent` ("Start Steam silently") rewrites the unit with `-silent`
(tray only); it and `bigpicture` exclude each other. The PC always boots into the desktop: there is no gamescope session. Takes effect at the next
login.
On a supported card (RTX 20 series or newer: not on chwd's legacy lists `/var/lib/chwd/ids/nvidia-*.ids`, the VRAM booster's
check, `vram_nvidia_legacy_id`; `nvidia_supported`) enabling it also does what NVIDIA's DRM stack wants, though it didn't cure
gamescope: `nvidia-drm.modeset=1 nvidia-drm.fbdev=1` on the kernel command line (Limine, systemd-boot or GRUB; the file is
backed up first; on Limine into the existing `KERNEL_CMDLINE[default]="..."` or `+="..."` line, never an extra appended line,
which ends up as text; the kernel treats `nvidia_drm` and `nvidia-drm` alike) and
`/etc/mkinitcpio.conf.d/90-steamify-nvidia.conf` (`MODULES+=(nvidia nvidia_modeset nvidia_uvm nvidia_drm)`), then the initramfs
and boot entries are rebuilt and checked for the parameters. The early-load drop-in is only there while every installed kernel
has the NVIDIA modules (mkinitcpio fails on a missing module, and `limine-mkinitcpio` then skips that kernel's boot entry):
a pacman hook (`/etc/pacman.d/hooks/85-steamify-nvidia-initramfs.hook`, after DKMS, before the initramfs is built) runs
`/usr/local/libexec/steamify-nvidia-initramfs` at every kernel or driver change and decides again. Turning it off removes
all of it. The tests are in steamify-cachyos-dev: `tests/nvidia-test.sh` (a fake GPU, a stub `pacman` and `systemctl`, a temp home) and `tests/nvidia-hardware-test.sh` (a real NVIDIA PC).
Tried and dropped (notes in steamify-cachyos-dev, `nvidia/HARDWARE-RESULTS.md`): a gamescope session that opens Big Picture in Plasma (it needed the `start-gamescope-session`
command shadowed in `/usr/local/bin`, and showed the desktop for a few seconds, then a Steam window with a black border);
a KWin session without Plasma (the mouse stuttered every second or two).
## HDMI-CEC ## HDMI-CEC
@@ -316,8 +347,7 @@ desktop through its desktop layout (A = Enter, B = Esc, Y = Space, X =
Steam's keyboard), in gaming mode as a gamepad. Steam's keyboard), in gaming mode as a gamepad.
Steam reads the list only at startup and writes it back on exit, so Steam is Steam reads the list only at startup and writes it back on exit, so Steam is
closed (`steam -shutdown`) for the edit and started again (through closed (`steam -shutdown`) for the edit and started again (`steam -silent`). That's refused in gaming
`steam-desktop-autostart.service` when it's there). That's refused in gaming
mode and when Steamify itself was started from Steam (`SteamGameId`), since mode and when Steamify itself was started from Steam (`SteamGameId`), since
closing Steam would end it. An entry for the start script that's already closing Steam would end it. An entry for the start script that's already
there (added by hand, or with the path from before 2.5.0) is updated, not there (added by hand, or with the path from before 2.5.0) is updated, not
@@ -462,7 +492,8 @@ In the home folder, everything is under `steamify`:
| `~/.local/share/steamify/bin/` | The shortcut's start scripts (`run-app`, `run-wizard`) and `steamify-notifier` | | `~/.local/share/steamify/bin/` | The shortcut's start scripts (`run-app`, `run-wizard`) and `steamify-notifier` |
| `~/.local/share/icons/hicolor/scalable/apps/steamify.svg` | The shortcut's icon | | `~/.local/share/icons/hicolor/scalable/apps/steamify.svg` | The shortcut's icon |
| `~/.local/share/applications/steamify-*.desktop` | The launcher entries | | `~/.local/share/applications/steamify-*.desktop` | The launcher entries |
| `~/.config/systemd/user/` | `steamify-update-check.*`, `steam-desktop-autostart.service` | | `~/.config/autostart/steam.desktop` | the `silent` option (Steam's "Run Steam when my computer starts") |
| `~/.config/systemd/user/` | `steamify-update-check.*` |
System-wide: `/usr/local/lib/steamify/` (kernel headers script), System-wide: `/usr/local/lib/steamify/` (kernel headers script),
`/usr/src/steamify-*` (DKMS modules), `/var/cache/steamify/kernel` (the old `/usr/src/steamify-*` (DKMS modules), `/var/cache/steamify/kernel` (the old
@@ -508,7 +539,9 @@ steamify.sh --defaults --list # what --defaults can se
item this PC can't use (e.g. `vram` without a VRAM region) is left off with item this PC can't use (e.g. `vram` without a VRAM region) is left off with
a warning. `--boot desktop` needs `gaming`. Unknown options, ids, `boot` or a warning. `--boot desktop` needs `gaming`. Unknown options, ids, `boot` or
`bios` in the list: exit code 1 before anything changes. What needs a `bios` in the list: exit code 1 before anything changes. What needs a
Plasma session waits for the first login (`lib/first-login.sh`). Plasma session waits for the first login (`lib/first-login.sh`). The same step (and the online theme path) replaces Plasma's default taskbar pins, which include Discover
(not installed on CachyOS: a blank icon), by CachyOS's own (`taskbar_drop_discover` in `lib/vapor-theme.sh`; skipped when Discover is
installed or the taskbar already has its own `launchers`).
With `Relogin=true`, a gamescope session that fails to start is restarted With `Relogin=true`, a gamescope session that fails to start is restarted
immediately, which can turn into a loop - see immediately, which can turn into a loop - see
@@ -538,7 +571,8 @@ immediately, which can turn into a loop - see
| `lib/steam-game.sh` | Add as non-Steam game: Steamify in the Steam library (`patches/steam-shortcuts.py`) | | `lib/steam-game.sh` | Add as non-Steam game: Steamify in the Steam library (`patches/steam-shortcuts.py`) |
| `lib/update-notifier.sh` | Update notifications: the notifier from `patches/` and its user timer | | `lib/update-notifier.sh` | Update notifications: the notifier from `patches/` and its user timer |
| `lib/first-login.sh` | `--defaults` without a session (the Steam Machine ISO's installer): the one-time first-login step that sets up single user's launcher on Plasma's new layout and opens the app | | `lib/first-login.sh` | `--defaults` without a session (the Steam Machine ISO's installer): the one-time first-login step that sets up single user's launcher on Plasma's new layout and opens the app |
| `lib/nvidia.sh` | NVIDIA fix for gaming mode: kernel parameters and early modules (part of the SteamOS conversion) | | `lib/controllers.sh` | Extended controller support: Xbox wireless dongle (xone) and Xbox Bluetooth (xpadneo) from the CachyOS repo |
| `lib/nvidia.sh` | Gaming on NVIDIA: Steam on the desktop, started at login, optionally in Big Picture (replaces the SteamOS conversion there) |
| `lib/vram-booster.sh` | VRAM booster (`dmemcg-booster`, `plasma-foreground-booster`) | | `lib/vram-booster.sh` | VRAM booster (`dmemcg-booster`, `plasma-foreground-booster`) |
| `services/` | The systemd units the scripts install (`service_file`, `@KEY@` placeholders); see its README | | `services/` | The systemd units the scripts install (`service_file`, `@KEY@` placeholders); see its README |
| `patches/` | Module sources and patches the scripts build or apply (`patch_file`); see its README | | `patches/` | Module sources and patches the scripts build or apply (`patch_file`); see its README |
-111
View File
@@ -1,111 +0,0 @@
# TODO: NVIDIA fix for gaming mode (branch `feature/nvidia-gaming-fix`)
Delete this file, `NVIDIA-INSTRUCTIONS.md`, `NVIDIA-RESEARCH.md` and `.no-release-yet` when the feature is released.
Written 2026-10-01 so a new session can pick this up.
## Problem
A PC with an NVIDIA RTX 5080 (Blackwell, open kernel modules) shows a corrupted
image when gaming mode (gamescope) starts. Cause not confirmed. Steamify had no
NVIDIA handling at all. Likely: `nvidia-drm.modeset=1` / `nvidia-drm.fbdev=1`
missing, or a gamescope/driver mismatch.
## What is built (all on this branch, pushed)
- `lib/nvidia.sh`: part of the SteamOS conversion (`gaming_enable` / `gaming_disable`).
With an NVIDIA GPU + driver it adds `nvidia-drm.modeset=1 nvidia-drm.fbdev=1` to the
kernel command line (Limine, systemd-boot, GRUB; backup first) and, only when every
installed kernel has `nvidia_drm`, `/etc/mkinitcpio.conf.d/90-steamify-nvidia.conf`.
Rebuilds initramfs + boot entries, verifies the config and the generated entries
have the parameters (error otherwise). Undone on disable. Description: `TECHNICAL.md`.
- `FEATURE_VERSION[gaming]=2.9.7` so installs that already have the conversion re-apply it.
- Test hooks `NVIDIA_DRM_DIR`, `NVIDIA_MODULES_DIR`, `NVIDIA_LIMINE_CONF`,
`NVIDIA_SDBOOT_DIR`, `NVIDIA_GRUB_CFG`: only set by tests; defaults are the real paths.
## Tested
- `bash tests/nvidia-test.sh`: 22 checks against a fake RTX 5080 beside an iGPU, a stub
`modinfo`, temp boot loader files. All pass.
- Real VMs (QEMU/KVM, Limine, systemd-boot, GRUB): enable, reboot, kernel command line
has the parameters; disable, reboot, original command line. All pass. Found and fixed:
Limine pasted an appended `+=` line as text into the cmdline; a kernel without the
NVIDIA modules made limine-mkinitcpio skip its boot entry.
## Kernel changes (done, VM-tested 2026-10-01, Limine)
The early-load drop-in is kept right by a pacman hook (`patches/steamify-nvidia-initramfs.{sh,hook}`,
installed by `nvidia_enable`, `/etc/pacman.d/hooks/85-steamify-nvidia-initramfs.hook`). Real pacman
transactions in a Limine VM: the hook runs between "Updating module dependencies" and "Updating
linux initcpios" (real hook names there: 60-*-remove, 80-limine-efi-deploy, 90-limine-mkinitcpio-remove-post,
90-mkinitcpio-install; DKMS would be 71-): the drop-in is present while every kernel has the modules, removed
when the LTS kernel loses them, back when they return; initramfs nvidia files 1 -> 5 -> 1 -> 5 -> 1
(1 = baseline, 4 modules added); no ERROR/skipping in any rebuild; cmdline kept the parameters after a reboot;
disable removes hook, script and drop-in. Found on the way: an empty hook/script was installed when
`patch_file` failed (now an error). Only tested with fake modules (renamed copies of a small module), on
Limine; systemd-boot and GRUB use the same hook but were not run with pacman transactions.
## Opt-out toggle (new request, 2026-10-01: not built yet)
When a compatible NVIDIA card is listed there should be a menu option, on by default (opt-out), named
"NVIDIA compatibility", as a sub-option of the SteamOS conversion, directly under "Boot into" (`boot`).
Today the fix runs unconditionally inside `gaming_enable`/`gaming_disable`.
- [ ] New component `nvidia` in `lib/menu.sh`: `COMPONENTS` right after `boot`, `PARENT[nvidia]=gaming`, `LABEL`,
`FEATURE_VERSION[nvidia]`, `component_available` -> `nvidia_available` (= `nvidia_present`); not in
`NO_PRESELECT` (ticked by default, `feature_new` ticks it for installs that already have the conversion).
`nvidia_status` from the system (hook + parameters present), `nvidia_enable`/`nvidia_disable` = the code now
called from `gaming_enable`/`gaming_disable` (remove those calls). Check `toggle_component` dependencies,
`feature_record_unticked`, the plan texts ("This will: ...").
- [ ] The app: `ui/qml/Texts.qml` item texts, `AppState.qml`, the screen rows, `lib/backend.sh` if it lists ids;
`--defaults [--options <ids>]` (the Steam Machine ISO's installer pages: it names the ids) and `--skip`.
- [ ] README rows/screenshot rule (a release that adds a menu row retakes `assets/screenshot-menu.png`), TECHNICAL.md,
CHANGELOG, `tests/nvidia-test.sh` (status/enable/disable through the component), VM menu test in
steamify-cachyos-dev (`share/vmtest/menu`, TESTPLAN.md row).
- [x] What "compatible" means (decided 2026-10-01): RTX 20 series or newer, the same check as the VRAM booster
(`vram_nvidia_legacy_id`: a card on chwd's legacy lists `/var/lib/chwd/ids/nvidia-*.ids` is older; without the
lists every card counts). `nvidia_present` = such a card + `nvidia_drm` available; the toggle's `nvidia_available`
is the same function. Older cards (GTX 10/9 series) are left alone: no promise they work with gamescope.
## Older cards and other research
Decision 2026-10-01: support RTX 20 series or newer only, with the VRAM booster's check (done in `lib/nvidia.sh`).
The user had hoped older GPUs would work too; not promised. Full notes with sources: **`NVIDIA-RESEARCH.md`**.
Short version: open kernel modules need Turing+, Maxwell/Pascal/Volta need the proprietary driver (580 legacy branch);
`nvidia-drm.modeset/fbdev` exist in both, so the fix applies to any card with `nvidia_drm`, but nothing found says gamescope
works better or worse there (a GTX 1050 Ti has a known gamescope>3.16.16 start problem on HDMI, not ours). Cannot be promised:
needs a test on a real older card. Design for the toggle: on by default for any card with `nvidia_drm`, the label says
what it does, `tests/nvidia-hardware-test.sh` reports GPU and driver so results can be compared.
## Still to do
1. [ ] **On the NVIDIA PC** (only place the real fix can be judged; the full steps, how to read the results and the undo
are in `NVIDIA-INSTRUCTIONS.md`), from this checkout:
`bash tests/nvidia-hardware-test.sh check` (before), `... apply` (asks sudo), reboot,
`... check` (after: `nvidia_drm modeset/fbdev = Y`), boot gaming mode, then
`... visual` (was the picture clean?). Everything goes to `~/steamify-nvidia-report.txt`:
paste it into the session.
2. [ ] If the parameters apply but the picture is still corrupted: look at the report's
gamescope/NVIDIA log lines and the versions (`nvidia-open`, `nvidia-utils`, `gamescope`,
`gamescope-session-cachyos`); the cause is then probably a gamescope/driver mismatch
for Blackwell, not this fix.
3. [ ] Not covered by any test: the early-load drop-in with the REAL NVIDIA modules (the VMs only have renamed
fake ones), and systemd-boot/GRUB with a pacman transaction (only Limine was run).
4. [ ] **Verify the RTX 20+ check on the PC** (decided 2026-10-01, only unit-tested with a fake chwd list; this laptop and the VMs
have no `/var/lib/chwd/ids`): `bash tests/nvidia-hardware-test.sh check` prints the NVIDIA PCI id, whether it is on a chwd legacy
list, and whether the lists exist at all. Expect for the RTX 5080: "supported", "not on a legacy list". If it says "no chwd
legacy lists found" the check cannot tell old from new there (every card then counts as supported, like the VRAM booster):
look at what `chwd`/`/var/lib/chwd/ids` provide on CachyOS and whether another source (the open-driver device list, the
`nvidia-open` package) would be better for both the VRAM booster and this fix. Also try `check` on any older NVIDIA card
that turns up (GTX 10/9 series): it must say "older than RTX 20 ... not applied" and `apply` must change nothing.
5. [ ] Changelog: fill in the commit hashes of this feature's lines (next commit, per AGENTS.md).
6. [ ] Build the opt-out toggle (section above) before release.
7. [ ] When complete and tested: ask the user whether it may be released. On a yes delete
`.no-release-yet` and this file, open the PR into `release/2.9.7` (local branch only so
far, one commit `chore: Version 2.9.7`; push it then) and merge it. The user merges
`release/2.9.7` into `main`.
## Working rules for this repo (see AGENTS.md and ../steamify-cachyos-dev/AGENTS.md)
- Never work on `main` or a `release/*` branch; no `Co-Authored-By` / "Generated with
Claude" lines in commits or PRs. No git identity on the dev laptop: use
`git -c user.name="Rick Peters" -c user.email="rickpeters@upriser.nl" commit`.
- Don't push `release/2.9.7` before the PR (a push can start a dev ISO build).
## If the VM tests need repeating (dev laptop, Ubuntu)
- `scripts/vminstall.sh` (steamify-cachyos-dev) with `VM_BOOTLOADER=limine|systemd-boot|grub`,
`CI=1`, a short `VM_DIR` (`~/vms/...`: socket paths over 108 bytes fail) and `VM_SSH_KEY`.
- This session's shell lacked the `kvm` group: run QEMU steps as `sg kvm -c "..."`.
- `/tmp/vminstall-iso.lock` belongs to another user and there is no `bsdtar`: use a copy of
`vminstall.sh` with another lock path and a `bsdtar` shim (Python `pycdlib` in a venv).
- Delete everything afterwards (`~/vms` incl. `pkg-cache`, the 3 GB ISO, keys).
Binary file not shown.

After

Width:  |  Height:  |  Size: 276 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 322 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 519 KiB

+14 -2
View File
@@ -50,10 +50,11 @@ backend_status() {
items+="${items:+,}{\"id\":$(json_str "$c"),\"label\":$(json_str "${LABEL[$c]%%:*}")" items+="${items:+,}{\"id\":$(json_str "$c"),\"label\":$(json_str "${LABEL[$c]%%:*}")"
items+=",\"hint\":$(json_str "$( [[ "${LABEL[$c]}" == *:* ]] && echo "${LABEL[$c]#*: }")")" items+=",\"hint\":$(json_str "$( [[ "${LABEL[$c]}" == *:* ]] && echo "${LABEL[$c]#*: }")")"
items+=",\"kind\":\"$kind\",\"parent\":$(json_str "$parent")" items+=",\"kind\":\"$kind\",\"parent\":$(json_str "$parent")"
items+=",\"needs\":\"\""
items+=",\"on\":$( [[ "$now" == 1 ]] && echo true || echo false)" items+=",\"on\":$( [[ "$now" == 1 ]] && echo true || echo false)"
items+=",\"wanted\":$( [[ "${WANTED[$c]:-0}" == 1 ]] && echo true || echo false)" items+=",\"wanted\":$( [[ "${WANTED[$c]:-0}" == 1 ]] && echo true || echo false)"
items+=",\"update\":$(feature_outdated "$c" && echo true || echo false)" items+=",\"update\":$(feature_outdated "$c" && echo true || echo false)"
items+=",\"new\":$(feature_new "$c" && echo true || echo false)" items+=",\"new\":$({ feature_new "$c" || feature_new_optin "$c"; } && echo true || echo false)"
items+=",\"selectable\":$(component_selectable "$c" && echo true || echo false)" items+=",\"selectable\":$(component_selectable "$c" && echo true || echo false)"
# Why it can't be turned on, for the app's explanation. # Why it can't be turned on, for the app's explanation.
[[ "$c" == vram && -n "${VRAM_NVIDIA_CASE:-}" ]] && [[ "$c" == vram && -n "${VRAM_NVIDIA_CASE:-}" ]] &&
@@ -146,8 +147,19 @@ backend_apply() {
for id in "${want[@]}"; do [[ "$id" == "$c" ]] && WANTED[$c]=1; done for id in "${want[@]}"; do [[ "$id" == "$c" ]] && WANTED[$c]=1; done
done done
# The same rules as the menu's toggles. # The same rules as the menu's toggles.
[[ "${WANTED[single]:-0}" == 1 ]] && WANTED[gaming]=1 # (Single user mode only needs the conversion where it is offered: not on NVIDIA PCs.)
[[ "${WANTED[single]:-0}" == 1 ]] && component_available gaming && WANTED[gaming]=1
if component_available gaming; then
[[ "${WANTED[gaming]:-0}" == 0 ]] && { WANTED[single]=0; WANTED[boot]=0; } [[ "${WANTED[gaming]:-0}" == 0 ]] && { WANTED[single]=0; WANTED[boot]=0; }
else
WANTED[boot]=0
fi
[[ "${WANTED[bigpicture]:-0}" == 1 ]] && WANTED[nvidia]=1
[[ "${WANTED[nvsilent]:-0}" == 1 ]] && WANTED[nvidia]=1
[[ "${WANTED[bigpicture]:-0}" == 1 ]] && WANTED[nvsilent]=0
[[ "${WANTED[nvidia]:-0}" == 0 ]] && { WANTED[bigpicture]=0; WANTED[nvsilent]=0; }
[[ "${WANTED[silent]:-0}" == 1 || "${WANTED[glyphs]:-0}" == 1 ]] && component_available gaming && WANTED[gaming]=1
[[ "${WANTED[gaming]:-0}" == 0 ]] && { WANTED[silent]=0; WANTED[glyphs]=0; }
[[ "${WANTED[poweroff]:-0}" == 1 ]] && WANTED[machine]=1 [[ "${WANTED[poweroff]:-0}" == 1 ]] && WANTED[machine]=1
[[ "${WANTED[machine]:-0}" == 0 ]] && WANTED[poweroff]=0 [[ "${WANTED[machine]:-0}" == 0 ]] && WANTED[poweroff]=0
[[ "${WANTED[kpin]:-0}" == 1 ]] && WANTED[machine]=1 [[ "${WANTED[kpin]:-0}" == 1 ]] && WANTED[machine]=1
+43
View File
@@ -0,0 +1,43 @@
#!/bin/bash
# Extended controller support: the Xbox wireless dongle (xone, with its firmware) and Xbox controllers over Bluetooth (xpadneo).
# The kernel has no driver for the dongle, and without xpadneo a Bluetooth Xbox controller works as a plain gamepad (buttons and
# sticks) but misses rumble (trigger motors too), proper button mapping and the battery level. Both are DKMS modules from CachyOS's
# own repo, built for every installed kernel (so every kernel needs its headers). Sourced by steamify.sh; not meant to be run on
# its own.
controller_xone_pkg() {
# A PC with the AUR's xone-dkms-git already works: the repo's xone-dkms would conflict with it.
pacman -Q xone-dkms-git >/dev/null 2>&1 && echo xone-dkms-git || echo xone-dkms
}
controller_pkgs() { echo "xpadneo-dkms $(controller_xone_pkg) xone-dongle-firmware"; }
extended_controller_support_status() {
# shellcheck disable=SC2046 # a list of package names
pacman -Q $(controller_pkgs) >/dev/null 2>&1
}
extended_controller_support_enable() {
local p prev missing=()
info "Installing extended controller support (Xbox wireless dongle, Xbox Bluetooth)..."
install_kernel_headers || return 1
for p in $(controller_pkgs); do pacman -Q "$p" >/dev/null 2>&1 || missing+=("$p"); done
if ((${#missing[@]})); then
sudo pacman -S --needed --noconfirm "${missing[@]}" ||
{ err "Installing ${missing[*]} failed."; return 1; }
# What a first, half-finished run installed stays on the list.
prev="$(state_get extended_controller_support installed_pkgs)"
state_set extended_controller_support installed_pkgs "$(echo "$prev ${missing[*]}" | xargs)"
fi
ok "Extended controller support on: plug the dongle in again (or reconnect the controller) to use it."
}
extended_controller_support_disable() {
local pkgs
pkgs="$(state_get extended_controller_support installed_pkgs)"
# Only what Steamify installed; kernel headers stay.
# shellcheck disable=SC2086 # a list of package names
[[ -n "$pkgs" ]] && sudo pacman -Rns --noconfirm $pkgs >/dev/null 2>&1
state_clear extended_controller_support
ok "Extended controller support off."
}
+15 -4
View File
@@ -7,13 +7,25 @@
FIRST_LOGIN_ENTRY="${XDG_CONFIG_HOME:-$HOME/.config}/autostart/steamify-first-login.desktop" FIRST_LOGIN_ENTRY="${XDG_CONFIG_HOME:-$HOME/.config}/autostart/steamify-first-login.desktop"
FIRST_LOGIN_SCRIPT="$STEAMIFY_BIN/first-login" FIRST_LOGIN_SCRIPT="$STEAMIFY_BIN/first-login"
FIRST_LOGIN_BUNDLE="$STEAMIFY_BIN/first-login-steamify.sh"
first_login_schedule() { first_login_schedule() {
# The newest release's Steamify runs at the first login. STEAMIFY_NO_DOWNLOAD (the ISO was started with
# steamify.nodownload, to test an unreleased Steamify): this very bundle runs instead.
# (Only a single-file bundle can be copied; SCRIPT_DIR doesn't exist in one.)
local run self="${BASH_SOURCE[0]:-}"
if [[ -n "${STEAMIFY_NO_DOWNLOAD:-}" && -f "$self" ]] && grep -q '^# Single-file build' "$self"; then
install_executable "$FIRST_LOGIN_BUNDLE" 755 < "$self"
run="bash \"$FIRST_LOGIN_BUNDLE\" --first-login; rm -f \"$FIRST_LOGIN_BUNDLE\""
else
run="curl -fsSL --max-time 30 \"$WIZARD_URL\" | bash -s -- --first-login"
fi
install_executable "$FIRST_LOGIN_SCRIPT" 755 << EOF2 install_executable "$FIRST_LOGIN_SCRIPT" 755 << EOF2
#!/bin/bash #!/bin/bash
# Installed by Steamify CachyOS: runs once, at the first desktop login. # Installed by Steamify CachyOS: runs once, at the first desktop login.
set -o pipefail set -o pipefail
curl -fsSL --max-time 30 "$WIZARD_URL" | bash -s -- --first-login mkdir -p ~/.cache
{ $run; } > ~/.cache/steamify-first-login.log 2>&1
rm -f "$FIRST_LOGIN_ENTRY" "\$0" rm -f "$FIRST_LOGIN_ENTRY" "\$0"
[[ -x "$WIZARD_APP_LAUNCHER" ]] && exec "$WIZARD_APP_LAUNCHER" [[ -x "$WIZARD_APP_LAUNCHER" ]] && exec "$WIZARD_APP_LAUNCHER"
EOF2 EOF2
@@ -31,10 +43,9 @@ first_login_run() {
[[ -n "$(plasma_applets org.kde.plasma.kickoff)" ]] && break [[ -n "$(plasma_applets org.kde.plasma.kickoff)" ]] && break
sleep 2 sleep 2
done done
if single_status; then
stop_plasmashell_for_edit stop_plasmashell_for_edit
single_launcher taskbar_drop_discover
single_status && single_launcher
restart_plasmashell_if_stopped restart_plasmashell_if_stopped
fi
return 0 return 0
} }
+15 -12
View File
@@ -109,7 +109,6 @@ gaming_enable() {
esac esac
create_desktop_shortcut create_desktop_shortcut
steam_enable steam_enable
nvidia_enable || return 1
os_name_enable || return 1 os_name_enable || return 1
} }
@@ -125,7 +124,6 @@ gaming_disable() {
steam_disable steam_disable
krevert gaming krevert gaming
os_name_disable os_name_disable
nvidia_disable
ok "The PC boots to the normal login screen again (from the next boot)." ok "The PC boots to the normal login screen again (from the next boot)."
} }
@@ -169,6 +167,20 @@ switch_to_sddm() {
ok "SDDM is the login manager from the next boot on." ok "SDDM is the login manager from the next boot on."
} }
remove_sddm_base_autologin() {
# /etc/sddm.conf is read last: an [Autologin] there would override our fragments.
if [[ -f /etc/sddm.conf ]] && grep -q '^\[Autologin\]' /etc/sddm.conf; then
backup_file /etc/sddm.conf
sudo awk '
/^\[Autologin\]/ { skip=1; next }
/^\[/ { skip=0 }
!skip { print }
' /etc/sddm.conf | sudo tee /etc/sddm.conf.tmp > /dev/null &&
sudo mv /etc/sddm.conf.tmp /etc/sddm.conf
info "Removed [Autologin] from /etc/sddm.conf (backup kept)."
fi
}
configure_sddm_autologin() { configure_sddm_autologin() {
# User= and Relogin= live in our own fragment; steam-set-session keeps # User= and Relogin= live in our own fragment; steam-set-session keeps
# Session= up to date in zz-steamos-autologin.conf, which sorts later # Session= up to date in zz-steamos-autologin.conf, which sorts later
@@ -184,16 +196,7 @@ Session=gamescope-session.desktop
Relogin=true Relogin=true
EOF EOF
if [[ -f /etc/sddm.conf ]] && grep -q '^\[Autologin\]' /etc/sddm.conf; then remove_sddm_base_autologin
backup_file /etc/sddm.conf
sudo awk '
/^\[Autologin\]/ { skip=1; next }
/^\[/ { skip=0 }
!skip { print }
' /etc/sddm.conf | sudo tee /etc/sddm.conf.tmp > /dev/null &&
sudo mv /etc/sddm.conf.tmp /etc/sddm.conf
info "Removed [Autologin] from /etc/sddm.conf (backup kept)."
fi
# Start in gamescope, through CachyOS's own tool so its file is current. # Start in gamescope, through CachyOS's own tool so its file is current.
sudo /usr/lib/steamos/steam-set-session gamescope-session.desktop sudo /usr/lib/steamos/steam-set-session gamescope-session.desktop
+58 -18
View File
@@ -5,18 +5,19 @@
# Menu order. Components are turned on in this order and off in reverse; # Menu order. Components are turned on in this order and off in reverse;
# gaming must come first (single user builds on it). # gaming must come first (single user builds on it).
COMPONENTS=(gaming boot theme glyphs single launcher steamgame notify vram cec machine poweroff kpin hdmi bios) COMPONENTS=(gaming boot silent glyphs nvidia bigpicture nvsilent theme single launcher steamgame notify extended_controller_support vram cec machine poweroff kpin hdmi bios)
# One-off actions rather than on/off components: never preselected, never # One-off actions rather than on/off components: never preselected, never
# re-applied, not listed as on or off. # re-applied, not listed as on or off.
ACTIONS=(bios) ACTIONS=(bios)
# Sub-options, shown indented under their parent and only while it's ticked. # Sub-options, shown indented under their parent and only while it's ticked.
declare -A PARENT=([boot]=gaming [steamgame]=launcher [poweroff]=machine [kpin]=machine [hdmi]=machine [bios]=machine) declare -A PARENT=([boot]=gaming [silent]=gaming [glyphs]=gaming [bigpicture]=nvidia [nvsilent]=nvidia [steamgame]=launcher [poweroff]=machine [kpin]=machine [hdmi]=machine [bios]=machine)
# Never preselected on a first run: booting into the desktop is a choice, # Never preselected on a first run: booting into the desktop is a choice,
# gamescope is the default; HDMI-CEC is opt-in (it can wake the machine or # gamescope is the default; HDMI-CEC is opt-in (it can wake the machine or
# upset other devices on the TV, even on SteamOS), except on a Steam Machine, # upset other devices on the TV, even on SteamOS), except on a Steam Machine,
# which has CEC like on SteamOS. HDMI refresh boost needs someone at the # which has CEC like on SteamOS. HDMI refresh boost needs someone at the
# screen to confirm each step. # screen to confirm each step. Extended controller support builds kernel modules for
NO_PRESELECT=(boot cec kpin hdmi) # every installed kernel: opt-in.
NO_PRESELECT=(boot silent nvsilent cec kpin hdmi extended_controller_support)
# Feature versions: the Steamify version in which what a component's enable # Feature versions: the Steamify version in which what a component's enable
# sets up last changed; set it to the new VERSION whenever you change one. # sets up last changed; set it to the new VERSION whenever you change one.
# Each successful run records it (state "features"); a component that's on # Each successful run records it (state "features"); a component that's on
@@ -25,20 +26,25 @@ NO_PRESELECT=(boot cec kpin hdmi)
# FEATURE_BASELINE. # FEATURE_BASELINE.
FEATURE_BASELINE=2.1.0 FEATURE_BASELINE=2.1.0
declare -A FEATURE_VERSION=( declare -A FEATURE_VERSION=(
[gaming]=2.9.7 [boot]=2.1.0 [theme]=2.1.0 [glyphs]=2.1.0 [single]=2.1.0 [gaming]=2.9.0 [boot]=2.1.0 [silent]=2.11.0 [nvidia]=2.10.0 [bigpicture]=2.10.0 [nvsilent]=2.11.0 [theme]=2.1.0 [glyphs]=2.1.0 [single]=2.1.0
[launcher]=2.1.0 [cec]=2.7.0 [machine]=2.9.0 [poweroff]=2.2.0 [vram]=2.3.0 [notify]=2.5.0 [steamgame]=2.5.1 [launcher]=2.1.0 [cec]=2.7.0 [machine]=2.9.0 [poweroff]=2.2.0 [vram]=2.3.0 [notify]=2.5.0 [steamgame]=2.5.1 [extended_controller_support]=2.10.0
[kpin]=2.1.0 [hdmi]=2.1.0 [kpin]=2.1.0 [hdmi]=2.1.0
) )
declare -A LABEL=( declare -A LABEL=(
[gaming]="SteamOS conversion: boot into gaming mode, Steam on the desktop" [gaming]="SteamOS conversion: boot into gaming mode, Steam on the desktop"
[boot]="Boot into the desktop instead of gaming mode" [boot]="Boot into the desktop instead of gaming mode"
[nvidia]="Gaming on NVIDIA: Steam on the desktop, started at login"
[silent]="Start Steam silently in desktop mode: in the tray at login on the desktop, no window"
[nvsilent]="Start Steam silently: in the tray at login, no window (untick: Steam's normal window)"
[bigpicture]="Steam starts in Big Picture: the controller-friendly Steam (untick: Steam's normal window)"
[theme]="Install SteamOS theme: Vapor look (cachyos-vapor)" [theme]="Install SteamOS theme: Vapor look (cachyos-vapor)"
[glyphs]="Install Steam Deck/Machine icons: Deck button icons in gaming mode" [glyphs]="Install Steam Deck/Machine icons: Deck button icons in gaming mode"
[single]="Single user mode: no password, lock screen or log out (SDDM)" [single]="Single user mode: no password, lock screen or log out (SDDM)"
[launcher]="Steamify shortcut: the app on the desktop, Steamify Terminal in the launcher" [launcher]="Steamify shortcut: the app on the desktop, Steamify Terminal in the launcher"
[steamgame]="Add as non-Steam game: Steamify in your Steam library, for the controller and gaming mode" [steamgame]="Add as non-Steam game: Steamify in your Steam library, for the controller and gaming mode"
[notify]="Update notifications: a notification when there's a new Steamify, never updates by itself" [notify]="Update notifications: a notification when there's a new Steamify, never updates by itself"
[extended_controller_support]="Extended controller support: Xbox wireless dongle (xone), Xbox controllers over Bluetooth (xpadneo)"
[vram]="VRAM booster: the game in front keeps its VRAM, background apps make room" [vram]="VRAM booster: the game in front keeps its VRAM, background apps make room"
[cec]="HDMI-CEC: use Steam with the TV remote, TV on/off with the PC (experimental)" [cec]="HDMI-CEC: use Steam with the TV remote, TV on/off with the PC (experimental)"
[machine]="Steam Machine support: LED bar driver, hardware settings in Steam" [machine]="Steam Machine support: LED bar driver, hardware settings in Steam"
@@ -51,9 +57,16 @@ declare -A CURRENT WANTED
component_available() { component_available() {
case "$1" in case "$1" in
# gamescope's own session is broken on NVIDIA: the conversion is replaced by "Gaming on NVIDIA" there (shown
# anyway when it's already on, so it can be turned off).
gaming|boot|silent|glyphs) ! nvidia_present || gaming_status ;;
nvidia) nvidia_available ;;
bigpicture|nvsilent) bigpicture_available ;;
machine|poweroff) machine_available ;; machine|poweroff) machine_available ;;
vram) vram_available ;; vram) vram_available ;;
steamgame) steamgame_available ;; # Steamify in the Steam library is for gaming mode's controller: not needed for Big Picture on the desktop (NVIDIA PCs;
# shown anyway when it's already on, so it can be turned off).
steamgame) steamgame_available && { ! nvidia_present || steamgame_status; } ;;
kpin) kpin_available ;; kpin) kpin_available ;;
hdmi) hdmi_available ;; hdmi) hdmi_available ;;
bios) bios_available ;; bios) bios_available ;;
@@ -72,6 +85,8 @@ menu_visible() {
# Shown in the menu. A sub-option ("Boot into", the kernel pin) only # Shown in the menu. A sub-option ("Boot into", the kernel pin) only
# while its parent is ticked. # while its parent is ticked.
component_available "$1" || return 1 component_available "$1" || return 1
# Silent start is hidden while Steam starts in Big Picture.
[[ "$1" == nvsilent && "${WANTED[bigpicture]:-0}" == 1 ]] && return 1
[[ -z "${PARENT[$1]:-}" || "${WANTED[${PARENT[$1]}]:-0}" == 1 ]] [[ -z "${PARENT[$1]:-}" || "${WANTED[${PARENT[$1]}]:-0}" == 1 ]]
} }
@@ -113,7 +128,7 @@ menu_label() {
# last run. # last run.
local l="${LABEL[$1]}" b="" local l="${LABEL[$1]}" b=""
if feature_outdated "$1"; then b="${c_yellow}(update)${c_reset}" if feature_outdated "$1"; then b="${c_yellow}(update)${c_reset}"
elif feature_new "$1"; then b="${c_green}(new)${c_reset}"; fi elif feature_new "$1" || feature_new_optin "$1"; then b="${c_green}(new)${c_reset}"; fi
if [[ -n "$b" ]]; then if [[ -n "$b" ]]; then
if [[ "$l" == *:* ]]; then l="${l%%:*} $b:${l#*:}" if [[ "$l" == *:* ]]; then l="${l%%:*} $b:${l#*:}"
else l+=" $b"; fi else l+=" $b"; fi
@@ -121,16 +136,30 @@ menu_label() {
printf '%s' "$l" printf '%s' "$l"
} }
feature_new() { feature_added() {
# A default option added after its parent was set up (e.g. the power-off # An option added after its parent was set up (e.g. the power-off fix under
# fix under Steam Machine support; a top-level one counts the SteamOS # Steam Machine support; a top-level one counts the SteamOS conversion, or
# conversion as its parent): never turned on or off. # "Gaming on NVIDIA" where that replaces it, as its parent), not on yet,
local p="${PARENT[$1]:-gaming}" # with no record: shown as "new".
[[ "$1" != gaming && "${CURRENT[$p]:-0}" == 1 && "${CURRENT[$1]:-0}" == 0 ]] && local p="${PARENT[$1]:-}" parent_on=0
! is_action "$1" && component_selectable "$1" && [[ " ${NO_PRESELECT[*]} " != *" $1 "* ]] && if [[ -n "$p" ]]; then parent_on="${CURRENT[$p]:-0}"
elif [[ "${CURRENT[gaming]:-0}" == 1 || "${CURRENT[nvidia]:-0}" == 1 ]]; then parent_on=1; fi
[[ "$1" != gaming && "$parent_on" == 1 && "${CURRENT[$1]:-0}" == 0 ]] &&
! is_action "$1" && component_selectable "$1" &&
[[ -z "$(state_get features "$1")" ]] [[ -z "$(state_get features "$1")" ]]
} }
feature_new() {
# A new default option: ticked for you (never turned on or off by itself).
feature_added "$1" && [[ " ${NO_PRESELECT[*]} " != *" $1 "* ]]
}
feature_new_optin() {
# A new opt-in option (unticked by default): the "new" badge only, it stays
# unticked. Boot into is a choice row of the conversion, not an item.
feature_added "$1" && [[ "$1" != boot && " ${NO_PRESELECT[*]} " == *" $1 "* ]]
}
component_selectable() { component_selectable() {
# Greyed out and not tickable when it has nothing to do. # Greyed out and not tickable when it has nothing to do.
case "$1" in case "$1" in
@@ -141,6 +170,7 @@ component_selectable() {
detect_components() { detect_components() {
local c any=false local c any=false
for c in "${COMPONENTS[@]}"; do CURRENT[$c]=0; WANTED[$c]=0; done
for c in "${COMPONENTS[@]}"; do for c in "${COMPONENTS[@]}"; do
component_available "$c" || continue component_available "$c" || continue
if "${c}_status"; then CURRENT[$c]=1; any=true; else CURRENT[$c]=0; fi if "${c}_status"; then CURRENT[$c]=1; any=true; else CURRENT[$c]=0; fi
@@ -222,7 +252,7 @@ defaults_options() {
warn "Leaving out ${LABEL[$c]%%:*}: not available on this PC." warn "Leaving out ${LABEL[$c]%%:*}: not available on this PC."
fi fi
done done
[[ "${WANTED[single]}" == 1 ]] && WANTED[gaming]=1 [[ "${WANTED[single]}" == 1 ]] && component_available gaming && WANTED[gaming]=1
for c in "${COMPONENTS[@]}"; do for c in "${COMPONENTS[@]}"; do
[[ "${WANTED[$c]}" == 1 && -n "${PARENT[$c]:-}" ]] && WANTED[${PARENT[$c]}]=1 [[ "${WANTED[$c]}" == 1 && -n "${PARENT[$c]:-}" ]] && WANTED[${PARENT[$c]}]=1
done done
@@ -256,7 +286,7 @@ defaults_list() {
[[ "$c" == cec ]] && machine_available && on=true [[ "$c" == cec ]] && machine_available && on=true
items+="${items:+,}{\"id\":$(json_str "$c"),\"label\":$(json_str "${LABEL[$c]%%:*}")" items+="${items:+,}{\"id\":$(json_str "$c"),\"label\":$(json_str "${LABEL[$c]%%:*}")"
items+=",\"hint\":$(json_str "$( [[ "${LABEL[$c]}" == *:* ]] && echo "${LABEL[$c]#*: }")")" items+=",\"hint\":$(json_str "$( [[ "${LABEL[$c]}" == *:* ]] && echo "${LABEL[$c]#*: }")")"
items+=",\"kind\":\"$kind\",\"parent\":$(json_str "${PARENT[$c]:-}"),\"on\":$on,\"selectable\":$sel}" items+=",\"kind\":\"$kind\",\"parent\":$(json_str "${PARENT[$c]:-}"),\"needs\":\"\",\"hideWhen\":$(json_str "$([[ "$c" == nvsilent ]] && echo bigpicture)"),\"on\":$on,\"selectable\":$sel}"
done done
printf '[%s]\n' "$items" printf '[%s]\n' "$items"
} }
@@ -266,10 +296,20 @@ toggle_component() {
component_selectable "$c" || return 1 component_selectable "$c" || return 1
WANTED[$c]=$(( 1 - WANTED[$c] )) WANTED[$c]=$(( 1 - WANTED[$c] ))
# Single user mode only makes sense on top of the SteamOS conversion. # Single user mode only makes sense on top of the SteamOS conversion.
if [[ "$c" == single && "${WANTED[single]}" == 1 ]]; then WANTED[gaming]=1; fi # (On NVIDIA the conversion isn't offered: single user mode logs in by itself, see lib/single-user.sh.)
if [[ "$c" == single && "${WANTED[single]}" == 1 ]] && component_available gaming; then WANTED[gaming]=1; fi
if [[ "$c" == gaming && "${WANTED[gaming]}" == 0 ]]; then WANTED[single]=0; WANTED[boot]=0; fi if [[ "$c" == gaming && "${WANTED[gaming]}" == 0 ]]; then WANTED[single]=0; WANTED[boot]=0; fi
# Where to boot to is part of the conversion, too. # Where to boot to is part of the conversion, too.
if [[ "$c" == boot && "${WANTED[boot]}" == 1 ]]; then WANTED[gaming]=1; fi if [[ "$c" == boot && "${WANTED[boot]}" == 1 ]]; then WANTED[gaming]=1; fi
# Big Picture is opt-out: ticked along with "Gaming on NVIDIA".
if [[ "$c" == nvidia ]]; then WANTED[bigpicture]=${WANTED[nvidia]}; fi
if [[ "$c" == bigpicture && "${WANTED[bigpicture]}" == 1 ]]; then WANTED[nvidia]=1; WANTED[nvsilent]=0; fi
# Silent and Big Picture exclude each other.
if [[ "$c" == nvsilent && "${WANTED[nvsilent]}" == 1 ]]; then WANTED[nvidia]=1; WANTED[bigpicture]=0; fi
if [[ "$c" == nvidia && "${WANTED[nvidia]}" == 0 ]]; then WANTED[nvsilent]=0; fi
if [[ "$c" == gaming && "${WANTED[gaming]}" == 0 ]]; then WANTED[silent]=0; WANTED[glyphs]=0; fi
if [[ "$c" == silent && "${WANTED[silent]}" == 1 ]]; then WANTED[gaming]=1; fi
if [[ "$c" == glyphs && "${WANTED[glyphs]}" == 1 ]]; then WANTED[gaming]=1; fi
# The power-off fix is opt-out: ticked along with Steam Machine support. # The power-off fix is opt-out: ticked along with Steam Machine support.
if [[ "$c" == machine ]]; then WANTED[poweroff]=${WANTED[machine]}; fi if [[ "$c" == machine ]]; then WANTED[poweroff]=${WANTED[machine]}; fi
if [[ "$c" == poweroff && "${WANTED[poweroff]}" == 1 ]]; then WANTED[machine]=1; fi if [[ "$c" == poweroff && "${WANTED[poweroff]}" == 1 ]]; then WANTED[machine]=1; fi
+117 -15
View File
@@ -1,22 +1,122 @@
#!/bin/bash #!/bin/bash
# NVIDIA fix for gaming mode, part of the SteamOS conversion # Gaming on NVIDIA PCs: the SteamOS conversion (gamescope session) isn't offered there, because gamescope's DRM session shows a
# (gaming_enable/gaming_disable). gamescope drives the display itself # corrupted picture on NVIDIA (NVIDIA's open bug 5240452: modes above 2560x1440@120). `nvidia` is the replacement: Steam on the
# through DRM/KMS; with NVIDIA that needs kernel modesetting and the # Plasma desktop, installed when missing and started at login; `bigpicture` (a sub-option) makes it start in Big Picture.
# framebuffer driver (nvidia-drm.modeset=1 nvidia-drm.fbdev=1) and the # On a supported card (RTX 20 series or newer, `nvidia_supported`) it also sets up what NVIDIA's Wayland/DRM stack wants:
# driver in the initramfs, or the screen shows a corrupted image. # nvidia-drm.modeset=1 and fbdev=1 on the kernel command line and the NVIDIA modules in the initramfs. That didn't cure
# Does nothing without a supported NVIDIA GPU (RTX 20 series or newer) that has # gamescope's picture (the driver already reported both `Y`), but it is the standard setup and may be needed.
# its driver installed.
# Sourced by steamify.sh; not meant to be run on its own. # Sourced by steamify.sh; not meant to be run on its own.
NVIDIA_UNIT=steamify-steam-autostart.service
NVIDIA_PARAMS="nvidia-drm.modeset=1 nvidia-drm.fbdev=1" NVIDIA_PARAMS="nvidia-drm.modeset=1 nvidia-drm.fbdev=1"
NVIDIA_INITRAMFS_CONF=/etc/mkinitcpio.conf.d/90-steamify-nvidia.conf NVIDIA_INITRAMFS_CONF=${NVIDIA_INITRAMFS_CONF:-/etc/mkinitcpio.conf.d/90-steamify-nvidia.conf}
# The script and pacman hook that keep the initramfs file right at every kernel change. # The script and pacman hook that keep the initramfs file right at every kernel change.
NVIDIA_SCRIPT=${NVIDIA_SCRIPT:-/usr/local/libexec/steamify-nvidia-initramfs} NVIDIA_SCRIPT=${NVIDIA_SCRIPT:-/usr/local/libexec/steamify-nvidia-initramfs}
NVIDIA_HOOK=${NVIDIA_HOOK:-/etc/pacman.d/hooks/85-steamify-nvidia-initramfs.hook} NVIDIA_HOOK=${NVIDIA_HOOK:-/etc/pacman.d/hooks/85-steamify-nvidia-initramfs.hook}
# The running kernel's command line; the tests point this at a file.
NVIDIA_CMDLINE=${NVIDIA_CMDLINE:-/proc/cmdline}
# The DRM devices in sysfs; the tests point this at a fake tree. # The DRM devices in sysfs; the tests point this at a fake tree.
NVIDIA_DRM_DIR=${NVIDIA_DRM_DIR:-/sys/class/drm} NVIDIA_DRM_DIR=${NVIDIA_DRM_DIR:-/sys/class/drm}
nvidia_unit_file() { echo "$HOME/.config/systemd/user/$NVIDIA_UNIT"; }
nvidia_present() { nvidia_present() {
# An NVIDIA GPU (PCI vendor 0x10de, display class) whose driver provides
# nvidia_drm. nouveau has none, and gamescope is not a problem there.
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* ]] || continue
modinfo nvidia_drm >/dev/null 2>&1 && return 0
done
return 1
}
# Shown on NVIDIA PCs, unless the SteamOS conversion is already on there (it
# has to be turned off first: both would start Steam at login).
nvidia_available() { nvidia_present && ! gaming_status 2>/dev/null; }
bigpicture_available() { nvidia_available; }
nvidia_status() {
pacman -Q steam >/dev/null 2>&1 && [[ -f "$(nvidia_unit_file)" ]] &&
user_systemctl is-enabled -q "$NVIDIA_UNIT" 2>/dev/null
}
nvidia_write_unit() {
# nvidia_write_unit [args]: the autostart unit, Steam started with those arguments.
local unit; unit="$(nvidia_unit_file)"
mkdir -p "$(dirname "$unit")"
service_file steamify-steam-autostart.service ARGS="$1" > "$unit" || { err "Writing $unit failed."; return 1; }
user_systemctl daemon-reload
}
nvidia_enable() {
info "Gaming on NVIDIA: Steam on the desktop, started at login..."
if ! pacman -Q steam >/dev/null 2>&1; then
sudo pacman -S --needed --noconfirm steam || { err "Installing Steam failed."; return 1; }
state_set nvidia installed_pkgs steam
fi
# Keeps what the Big Picture option set up; a first run starts Steam normally.
local unit_args=""
if bigpicture_status; then unit_args=-gamepadui; elif nvsilent_status; then unit_args=-silent; fi
nvidia_write_unit "$unit_args" || return 1
user_systemctl enable "$NVIDIA_UNIT" >/dev/null 2>&1 || { err "Enabling $NVIDIA_UNIT failed."; return 1; }
nvidia_kernel_enable || return 1
ok "Steam starts at your next login."
}
nvidia_disable() {
local pkgs unit; unit="$(nvidia_unit_file)"
user_systemctl disable --now "$NVIDIA_UNIT" >/dev/null 2>&1
rm -f "$unit"
user_systemctl daemon-reload
pkgs="$(state_get nvidia installed_pkgs)"
# Only what Steamify installed; games and the Steam folder stay.
# shellcheck disable=SC2086 # a list of package names
[[ -n "$pkgs" ]] && sudo pacman -Rns --noconfirm $pkgs >/dev/null 2>&1
state_clear nvidia
krevert bigpicture
nvidia_kernel_disable
ok "Steam no longer starts at login."
}
bigpicture_status() { grep -qs -- '-gamepadui' "$(nvidia_unit_file)"; }
bigpicture_enable() {
# The unit comes from nvidia_enable (it runs first); without it there is nothing to change.
[[ -f "$(nvidia_unit_file)" ]] || return 0
nvidia_write_unit -gamepadui || return 1
# Windows of the last session (Discord, a browser) would be restored on top of Big Picture.
kset bigpicture ksmserverrc General loginMode emptySession
ok "Steam starts in Big Picture at your next login, on an empty desktop."
}
bigpicture_disable() {
krevert bigpicture
[[ -f "$(nvidia_unit_file)" ]] || return 0
nvidia_write_unit "" && ok "Steam starts in its normal window at your next login."
}
# Sub-option: Steam starts silently (tray only, no window). Big Picture and
# a silent start exclude each other (the menus untick one when the other is
# ticked); a first run with both gets Big Picture.
nvsilent_status() { grep -qs -- '-silent' "$(nvidia_unit_file)"; }
nvsilent_enable() {
[[ -f "$(nvidia_unit_file)" ]] || return 0
bigpicture_status && return 0
nvidia_write_unit -silent || return 1
ok "Steam starts silently at your next login."
}
nvsilent_disable() {
nvsilent_status || return 0
nvidia_write_unit "" && ok "Steam starts in its normal window at your next login."
}
# --- Kernel parameters and early modules (a supported card only)
nvidia_supported() {
# A supported NVIDIA GPU: PCI vendor 0x10de, display class, its kernel # A supported NVIDIA GPU: PCI vendor 0x10de, display class, its kernel
# driver installed, and not older than the RTX 20 series, decided like the # 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 # VRAM booster does (vram_nvidia_legacy_id: chwd's legacy card lists, every
@@ -50,9 +150,11 @@ nvidia_boot_file() {
nvidia_param_set() { nvidia_param_set() {
# 0 when $1 (e.g. nvidia-drm.modeset=1) is on the kernel command line or # 0 when $1 (e.g. nvidia-drm.modeset=1) is on the kernel command line or
# already in the boot loader's file (not booted yet). # already in the boot loader's file (not booted yet).
local f; f="$(nvidia_boot_file)" # The kernel treats "nvidia_drm" and "nvidia-drm" alike: CachyOS' own
grep -qw -- "$1" /proc/cmdline 2>/dev/null || # setup may already have written the underscore spelling.
{ [[ -n "$f" ]] && grep -qw -- "$1" "$f" 2>/dev/null; } local f re; f="$(nvidia_boot_file)"; re="${1//nvidia-drm/nvidia[-_]drm}"
grep -qwE -- "$re" "$NVIDIA_CMDLINE" 2>/dev/null ||
{ [[ -n "$f" ]] && grep -qwE -- "$re" "$f" 2>/dev/null; }
} }
nvidia_params_missing() { nvidia_params_missing() {
@@ -105,8 +207,8 @@ nvidia_boot_has_params() {
sudo grep -rqs 'nvidia-drm.modeset=1' "$target" sudo grep -rqs 'nvidia-drm.modeset=1' "$target"
} }
nvidia_enable() { nvidia_kernel_enable() {
nvidia_present || return 0 nvidia_supported || return 0
local f changed=0 p; f="$(nvidia_boot_file)" local f changed=0 p; f="$(nvidia_boot_file)"
if nvidia_params_missing; then if nvidia_params_missing; then
if [[ -z "$f" ]]; then if [[ -z "$f" ]]; then
@@ -116,7 +218,7 @@ nvidia_enable() {
backup_file "$f" backup_file "$f"
case "$f" in case "$f" in
*/limine) */limine)
sudo sed -i -E "s/^(KERNEL_CMDLINE\[default\]=\"[^\"]*)\"/\1 $NVIDIA_PARAMS\"/" "$f" ;; sudo sed -i -E "s/^(KERNEL_CMDLINE\[default\]\+?=\"[^\"]*)\"/\1 $NVIDIA_PARAMS\"/" "$f" ;;
*/sdboot-manage.conf) */sdboot-manage.conf)
sudo sed -i -E "s/^(LINUX_OPTIONS=\"[^\"]*)\"/\1 $NVIDIA_PARAMS\"/" "$f" ;; sudo sed -i -E "s/^(LINUX_OPTIONS=\"[^\"]*)\"/\1 $NVIDIA_PARAMS\"/" "$f" ;;
*/grub) */grub)
@@ -152,7 +254,7 @@ nvidia_enable() {
return 0 return 0
} }
nvidia_disable() { nvidia_kernel_disable() {
local f changed=0; f="$(nvidia_boot_file)" local f changed=0; f="$(nvidia_boot_file)"
if [[ -n "$f" ]] && grep -q "$NVIDIA_PARAMS" "$f" 2>/dev/null; then if [[ -n "$f" ]] && grep -q "$NVIDIA_PARAMS" "$f" 2>/dev/null; then
sudo sed -i "s/ \?$NVIDIA_PARAMS//" "$f" sudo sed -i "s/ \?$NVIDIA_PARAMS//" "$f"
+30
View File
@@ -119,7 +119,36 @@ single_launcher_drop() {
return 0 return 0
} }
# Without the SteamOS conversion (NVIDIA PCs: gamescope's session is broken there) nothing logs in by itself, so single user
# mode does it: SDDM, autologin into the Plasma session. Named to sort after steam-set-session's zz-steamos-autologin.conf,
# which may still say gamescope from an earlier conversion.
SINGLE_AUTOLOGIN=${SINGLE_AUTOLOGIN:-/etc/sddm.conf.d/zzz-steamify-autologin.conf}
single_login_needed() { nvidia_present && ! gaming_status; }
single_login_enable() {
single_login_needed || return 0
switch_to_sddm || return 1
info "Logging in to the desktop by itself (SDDM autologin for $TARGET_USER)..."
sudo mkdir -p "$(dirname "$SINGLE_AUTOLOGIN")"
sudo tee "$SINGLE_AUTOLOGIN" > /dev/null << EOF
[Autologin]
User=$TARGET_USER
Session=plasma.desktop
Relogin=true
EOF
remove_sddm_base_autologin
}
single_login_disable() {
[[ -f "$SINGLE_AUTOLOGIN" ]] || return 0
sudo rm -f "$SINGLE_AUTOLOGIN"
# The way back is CachyOS's own login manager, unless the conversion is on (it keeps SDDM).
gaming_status || switch_to_plasmalogin
}
single_enable() { single_enable() {
single_login_enable || return 1
info "Turning off the lock screen, user switching and logging out..." info "Turning off the lock screen, user switching and logging out..."
stop_plasmashell_for_edit stop_plasmashell_for_edit
@@ -145,6 +174,7 @@ single_enable() {
} }
single_disable() { single_disable() {
single_login_disable
info "Restoring the lock screen, user switching and logging out..." info "Restoring the lock screen, user switching and logging out..."
stop_plasmashell_for_edit stop_plasmashell_for_edit
if has_journal single; then if has_journal single; then
+43 -15
View File
@@ -5,35 +5,63 @@
steam_enable() { steam_enable() {
info "Applying non-optional SteamOS environment & keyboard fixes..." info "Applying non-optional SteamOS environment & keyboard fixes..."
local steam_env_dir systemd_user_dir local steam_env_dir
steam_env_dir="$HOME/.config/environment.d" steam_env_dir="$HOME/.config/environment.d"
mkdir -p "$steam_env_dir" mkdir -p "$steam_env_dir"
# 2. Prevent KDE Wayland from blocking the virtual keyboard overlay # 2. Prevent KDE Wayland from blocking the virtual keyboard overlay
echo "KWIN_IM_SHOW_ALWAYS=1" > "$steam_env_dir/99-kde-virtual-keyboard.conf" echo "KWIN_IM_SHOW_ALWAYS=1" > "$steam_env_dir/99-kde-virtual-keyboard.conf"
# 3. Setup robust background systemd service for Steam autostart on Desktop Mode ok "Steam UI parameters and keyboard fix deployed successfully."
systemd_user_dir="$HOME/.config/systemd/user" }
mkdir -p "$systemd_user_dir"
service_file steam-desktop-autostart.service > "$systemd_user_dir/steam-desktop-autostart.service" # Sub-option of the SteamOS conversion: Steam starts silently (in the tray,
# no window) on the Plasma desktop. It is Steam's own autostart entry, the file
# Steam's setting "Run Steam when my computer starts" creates and removes, so
# that setting shows what Steamify did (and the other way around). Steam's copy
# is the system steam.desktop; ours has -silent in its Exec line.
STEAM_AUTOSTART="${XDG_CONFIG_HOME:-$HOME/.config}/autostart/steam.desktop"
STEAM_SYSTEM_DESKTOP=/usr/share/applications/steam.desktop
# Clean out old .desktop shortcut so they don't fight silent_status() {
rm -f "$HOME/.config/autostart/steam.desktop" # The old systemd unit counts as on too (until it is migrated by an update of this option).
grep -qs '^Exec=.*-silent' "$STEAM_AUTOSTART" ||
[[ -f "$HOME/.config/systemd/user/steam-desktop-autostart.service" ]]
}
# Reload user systemd context and activate the background loop silent_old_unit_remove() {
# Before 2.11.0 the option was a systemd user unit: it would start Steam a second time.
local unit="$HOME/.config/systemd/user/steam-desktop-autostart.service"
[[ -f "$unit" ]] || return 0
user_systemctl disable --now steam-desktop-autostart.service 2>/dev/null
rm -f "$unit"
user_systemctl daemon-reload user_systemctl daemon-reload
user_systemctl enable --now steam-desktop-autostart.service }
ok "Steam UI parameters and keyboard autostart deployed successfully." silent_enable() {
silent_old_unit_remove
mkdir -p "$(dirname "$STEAM_AUTOSTART")"
if [[ -f "$STEAM_SYSTEM_DESKTOP" ]]; then
sed 's|^Exec=/usr/bin/steam %U$|Exec=/usr/bin/steam -silent %U|' "$STEAM_SYSTEM_DESKTOP" > "$STEAM_AUTOSTART"
fi
silent_status || printf '%s\n' '[Desktop Entry]' 'Name=Steam' 'Exec=/usr/bin/steam -silent %U' \
'Icon=steam' 'Terminal=false' 'Type=Application' 'Categories=Network;FileTransfer;Game;' > "$STEAM_AUTOSTART"
ok "Steam starts silently on the desktop from the next login."
}
silent_disable() {
silent_old_unit_remove
silent_status && rm -f "$STEAM_AUTOSTART"
ok "Steam no longer starts by itself on the desktop."
} }
steam_disable() { steam_disable() {
info "Removing Steam desktop autostart..." info "Removing Steam desktop settings..."
user_systemctl disable --now steam-desktop-autostart.service 2>/dev/null # The autostart entry is the `silent` option's: removed with it, and here
rm -f "$HOME/.config/systemd/user/steam-desktop-autostart.service" \ # too for when the conversion goes off by itself.
"$HOME/.config/environment.d/99-kde-virtual-keyboard.conf" silent_status && silent_disable
user_systemctl daemon-reload silent_old_unit_remove
rm -f "$HOME/.config/environment.d/99-kde-virtual-keyboard.conf"
ok "Steam desktop settings removed (takes full effect at next login)." ok "Steam desktop settings removed (takes full effect at next login)."
} }
+1 -5
View File
@@ -56,7 +56,7 @@ steamgame_steam_busy() {
steamgame_edit() { steamgame_edit() {
# steamgame_edit <function>: runs it with Steam closed, then starts Steam # steamgame_edit <function>: runs it with Steam closed, then starts Steam
# again if it was running (through our autostart unit when that's there). # again if it was running (silently, in the tray).
local was_running=false i local was_running=false i
if pgrep -x steam >/dev/null; then if pgrep -x steam >/dev/null; then
steamgame_steam_busy && return 1 steamgame_steam_busy && return 1
@@ -72,11 +72,7 @@ steamgame_edit() {
fi fi
"$1"; local rc=$? "$1"; local rc=$?
if [[ "$was_running" == true ]]; then if [[ "$was_running" == true ]]; then
if user_systemctl is-enabled -q steam-desktop-autostart.service 2>/dev/null; then
user_systemctl start steam-desktop-autostart.service
else
systemd-run --user --collect -q steam -silent >/dev/null 2>&1 systemd-run --user --collect -q steam -silent >/dev/null 2>&1
fi
info "Steam is starting again." info "Steam is starting again."
fi fi
return "$rc" return "$rc"
+5 -2
View File
@@ -407,9 +407,12 @@ wifi_backend_disable() {
serial_enable() { serial_enable() {
printf '%s\n' "# Written by Steamify: Steam shows the serial number, like on SteamOS." \ printf '%s\n' "# Written by Steamify: Steam shows the serial number, like on SteamOS." \
'z /sys/class/dmi/id/product_serial 0444 - - -' | sudo tee "$SERIAL_TMPFILES" > /dev/null && 'z /sys/class/dmi/id/product_serial 0444 - - -' | sudo tee "$SERIAL_TMPFILES" > /dev/null ||
sudo systemd-tmpfiles --create "$SERIAL_TMPFILES" ||
{ err "Making the serial number readable for Steam failed."; return 1; } { err "Making the serial number readable for Steam failed."; return 1; }
# The file applies at every boot; now too, unless /sys is read-only (the ISO's installer runs in a chroot).
sudo systemd-tmpfiles --create "$SERIAL_TMPFILES" 2>/dev/null ||
info "The serial number becomes readable for Steam at the next boot."
return 0
} }
serial_disable() { serial_disable() {
+19 -4
View File
@@ -106,17 +106,32 @@ theme_enable() {
# SteamOS panel, launcher icon and wallpaper. It needs plasmashell up. # SteamOS panel, launcher icon and wallpaper. It needs plasmashell up.
lookandfeeltool -a "$VAPOR_LOOKANDFEEL" --resetLayout >/dev/null 2>&1 || lookandfeeltool -a "$VAPOR_LOOKANDFEEL" --resetLayout >/dev/null 2>&1 ||
{ err "lookandfeeltool failed."; return 1; } { err "lookandfeeltool failed."; return 1; }
# The new layout has a new launcher, without single user's settings. # The new layout has a new launcher, without single user's settings, and the default taskbar pins.
if single_status; then
sleep 3 sleep 3
stop_plasmashell_for_edit stop_plasmashell_for_edit
single_launcher taskbar_drop_discover
single_status && single_launcher
restart_plasmashell_if_stopped restart_plasmashell_if_stopped
fi
extras_enable || warn "SteamOS desktop extras not installed (see above); the theme itself is on." extras_enable || warn "SteamOS desktop extras not installed (see above); the theme itself is on."
ok "Vapor theme active." ok "Vapor theme active."
} }
taskbar_drop_discover() {
# Plasma's default taskbar pins Discover, which CachyOS doesn't install: the pin shows as a
# blank icon. Pin what CachyOS's own layout pins (/etc/skel) instead. Not when Discover is
# installed, and only on a taskbar that still has the default pins (no launchers key).
# Edit only while plasmashell is stopped.
[[ -e /usr/share/applications/org.kde.discover.desktop ]] && return 0
local applet grp
for applet in $(plasma_applets org.kde.plasma.icontasks); do
grp="Containments|${applet%%:*}|Applets|${applet#*:}|Configuration|General"
[[ -n "$(kreadconfig6 --file plasma-org.kde.plasma.desktop-appletsrc --group Containments --group "${applet%%:*}" \
--group Applets --group "${applet#*:}" --group Configuration --group General --key launchers)" ]] && continue
kset theme plasma-org.kde.plasma.desktop-appletsrc "$grp" launchers \
'applications:systemsettings.desktop,preferred://filemanager,preferred://browser'
done
}
theme_disable() { theme_disable() {
extras_disable extras_disable
info "Restoring the previous desktop look and layout..." info "Restoring the previous desktop look and layout..."
+1 -1
View File
@@ -11,6 +11,6 @@ in the shell code.
|---|---|---| |---|---|---|
| `steamify-boot-desktop.service` | `lib/boot-session.sh` (Boot into: desktop) | Sets the Plasma session before the login manager starts | | `steamify-boot-desktop.service` | `lib/boot-session.sh` (Boot into: desktop) | Sets the Plasma session before the login manager starts |
| `sync-steamos-session.path`, `.service` | `lib/login-manager.sh` (SteamOS conversion, plasma-login-manager) | The sync bridge: copies Steam's session choice into `plasmalogin.conf` | | `sync-steamos-session.path`, `.service` | `lib/login-manager.sh` (SteamOS conversion, plasma-login-manager) | The sync bridge: copies Steam's session choice into `plasmalogin.conf` |
| `steam-desktop-autostart.service` | `lib/steam-desktop.sh` (SteamOS conversion) | Steam in the background on the Plasma desktop (user unit) | | `steamify-steam-autostart.service` | `lib/nvidia.sh` (Gaming on NVIDIA) | Steam at login on the Plasma desktop, normal or in Big Picture (user unit) |
| `ensure-kernel-headers.service` | `lib/steam-machine.sh` (Steam Machine support) | Installs missing kernel headers at boot, so DKMS builds for every kernel | | `ensure-kernel-headers.service` | `lib/steam-machine.sh` (Steam Machine support) | Installs missing kernel headers at boot, so DKMS builds for every kernel |
| `steamify-update-check.service`, `.timer` | `lib/update-notifier.sh` (Update notifications) | The daily and login check for a new release (user units) | | `steamify-update-check.service`, `.timer` | `lib/update-notifier.sh` (Update notifications) | The daily and login check for a new release (user units) |
@@ -1,13 +1,13 @@
[Unit] [Unit]
Description=Steam Background Autostart for Virtual Keyboard Description=Steam at login (Steamify, NVIDIA PCs)
After=graphical-session.target After=graphical-session.target
PartOf=graphical-session.target PartOf=graphical-session.target
[Service] [Service]
Type=simple Type=simple
# Only in the Plasma desktop session; gamescope-session starts its own Steam. # Only in the Plasma desktop session.
ExecCondition=/bin/sh -c '[ "$XDG_CURRENT_DESKTOP" = KDE ]' ExecCondition=/bin/sh -c '[ "$XDG_CURRENT_DESKTOP" = KDE ]'
ExecStart=/usr/bin/steam -silent ExecStart=/usr/bin/steam @ARGS@
Restart=on-failure Restart=on-failure
RestartSec=5 RestartSec=5
+2 -2
View File
@@ -15,11 +15,11 @@
set -uo pipefail set -uo pipefail
# Release version, see CHANGELOG.md. # Release version, see CHANGELOG.md.
VERSION=2.9.7 VERSION=2.11.1
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
for lib in common state packages login-manager single-user steam-desktop steam-machine fremont-poweroff vram-booster hdmi-refresh nvidia cec boot-session vapor-theme steamos-extras bios desktop-shortcut wizard-shortcut steam-game update-notifier first-login menu backend; do for lib in common state packages login-manager single-user steam-desktop steam-machine fremont-poweroff vram-booster hdmi-refresh nvidia controllers cec boot-session vapor-theme steamos-extras bios desktop-shortcut wizard-shortcut steam-game update-notifier first-login menu backend; do
# shellcheck source=/dev/null # shellcheck source=/dev/null
source "$SCRIPT_DIR/lib/$lib.sh" source "$SCRIPT_DIR/lib/$lib.sh"
done done
-93
View File
@@ -1,93 +0,0 @@
#!/bin/bash
# Test of the NVIDIA fix on a real PC with an NVIDIA GPU (the unit test fakes
# one: tests/nvidia-test.sh). Run from the Steamify checkout:
# bash tests/nvidia-hardware-test.sh check read-only: what is detected, what the live kernel uses, what apply would change
# bash tests/nvidia-hardware-test.sh apply really applies the fix (sudo), then reboot and run check again
# bash tests/nvidia-hardware-test.sh visual after trying gaming mode: was the picture clean? (asks you)
# 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/vram-booster.sh; source lib/nvidia.sh
mode="${1:-check}"
fail=0
say() { echo "$*" | tee -a "$REPORT"; }
pass() { say "PASS $*"; }
bad() { say "FAIL $*"; fail=1; }
note() { say " $*"; }
root_cat() { cat "$1" 2>/dev/null || sudo cat "$1" 2>/dev/null || echo "(unreadable)"; }
say ""; say "===== $(date '+%F %T') mode=$mode kernel=$(uname -r)"
report_system() {
say "-- GPU and software"
lspci -nn 2>/dev/null | grep -iE 'vga|3d|display' | while read -r l; do note "$l"; done
command -v nvidia-smi >/dev/null && note "driver: $(nvidia-smi --query-gpu=name,driver_version --format=csv,noheader 2>&1 | head -n 1)"
for p in nvidia-open nvidia-utils nvidia-dkms gamescope gamescope-session-cachyos linux-cachyos-nvidia-open; do
v="$(pacman -Q "$p" 2>/dev/null)" && note "$v"
done
note "boot loader file: $(nvidia_boot_file || true)"
note "cmdline: $(cat /proc/cmdline)"
}
check_state() {
say "-- Steamify's view"
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"
elif nvidia_param_set "$p"; then bad "$p is in the boot loader's file but not booted yet: reboot"
else bad "$p is missing (run: bash tests/nvidia-hardware-test.sh apply)"; fi
done
say "-- the live NVIDIA driver"
local m
for m in modeset fbdev; do
v="$(root_cat /sys/module/nvidia_drm/parameters/$m)"
if [[ "$v" == Y ]]; then pass "nvidia_drm $m = Y"; else bad "nvidia_drm $m = $v (want Y)"; fi
done
lsmod | grep -q '^nvidia_drm' && pass "nvidia_drm is loaded" || bad "nvidia_drm is not loaded"
local c found=0
for c in /sys/class/drm/card[0-9]*/device; do
[[ "$(cat "$c/vendor" 2>/dev/null)" == 0x10de ]] || continue
found=1; note "NVIDIA card: ${c%/device} driver=$(basename "$(readlink -f "$c/driver" 2>/dev/null)")"
for s in "${c%/device}"/card*-*/status; do [[ -f "$s" ]] && note " $(basename "$(dirname "$s")"): $(cat "$s")"; done
done
[[ $found == 1 ]] || bad "no NVIDIA card in /sys/class/drm"
say "-- initramfs"
if nvidia_modules_everywhere; then note "every installed kernel has nvidia_drm: the early-load drop-in is used"
else note "not every installed kernel has nvidia_drm: the early-load drop-in is skipped (parameters still apply)"; fi
nvidia_initramfs_ok && note "NVIDIA modules are in the initramfs config" || note "NVIDIA modules are not in the initramfs config"
say "-- what apply would change"
if nvidia_params_missing; then note "adds $NVIDIA_PARAMS to $(nvidia_boot_file)"; else note "kernel parameters: nothing to change"; fi
if ! nvidia_initramfs_ok && nvidia_modules_everywhere; then note "writes $NVIDIA_INITRAMFS_CONF"; fi
}
case "$mode" in
check)
report_system; check_state ;;
apply)
report_system
say "-- applying"
if nvidia_enable 2>&1 | tee -a "$REPORT"; [[ ${PIPESTATUS[0]} == 0 ]]; then pass "nvidia_enable finished"
else bad "nvidia_enable failed (output above)"; fi
say "Now reboot, then run: bash tests/nvidia-hardware-test.sh check" ;;
visual)
report_system
say "-- try gaming mode now (log in to it or reboot into it), look at the screen, then answer"
read -rp "Is the gaming mode picture clean (no corruption, no flicker)? [y/n/partly] " a
read -rp "What did you see (one line, e.g. 'garbled colours at start, fine after login')? " what
say "visual result: $a: $what"
[[ "$a" == y ]] && pass "picture clean" || bad "picture not clean ($a)"
say "-- gamescope and NVIDIA lines from this boot's log"
{ journalctl -b --no-pager 2>/dev/null || sudo journalctl -b --no-pager 2>/dev/null; } |
grep -iE 'gamescope|nvidia|drm|nvrm|wlserver|vulkan' | tail -n 80 | tee -a "$REPORT" | tail -n 5
note "(more in $REPORT)" ;;
*) echo "usage: $0 check|apply|visual"; exit 2 ;;
esac
say ""; say "Report: $REPORT"
exit $fail
-88
View File
@@ -1,88 +0,0 @@
#!/bin/bash
# Tests lib/nvidia.sh against a fake RTX 5080 (PCI 10de:2c02) beside an
# Intel iGPU, a stub modinfo, and temp copies of the boot loader files. No
# root, VM or NVIDIA hardware needed: bash tests/nvidia-test.sh
cd "$(dirname "$0")/.." || exit 1
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/vram-booster.sh; source lib/nvidia.sh
sudo() { "$@"; }
info() { :; }; ok() { :; }; warn() { :; }; err() { echo "ERR $*"; }
backup_file() { [[ -f "$1.bak" ]] || cp "$1" "$1.bak"; }
modinfo() { [[ "$FAKE_DRIVER" == 1 ]]; }
REBUILDS=0; nvidia_rebuild_boot() { REBUILDS=$((REBUILDS + 1)); }
NVIDIA_INITRAMFS_CONF="$T/90-steamify-nvidia.conf"
mkdir -p "$T/drm/card0/device" "$T/drm/card1/device"
echo 0x8086 > "$T/drm/card0/device/vendor"; echo 0x030000 > "$T/drm/card0/device/class"
echo 0x10de > "$T/drm/card1/device/vendor"; echo 0x030000 > "$T/drm/card1/device/class"
echo 0x2c02 > "$T/drm/card1/device/device"
NVIDIA_DRM_DIR="$T/drm"
mkdir -p "$T/mods/6.1.0-cachyos/kernel"; : > "$T/mods/6.1.0-cachyos/kernel/nvidia-drm.ko.zst"; : > "$T/mods/6.1.0-cachyos/pkgbase"
NVIDIA_SCRIPT="$T/libexec/steamify-nvidia-initramfs"; NVIDIA_HOOK="$T/hooks/85-steamify-nvidia-initramfs.hook"
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
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"
for loader in limine sdboot grub; do
case $loader in
limine) F="$T/limine"; printf 'KERNEL_CMDLINE[default]="quiet splash"\n' > "$F" ;;
sdboot) F="$T/sdboot-manage.conf"; printf 'LINUX_OPTIONS="quiet splash"\n' > "$F" ;;
grub) F="$T/grub"; printf 'GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"\n' > "$F" ;;
esac
nvidia_boot_file() { echo "$F"; }
rm -f "$NVIDIA_INITRAMFS_CONF"; REBUILDS=0; ORIG="$(cat "$F")"
nvidia_enable
check "$loader: parameters added" 'grep -q "nvidia-drm.modeset=1" "$F" && grep -q "nvidia-drm.fbdev=1" "$F"'
check "$loader: initramfs drop-in written" 'grep -q nvidia_drm "$NVIDIA_INITRAMFS_CONF"'
check "$loader: script and pacman hook installed" '[[ -x "$NVIDIA_SCRIPT" ]] && grep -q "^Exec = $NVIDIA_SCRIPT sync" "$NVIDIA_HOOK"'
check "$loader: backup made, rebuilt once" '[[ -f "$F.bak" && $REBUILDS == 1 ]]'
SUM="$(cat "$F")"; nvidia_enable
check "$loader: second run changes nothing" '[[ "$(cat "$F")" == "$SUM" && $REBUILDS == 1 ]]'
nvidia_disable
check "$loader: disable restores the file, drops the drop-in, script and hook" '[[ "$(cat "$F")" == "$ORIG" && ! -f "$NVIDIA_INITRAMFS_CONF" && ! -e "$NVIDIA_SCRIPT" && ! -e "$NVIDIA_HOOK" ]]'
done
# A missing patches/ file must be an error, never an empty script or hook.
( SCRIPT_DIR="$T/no-patches"; NVIDIA_SCRIPT="$T/empty/script"; NVIDIA_HOOK="$T/empty/hook"; ! nvidia_hook_install 2>/dev/null && [[ ! -s "$T/empty/script" ]] ) && echo "ok a missing patch file is an error, nothing empty installed" || { echo "FAIL a missing patch file is an error, nothing empty installed"; fail=1; }
# The pacman hook's script decides again at every kernel change.
syncit() { NVIDIA_INITRAMFS_CONF="$NVIDIA_INITRAMFS_CONF" NVIDIA_MODULES_DIR="$NVIDIA_MODULES_DIR" bash "$NVIDIA_SCRIPT" sync; }
nvidia_hook_install; rm -f "$NVIDIA_INITRAMFS_CONF"
syncit; check "hook script: every kernel has the modules -> drop-in written" '[[ -f "$NVIDIA_INITRAMFS_CONF" ]]'
mkdir -p "$T/mods/6.6.0-lts/kernel"; : > "$T/mods/6.6.0-lts/pkgbase"
syncit; check "hook script: a new kernel without modules -> drop-in removed" '[[ ! -f "$NVIDIA_INITRAMFS_CONF" ]]'
: > "$T/mods/6.6.0-lts/kernel/nvidia-drm.ko.zst"
syncit; check "hook script: the modules arrive (DKMS built) -> drop-in back" '[[ -f "$NVIDIA_INITRAMFS_CONF" ]]'
rm -rf "$T/mods/6.6.0-lts"; mkdir -p "$T/mods/5.0.0-leftover"; : > "$T/mods/5.0.0-leftover/modules.dep"
syncit; check "hook script: a leftover folder of a removed kernel is ignored" '[[ -f "$NVIDIA_INITRAMFS_CONF" ]]'
rm -rf "$T/mods/5.0.0-leftover"; nvidia_disable
# A second kernel without the NVIDIA modules: no early-load drop-in, parameters still set.
mkdir -p "$T/mods/6.6.0-lts/kernel"; : > "$T/mods/6.6.0-lts/pkgbase"; F="$T/sdboot-manage.conf"; printf 'LINUX_OPTIONS="quiet"\n' > "$F"
nvidia_boot_file() { echo "$F"; }; rm -f "$NVIDIA_INITRAMFS_CONF"; REBUILDS=0; nvidia_enable
check "kernel without nvidia modules: no drop-in, parameters set" '[[ ! -f "$NVIDIA_INITRAMFS_CONF" ]] && grep -q "nvidia-drm.fbdev=1" "$F"'
rm -rf "$T/mods/6.6.0-lts"
# Generated boot entries without the parameters (the initramfs build failed): an error.
printf 'linux /vmlinuz root=/dev/sda1\n' > "$T/grub.cfg"; NVIDIA_GRUB_CFG="$T/grub.cfg"
F="$T/grub"; printf 'GRUB_CMDLINE_LINUX_DEFAULT="quiet"\n' > "$F"; nvidia_boot_file() { echo "$F"; }; rm -f "$NVIDIA_INITRAMFS_CONF"
check "boot entries without the parameters: error" '! nvidia_enable >/dev/null'
NVIDIA_GRUB_CFG="$T/none/grub.cfg"
# A config file without the setting to edit: an error, not "applied".
F="$T/sdboot-manage.conf"; printf '#LINUX_OPTIONS=""\n' > "$F"; nvidia_boot_file() { echo "$F"; }; REBUILDS=0
check "no setting to edit: error, nothing rebuilt" '! nvidia_enable >/dev/null && [[ $REBUILDS == 0 ]]'
FAKE_DRIVER=0; printf 'LINUX_OPTIONS="quiet"\n' > "$T/sdboot"; F="$T/sdboot"; REBUILDS=0; nvidia_enable
check "no NVIDIA driver: nothing touched" '[[ "$(cat "$F")" == "LINUX_OPTIONS=\"quiet\"" && $REBUILDS == 0 ]]'
exit $fail
+14 -4
View File
@@ -38,7 +38,9 @@ Item {
readonly property var status: backend.status || ({}) readonly property var status: backend.status || ({})
readonly property var items: status.items || [] readonly property var items: status.items || []
readonly property var rows: items.filter(function (i) { return !i.parent || want[i.parent]; }) // Hidden: Big Picture excludes a silent start.
function hidden(i) { return i.id === "nvsilent" && want.bigpicture; }
readonly property var rows: items.filter(function (i) { return (!i.parent || want[i.parent]) && !hidden(i); })
readonly property var bios: status.bios || null readonly property var bios: status.bios || null
signal passwordRequested() signal passwordRequested()
@@ -75,8 +77,15 @@ Item {
var w = Object.assign({}, want); var w = Object.assign({}, want);
w[id] = !w[id]; w[id] = !w[id];
// The same rules as the terminal menu (toggle_component). // The same rules as the terminal menu (toggle_component).
if (id === "gaming" && !w.gaming) w.single = false; var hasGaming = items.some(function (i) { return i.id === "gaming"; });
if (id === "single" && w.single) w.gaming = true; if (id === "gaming" && !w.gaming) { w.single = false; w.silent = false; w.glyphs = false; }
if (id === "single" && w.single && hasGaming) w.gaming = true;
if (id === "nvidia") w.bigpicture = w.nvidia;
if (id === "bigpicture" && w.bigpicture) { w.nvidia = true; w.nvsilent = false; }
if (id === "nvsilent" && w.nvsilent) { w.nvidia = true; w.bigpicture = false; }
if (id === "nvidia" && !w.nvidia) w.nvsilent = false;
if (id === "silent" && w.silent) w.gaming = true;
if (id === "glyphs" && w.glyphs) w.gaming = true;
if (id === "machine") w.poweroff = w.machine; if (id === "machine") w.poweroff = w.machine;
if (id === "poweroff" && w.poweroff) w.machine = true; if (id === "poweroff" && w.poweroff) w.machine = true;
if (id === "machine" && !w.machine) w.kpin = false; if (id === "machine" && !w.machine) w.kpin = false;
@@ -90,6 +99,7 @@ Item {
for (var i = 0; i < items.length; i++) { for (var i = 0; i < items.length; i++) {
var it = items[i]; var it = items[i];
if (it.kind !== "toggle") continue; if (it.kind !== "toggle") continue;
if (hidden(it)) { if (it.on) p.push({ id: it.id, action: "off" }); continue; }
if (it.parent && !want[it.parent]) { if (it.on) p.push({ id: it.id, action: "off" }); continue; } if (it.parent && !want[it.parent]) { if (it.on) p.push({ id: it.id, action: "off" }); continue; }
if (want[it.id] && !it.on) p.push({ id: it.id, action: "on", isNew: !!it["new"] }); if (want[it.id] && !it.on) p.push({ id: it.id, action: "on", isNew: !!it["new"] });
else if (!want[it.id] && it.on) p.push({ id: it.id, action: "off" }); else if (!want[it.id] && it.on) p.push({ id: it.id, action: "off" });
@@ -106,7 +116,7 @@ Item {
function wantedIds() { function wantedIds() {
var ids = []; var ids = [];
for (var i = 0; i < items.length; i++) for (var i = 0; i < items.length; i++)
if (items[i].kind === "toggle" && want[items[i].id] && (!items[i].parent || want[items[i].parent])) ids.push(items[i].id); if (items[i].kind === "toggle" && want[items[i].id] && !hidden(items[i]) && (!items[i].parent || want[items[i].parent])) ids.push(items[i].id);
return ids; return ids;
} }
+16 -1
View File
@@ -6,10 +6,22 @@ QtObject {
readonly property var items: ({ readonly property var items: ({
gaming: { label: "SteamOS conversion", hint: "Boot into gaming mode, Steam on the desktop", gaming: { label: "SteamOS conversion", hint: "Boot into gaming mode, Steam on the desktop",
body: "Boots straight into gaming mode. Switch to Desktop in Steam works, and Return to Gaming Mode on the desktop brings you back.", body: "Boots straight into gaming mode. Switch to Desktop in Steam works, and Return to Gaming Mode on the desktop brings you back.",
changes: ["Autologin into gamescope", "Return to Gaming Mode shortcut", "Steam starts silently on the desktop"] }, changes: ["Autologin into gamescope", "Return to Gaming Mode shortcut"] },
boot: { label: "Boot into", hint: "Where the PC starts", boot: { label: "Boot into", hint: "Where the PC starts",
body: "Where the PC starts after a restart. Switching back and forth works the same either way.", body: "Where the PC starts after a restart. Switching back and forth works the same either way.",
changes: ["Desktop: the Plasma session is set before login", "Gaming: the SteamOS default"] }, changes: ["Desktop: the Plasma session is set before login", "Gaming: the SteamOS default"] },
silent: { label: "Start Steam silently in desktop mode", hint: "In the tray at login on the desktop, no window",
body: "Steam starts by itself when you log in to the Plasma desktop, in the tray without a window. Gaming mode starts its own Steam.",
changes: ["Steam is started with -silent (a systemd user service, desktop only)", "Off: the service is removed again"] },
nvidia: { label: "Gaming on NVIDIA", hint: "Steam on the desktop, started at login",
body: "gamescope's own gaming mode shows a corrupted picture on NVIDIA graphics cards (an open NVIDIA driver bug), so it isn't offered here. This puts Steam on the Plasma desktop instead and starts it when you log in.",
changes: ["Steam is installed when it's missing", "Steam starts at login (a systemd user service)", "Off: the service is removed again; Steam is only removed if Steamify installed it"] },
bigpicture: { label: "Steam starts in Big Picture", hint: "The controller-friendly Steam, or the normal window",
body: "Steam opens in Big Picture at login, which works well with a controller on the TV. Untick it for Steam's normal window.",
changes: ["Steam is started with -gamepadui", "Plasma starts with an empty session, so old windows don't cover Big Picture", "Off: Steam starts in its normal window"] },
nvsilent: { label: "Start Steam silently", hint: "In the tray at login, no window",
body: "Steam starts in the tray at login without a window. Not together with Big Picture: ticking one unticks the other.",
changes: ["Steam is started with -silent", "Off: Steam starts in its normal window"] },
theme: { label: "SteamOS theme", hint: "Vapor look for the desktop, Add to Steam", theme: { label: "SteamOS theme", hint: "Vapor look for the desktop, Add to Steam",
body: "The Vapor look of SteamOS for the desktop, with its panel, launcher icon and wallpaper.", body: "The Vapor look of SteamOS for the desktop, with its panel, launcher icon and wallpaper.",
changes: ["cachyos-vapor global theme", "Add to Steam in right-click menus", "Nested Desktop, Steam keyboard window rule"] }, changes: ["cachyos-vapor global theme", "Add to Steam in right-click menus", "Nested Desktop, Steam keyboard window rule"] },
@@ -27,6 +39,9 @@ QtObject {
notify: { label: "Update notifications", hint: "A notification when there's a new Steamify", notify: { label: "Update notifications", hint: "A notification when there's a new Steamify",
body: "Checks once a day and when you log in to the desktop. When there's a new Steamify you get a notification and a tray icon: open the app to see what's new and choose what to update, or skip that version. It never updates anything by itself.", body: "Checks once a day and when you log in to the desktop. When there's a new Steamify you get a notification and a tray icon: open the app to see what's new and choose what to update, or skip that version. It never updates anything by itself.",
changes: ["A daily check (systemd user timer), only on the desktop", "Tray icon only while an update is waiting", "Skip this version: quiet until the next one"] }, changes: ["A daily check (systemd user timer), only on the desktop", "Tray icon only while an update is waiting", "Skip this version: quiet until the next one"] },
extended_controller_support: { label: "Extended controller support", hint: "Xbox wireless dongle, Xbox controllers over Bluetooth",
body: "Drivers for Xbox controllers that Linux doesn't handle well by itself. xone makes the Xbox wireless dongle work (the kernel has no driver for it), xpadneo gives an Xbox controller over Bluetooth rumble including the triggers, the right button mapping and its battery level. They are built for every installed kernel, which takes a minute or two each.",
changes: ["xone (the dongle) with its firmware, and xpadneo (Bluetooth), from the CachyOS repo", "Kernel headers for every installed kernel, so the drivers build for each", "Off: only what Steamify installed is removed again"] },
vram: { label: "VRAM booster", hint: "The game in front keeps its VRAM", vram: { label: "VRAM booster", hint: "The game in front keeps its VRAM",
body: "Like SteamOS 3.9: the game you're playing keeps its video memory, and background apps are moved out first. Without it a game that needs most of the video memory can spill into system RAM and stutter. Shown for GPUs whose driver supports it (AMD, Intel, NVIDIA with its open kernel modules from driver 615) on kernel 7.2 or newer.", body: "Like SteamOS 3.9: the game you're playing keeps its video memory, and background apps are moved out first. Without it a game that needs most of the video memory can spill into system RAM and stutter. Shown for GPUs whose driver supports it (AMD, Intel, NVIDIA with its open kernel modules from driver 615) on kernel 7.2 or newer.",
changes: ["dmemcg-booster (system and user service)", "plasma-foreground-booster, which tells it which window is in front", "Off: removed again, unless you had installed them yourself"] }, changes: ["dmemcg-booster (system and user service)", "plasma-foreground-booster, which tells it which window is in front", "Off: removed again, unless you had installed them yourself"] },