mirror of
https://github.com/theupriser/steamify-cachyos.git
synced 2026-10-13 20:35:40 +02:00
Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9924617a2d | ||
|
|
5da1833a03 | ||
|
|
62cb75d161 |
No files matched your search
@@ -1,2 +0,0 @@
|
|||||||
Not tested on hardware yet: the whole Steamify flow for the patched gamescope on NVIDIA (apply, reboot, session).
|
|
||||||
Delete this file when it was, after asking the user (AGENTS.md).
|
|
||||||
@@ -48,15 +48,11 @@ 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`.
|
||||||
- **NVIDIA** (`lib/gamescope-nvidia.sh`, `lib/nvidia.sh`): since 2.12.0 the SteamOS conversion (`gaming` and its options) runs on
|
- **NVIDIA** (`lib/nvidia.sh`): gamescope's session is broken on NVIDIA, so the SteamOS conversion (`gaming`, `boot`, `single`,
|
||||||
NVIDIA PCs with a patched gamescope (GBM scan-out: gamescope#2309; Steam's UI kept at the display's size), downloaded as the
|
`glyphs`) is hidden there (unless already on) and `nvidia` + its sub-option `bigpicture` ("Gaming on NVIDIA") replace it:
|
||||||
newest release of theupriser/steamify-gamescope-nvidia, with the pinned package (`GSN_VERSION`, `GSN_SHA256`), the copy the ISO
|
Steam on the Plasma desktop, started at login. Never reintroduce a gamescope session for NVIDIA without re-testing on the
|
||||||
leaves, and a build here (`patches/gamescope-nvidia.PKGBUILD` + the two patches) as the fallback. "Gaming on NVIDIA" (`nvidia`,
|
hardware (notes: steamify-cachyos-dev, `nvidia/`). It can't be tested without the hardware: keep the branch behind
|
||||||
`bigpicture`, `nvsilent`) isn't offered any more (`nvidia_available`); turning the conversion on turns it off (`nvidia_swap_out`).
|
`.no-release-yet` until it was.
|
||||||
Builds exist per CPU level (`gsn_cpu_variant`: znver4, v4, v3, generic; `GSN_SHA256` is a map; the installed one must pass `gsn_smoke_test`, else generic). A new pin = the release's tag + each variant's sha256 (from `SHA256SUMS`) in `lib/gamescope-nvidia.sh` and the PKGBUILD's pkgver/pkgrel, copied from the
|
|
||||||
repository (the patches in `patches/` must stay identical to that repository's). Steam must keep running with `-steamos3`
|
|
||||||
(without it games don't launch in gaming mode and the settings pages go): never "fix" the UI size by dropping flags or by
|
|
||||||
`XWAYLAND_COUNT`. Tested on an RTX 5080 only; keep the branch behind `.no-release-yet` until the whole flow ran on hardware.
|
|
||||||
- **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
|
||||||
@@ -160,8 +156,9 @@ 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-steam-machine.png`; NVIDIA PCs get the same menu, so there is no separate
|
README screenshots (`assets/screenshot-menu-steam-machine.png` and
|
||||||
one): the app from the branch on a Steam Machine, every row visible and the window only as tall as its options need, the header showing the new
|
`assets/screenshot-menu-nvidia.png`, side by side in the README): the app from the branch on a Steam Machine and on a PC
|
||||||
|
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
|
`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
|
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).
|
Machine runs at 1.75).
|
||||||
|
|||||||
+1
-30
@@ -5,38 +5,9 @@ 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.12.0 - 2026-10-13
|
|
||||||
|
|
||||||
- **feat: setting up the SteamOS conversion on NVIDIA first checks that nothing blocks it (a pacman lock, less than 1.5 GB free), and a failed setup is remembered: a desktop notification now and a reminder in the menu until a setup works**
|
|
||||||
- **docs: the README and TECHNICAL.md describe NVIDIA as it is now (the SteamOS conversion with the patched gamescope; "Gaming on NVIDIA" only as history); the NVIDIA menu screenshot is gone, NVIDIA PCs get the same menu**
|
|
||||||
- **feat: the patched gamescope comes in one build per CPU level, like CachyOS's repositories (generic, x86-64-v3, v4, znver4): Steamify picks the best one this CPU can run (`gsn_cpu_variant`), falls back to generic, and starts the installed gamescope once headless (`gsn_smoke_test`): a build that doesn't start is replaced by the generic one. CI compiles each with an explicit `-march` (a `-march=native` build died with SIGILL on a Ryzen) and checks the binary for instructions beyond its level.**
|
|
||||||
- **feat: on NVIDIA the gaming session runs on the display's own mode and Steam's interface at its size: a second gamescope patch (`gamescope-ui-native.patch`, release `3.16.31-3` of steamify-gamescope-nvidia, now the pin; built once per CPU level, see below) keeps Steam's UI X server at the output size when Steam (with `-steamos3`) asks for 1920x1080, and a wrapper (`gamescope-display-wrapper.sh`, set up by the conversion with a drop-in of `gamescope-session.service`) starts gamescope on the mode KDE has saved for the connected display, else the biggest mode at the highest refresh rate: before, gaming mode ran at the display's preferred mode (60 Hz on many monitors) with a 1080p Steam UI. Tested on an RTX 5080, 3440x1440@175: widescreen, sharp, a Proton game starts**
|
|
||||||
|
|
||||||
- **fix: on an NVIDIA PC that had single user mode on before the SteamOS conversion, "Return to Gaming Mode" and the boot choice work again: single user mode's desktop autologin (`zzz-steamify-autologin.conf`, read last) pinned the Plasma session; the conversion removes it, and turning the conversion off sets it up again**
|
|
||||||
|
|
||||||
- **fix: when an option fails, its sub-options are not applied any more (a failed conversion used to leave its "Boot into the desktop", silent start and icons on without it)**
|
|
||||||
|
|
||||||
- **fix: a PC that keeps `python-hidapi` (liquidctl needs it) can use the SteamOS conversion: jupiter-hw-support, which gamescope-session-cachyos depends on, wants `python-hid`, which conflicts with it and stopped the package install. Steamify builds and installs an empty placeholder package that provides `python-hid` first (`patches/python-hid-shim.PKGBUILD`); only the Steam Deck controller firmware updater uses it**
|
|
||||||
|
|
||||||
- **feat: the patched gamescope is downloaded as the newest release of steamify-gamescope-nvidia (checked against that release's `.sha256`), a newer one than the installed package shows the SteamOS conversion as an update, and what this Steamify was tested with is the fallback: the pinned package (sha256 in Steamify), the copy the ISO leaves, a build here; the repository's workflow builds each release in CachyOS's container**
|
|
||||||
|
|
||||||
- `124b424`, `f234c72` **fix: HDMI-CEC on the Steam Machine no longer needs GitHub: when downloading Valve's CEC driver fails, Steamify uses the copy it carries (`patches/cros-ec-cec.c`), checked against the same pinned sha256**
|
|
||||||
|
|
||||||
- `127b8cf`, `2811ecc`, `f3cd053`, `4325d80`, `03f9e87`, `5b5181f`, `06ffc8b`, `4d60dd2`, `0ba94b2` **feat: the SteamOS conversion is offered on NVIDIA PCs again (GTX 16 / RTX 20 series or newer: Turing and later, the cards NVIDIA's open kernel driver supports): it builds and installs a patched gamescope from the recipe and patch Steamify carries (`patches/`, prepared in [steamify-gamescope-nvidia](https://github.com/theupriser/steamify-gamescope-nvidia); gamescope 3.16.31, so a Steamify release builds the version it was tested with) (GBM-allocated scan-out buffers, NVIDIA's corrupted gaming-mode picture, gamescope#2309; a few minutes to build) and sets `gamescope_drm_gbm_scanout=1` for the session (`lib/gamescope-nvidia.sh`). It replaces "Gaming on NVIDIA", which is not offered any more (the kernel parameters, early modules, suspend memory and the 32-bit libraries come with the conversion on a supported card; a PC that had "Gaming on NVIDIA" on has it turned off when the conversion is turned on). Tested on an RTX 5080 (driver 615.78.08): Steam's gaming UI is clean with it and shows artifacts without. The package is pinned to one gamescope release: updating it is not automatic yet**
|
|
||||||
|
|
||||||
- `ce4bc67` **feat: "Gaming on NVIDIA" also keeps video memory over suspend (`NVreg_PreserveVideoMemoryAllocations=1` in `/etc/modprobe.d/90-steamify-nvidia.conf`, the initramfs is rebuilt), enables `nvidia-suspend`/`nvidia-resume`/`nvidia-hibernate`, and installs `lib32-nvidia-utils` and `lib32-libxkbcommon` (32-bit games, the 32-bit MangoHud preload) on a supported card; off removes only what Steamify added. Untested on hardware yet**
|
|
||||||
|
|
||||||
## 2.11.1 - 2026-10-02
|
|
||||||
|
|
||||||
- `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**
|
|
||||||
## 2.11.0 - 2026-10-01
|
## 2.11.0 - 2026-10-01
|
||||||
|
|
||||||
- `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**
|
- `5da1833` **feat: "Start Steam silently" sub-option: under the SteamOS conversion (`silent`, on by default, as before) and under Gaming on NVIDIA (`nvsilent`, opt-in, not together with Big Picture); on a Steam Machine only when it boots into the desktop**
|
||||||
- `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`**
|
|
||||||
- `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
|
## 2.10.0 - 2026-10-01
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,14 @@
|
|||||||
# Steamify CachyOS
|
# Steamify CachyOS
|
||||||
|
|
||||||
The Steamify app's menu, on a Steam Machine. On a PC with an NVIDIA graphics card (GTX 16 / RTX 20 series or
|
The Steamify app's menu. On a Steam Machine (or any PC with an AMD or Intel
|
||||||
newer) the same SteamOS conversion is offered; Steamify installs a patched gamescope for it.
|
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 |
|
||||||
|
|---|---|
|
||||||
|
|  |  |
|
||||||
|
|
||||||
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
|
||||||
@@ -22,28 +27,20 @@ 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** (GTX 16 / RTX 20 series or newer): stock gamescope shows a corrupted
|
- **NVIDIA graphics cards:** gamescope's gaming mode shows a corrupted
|
||||||
picture on them (an open NVIDIA driver bug), so on an NVIDIA PC Steamify installs a **patched gamescope**
|
picture there (an open NVIDIA driver bug), so the conversion isn't
|
||||||
(GBM scan-out, from [steamify-gamescope-nvidia](https://github.com/theupriser/steamify-gamescope-nvidia))
|
offered. **Gaming on NVIDIA** takes its place: Steam on the desktop,
|
||||||
and sets up the rest: the gaming session starts on the monitor's own resolution and refresh rate, with
|
installed if it's missing and started at login, in **Big Picture** or its
|
||||||
Steam's interface at that size. It is the same conversion as everywhere else, with one extra step.
|
normal window as you choose
|
||||||
The newest patched build for your CPU is downloaded from GitHub (checked, with a built-in fallback if GitHub
|
([details](TECHNICAL.md#gaming-on-nvidia)).
|
||||||
can't be reached), and a newer one shows up as an **Update** in the menu. Tested on an RTX 5080 only
|
|
||||||
([details](TECHNICAL.md#nvidia-graphics-cards)).
|
|
||||||
The old **Gaming on NVIDIA** option (Steam on the desktop) is gone: a PC that had it on is moved to the
|
|
||||||
conversion, and keeps starting Steam in Big Picture if that was on.
|
|
||||||
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 (an option of the SteamOS conversion).
|
3. **Steam Deck/Machine icons** - Steam Deck button icons in gaming mode.
|
||||||
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
|
||||||
@@ -54,7 +51,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. Not offered on PCs with an NVIDIA graphics card yet (not tested there).
|
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
|
||||||
@@ -186,18 +183,6 @@ Contributing (or an AI agent)? Read [AGENTS.md](AGENTS.md).
|
|||||||
|
|
||||||
MIT - do whatever you want with it. See [LICENSE.md](LICENSE.md).
|
MIT - do whatever you want with it. See [LICENSE.md](LICENSE.md).
|
||||||
|
|
||||||
### Code from other projects
|
|
||||||
|
|
||||||
Some files in `patches/` are not MIT. They keep their own license, and each file says where it comes from:
|
|
||||||
|
|
||||||
| File | What | License and source |
|
|
||||||
|---|---|---|
|
|
||||||
| `steamify-fremont-poweroff.c` | Kernel module for the Steam Machine's power-off fix. It does what Valve's Steam Machine kernel does for this (clears the S4 wake bit of GPIO pin 18 at probe), but at power-off, for kernels without Valve's change. Valve's kernel: [evlaV/linux-integration](https://github.com/evlaV/linux-integration). | GPL-2.0, like the Linux kernel it is built into |
|
|
||||||
| `cros-ec-cec.c` | Valve's Steam Machine HDMI-CEC driver (ChromeOS EC CEC, Copyright BayLibre; Valve's version of it), at a pinned commit of [evlaV/linux-integration](https://github.com/evlaV/linux-integration). Used when it can't be downloaded. | GPL-2.0+, unmodified (Steamify's `cros-ec-cec-single-port.patch` is applied when it is built) |
|
|
||||||
| `gamescope-gbm-scanout.patch` | GBM scan-out for gamescope on NVIDIA: nine commits of [farnoy/gamescope](https://github.com/farnoy/gamescope) on [ValveSoftware/gamescope](https://github.com/ValveSoftware/gamescope). | gamescope's license (BSD-2-Clause) |
|
|
||||||
| `gamescope-ui-native.patch` | Keeps Steam's interface at the display's size in gamescope on NVIDIA (a small patch after the one above). | gamescope's license (BSD-2-Clause) |
|
|
||||||
| `gamescope-nvidia.PKGBUILD` | The recipe for the patched gamescope package, used only when it can't be downloaded. | MIT, like Steamify |
|
|
||||||
|
|
||||||
## Disclaimer
|
## Disclaimer
|
||||||
|
|
||||||
Steamify CachyOS is an unofficial community project. It is not affiliated
|
Steamify CachyOS is an unofficial community project. It is not affiliated
|
||||||
|
|||||||
+21
-85
@@ -43,7 +43,7 @@ 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** (any PC with it off; on NVIDIA that is before 2.12.0 or after turning it off) nothing else logs in by itself, so single user mode
|
**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
|
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
|
`/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
|
`steam-set-session`'s `zz-steamos-autologin.conf`, which may still say gamescope from an earlier conversion), and drops any
|
||||||
@@ -109,10 +109,8 @@ tools write to the conf.d fragment into the base config.
|
|||||||
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; the sub-option `silent`
|
- `KWIN_IM_SHOW_ALWAYS=1` for the virtual keyboard; the sub-option `silent`
|
||||||
("Start Steam silently in desktop mode", opt-in, always shown) writes
|
("Start Steam silently", on by default) adds a `steam-desktop-autostart`
|
||||||
`~/.config/autostart/steam.desktop` (the system steam.desktop with `-silent` in its Exec line). That is the
|
systemd user service that starts Steam silently in Plasma only;
|
||||||
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.
|
||||||
@@ -126,8 +124,7 @@ 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. It is a sub-option of the SteamOS conversion (`gaming`):
|
file), which makes Steam show Steam Deck button glyphs in gaming mode.
|
||||||
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
|
||||||
|
|
||||||
@@ -227,79 +224,21 @@ DKMS modules, built for every installed kernel, so `install_kernel_headers` (`li
|
|||||||
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
|
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
|
||||||
`xone-dkms`. Status is the three packages being installed. Off removes only what Steamify installed (state
|
`xone-dkms`. Status is the three packages being installed. Off removes only what Steamify installed (state
|
||||||
`extended_controller_support`, `installed_pkgs`); the headers stay. The drivers load when the device shows up: the dongle is
|
`extended_controller_support`, `installed_pkgs`); the headers stay. The drivers load when the device shows up: the dongle is
|
||||||
plugged in again, or the controller reconnected. Its test is in steamify-cachyos-dev (`tests/controllers-test.sh`).
|
plugged in again, or the controller reconnected. `tests/controllers-test.sh` tests it with a stub `pacman`.
|
||||||
|
|
||||||
## NVIDIA graphics cards
|
## Gaming on NVIDIA
|
||||||
|
|
||||||
**The problem.** gamescope's gaming mode shows a corrupted picture on NVIDIA graphics cards: NVIDIA's open bug 5240452 (flicker
|
gamescope's own gaming mode shows a corrupted picture on NVIDIA graphics cards: NVIDIA's open bug 5240452 (flicker and
|
||||||
and artifacts in the DRM session at modes above 2560x1440@120, seen up to driver 595 and on RTX 3070 Ti, 4090, 5090 and 5080; also
|
artifacts in the DRM session at modes above 2560x1440@120, seen up to driver 595 and on RTX 3070 Ti, 4090, 5090 and 5080;
|
||||||
[gamescope#2309](https://github.com/ValveSoftware/gamescope/issues/2309)). The kernel parameters `nvidia-drm.modeset=1`/`fbdev=1`
|
no fix known). The kernel parameters `nvidia-drm.modeset=1`/`fbdev=1` and loading the NVIDIA modules early don't change it
|
||||||
and loading the NVIDIA modules early don't change it, and gamescope nested inside KDE artifacts too.
|
(the driver already reports both `Y`), and gamescope started nested inside KDE artifacts too when KWin hands its fullscreen
|
||||||
|
window straight to the display. What does work on an RTX 5080: Steam's Big Picture (`steam -gamepadui`) as a normal window of
|
||||||
|
the Plasma desktop session, smooth and clean.
|
||||||
|
|
||||||
**The fix.** gamescope with GBM-allocated scan-out buffers, opt-in through the environment variable
|
So with an NVIDIA GPU (PCI vendor 0x10de, display class, its driver providing `nvidia_drm`: `nvidia_present`) the SteamOS
|
||||||
`gamescope_drm_gbm_scanout=1`. The patch is nine commits of [farnoy/gamescope](https://github.com/farnoy/gamescope)
|
conversion (`gaming`, and its options `boot`, `single`, `glyphs`) isn't offered, unless it is already on (so it can be turned
|
||||||
(`nvidia-gbm-wayland`). A second small patch keeps Steam's UI server (Steam with `-steamos3` asks gamescope for 1920x1080) at the
|
off). `nvidia` ("Gaming on NVIDIA", `lib/nvidia.sh`) takes its place, hidden while the conversion is on (both would start
|
||||||
display's size. Both are built into one package, `steamify-gamescope-nvidia` (it provides and conflicts with `gamescope`), in
|
Steam at login): it installs `steam` when missing (recorded in state `nvidia`, removed again only then) and enables the user
|
||||||
[theupriser/steamify-gamescope-nvidia](https://github.com/theupriser/steamify-gamescope-nvidia): the patches, the PKGBUILD, and CI.
|
|
||||||
Tested on an RTX 5080 (driver 615.78.08, 3440x1440@175): clean picture, widescreen and sharp Steam UI, Proton games start.
|
|
||||||
Everything below is `lib/gamescope-nvidia.sh` unless named otherwise.
|
|
||||||
|
|
||||||
**What the SteamOS conversion does on an NVIDIA PC** (`gaming_enable` calls `gsn_enable`; `nvidia_present`: PCI vendor 0x10de,
|
|
||||||
display class, its driver providing `nvidia_drm`; `nvidia_supported`: GTX 16 / RTX 20 series or newer, Turing and later):
|
|
||||||
1. `gsn_preflight`: no pacman lock, at least 1.5 GB free on `/`. A failure stops before anything changes.
|
|
||||||
2. `nvidia_swap_out`: turns "Gaming on NVIDIA" off if it was on (see below).
|
|
||||||
3. On a supported card the kernel parameters, early modules, suspend memory and 32-bit libraries (`nvidia_kernel_enable`,
|
|
||||||
`nvidia_extras_enable`, `lib/nvidia.sh`, described below).
|
|
||||||
4. `gsn_install_package`: the patched gamescope (next paragraph).
|
|
||||||
5. `gsn_env_enable`: `gamescope_drm_gbm_scanout=1` in `~/.config/gamescope-session/environment` and
|
|
||||||
`~/.config/environment.d/99-steamify-gamescope-nvidia.conf`.
|
|
||||||
6. `gsn_display_enable`: the display wrapper. `patches/gamescope-display-wrapper.sh` is installed as `gamescope` in Steamify's bin
|
|
||||||
folder and put first in the gaming session's PATH with a drop-in of `gamescope-session.service` (`steamify-display.conf`). It
|
|
||||||
starts gamescope on the mode KDE has saved for the connected display (`~/.config/kwinoutputconfig.json`, modes from
|
|
||||||
`modetest`), else the biggest mode at the highest refresh rate; with several displays connected it passes nothing and gamescope
|
|
||||||
chooses. `--print-args` shows what it would use.
|
|
||||||
7. `single_login_release` (`lib/single-user.sh`): single user mode's `zzz-steamify-autologin.conf` is read last and would pin the
|
|
||||||
Plasma session, so it goes (turning the conversion off sets it up again). `python_hid_shim_ensure` (`lib/packages.sh`): the
|
|
||||||
conversion's dependency jupiter-hw-support wants `python-hid`, which conflicts with `python-hidapi` (liquidctl needs it): an
|
|
||||||
empty package providing `python-hid` (`patches/python-hid-shim.PKGBUILD`) makes both work.
|
|
||||||
Turning the conversion off removes the setting, the wrapper and the kernel settings, and keeps the packages. When the setup
|
|
||||||
fails, `gsn_fail_mark` records it (state `gamescope_nvidia`, key `failed`) and sends a desktop notification; the menu reminds
|
|
||||||
(`gsn_fail_note`) until a setup works. A failed option's sub-options aren't applied.
|
|
||||||
|
|
||||||
**Getting the package, and keeping it current.** gamescope changes every few weeks, so the package is downloaded, not carried.
|
|
||||||
CI builds it in CachyOS's container, once per CPU level like CachyOS's repositories: generic, x86-64-v3, v4 and znver4, each with an
|
|
||||||
explicit `-march` (a `-march=native` build died with SIGILL on a Ryzen) and checked for instructions beyond its level and for both
|
|
||||||
patches. A release is `<gamescope version>-<package release>` (for example `3.16.31-3`) with `SHA256SUMS`. `gsn_cpu_variant`
|
|
||||||
picks the build for this CPU (the dynamic loader's x86-64 level; AMD with `avx512_bf16` is znver4) and generic is the fallback.
|
|
||||||
`gsn_fetch_package` tries, for the CPU's variant and then generic: the newest release on GitHub (if newer than the pin), the release
|
|
||||||
Steamify was tested with (`GSN_VERSION`, hashes in `GSN_SHA256`: from GitHub, the cache, or the copy the ISO leaves in
|
|
||||||
`/usr/local/share/steamify/gamescope`); only files with the expected sha256 count (newer releases: their `.sha256`). If nothing is
|
|
||||||
reachable, `gsn_build_package` builds from `patches/gamescope-nvidia.PKGBUILD` and the two patches (`makepkg` as the user in
|
|
||||||
`~/.cache/steamify`). `gsn_install_package` installs with `pacman -U --ask 4`; `gsn_smoke_test` then starts gamescope headless
|
|
||||||
and installs the generic build instead if it doesn't start. Nothing else changes before a package is installed. A newer release than
|
|
||||||
the installed package shows the conversion as an update (`gsn_update_pending`, looked up at most every six hours, quiet offline).
|
|
||||||
A new pin = the release's tag and each variant's sha256 in `GSN_VERSION` and `GSN_SHA256` plus the PKGBUILD's pkgver/pkgrel; the patches in `patches/` must
|
|
||||||
stay identical to that repository's. New gamescope versions: the repository's daily check bumps the version when the patch still
|
|
||||||
applies, or opens an issue when it needs a rebase; a person merges and tags the release.
|
|
||||||
|
|
||||||
**What the kernel side does** (`lib/nvidia.sh`; a supported card only): `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), 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. The
|
|
||||||
early-load drop-in is only there while every installed kernel has the NVIDIA modules (mkinitcpio fails on a missing module): a
|
|
||||||
pacman hook (`/etc/pacman.d/hooks/85-steamify-nvidia-initramfs.hook`) runs `/usr/local/libexec/steamify-nvidia-initramfs` at every
|
|
||||||
kernel or driver change and decides again. `nvidia_extras_enable` adds `NVreg_PreserveVideoMemoryAllocations=1`
|
|
||||||
(`/etc/modprobe.d/90-steamify-nvidia.conf`), enables `nvidia-suspend`/`resume`/`hibernate` and installs `lib32-nvidia-utils` and
|
|
||||||
`lib32-libxkbcommon`. Takes effect at the next boot. 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).
|
|
||||||
|
|
||||||
**Limits.** Tested on one PC (RTX 5080, Ryzen). The "Add as non-Steam game" option isn't offered on NVIDIA PCs yet. Steam must keep
|
|
||||||
running with `-steamos3` (the Display settings' "Maximum Game Resolution" exists only with it, and dropping it or setting
|
|
||||||
`XWAYLAND_COUNT=1` stopped games from launching). If upstream fixes the bug, the patched package and this section go, and Steamify
|
|
||||||
goes back to the stock gamescope.
|
|
||||||
|
|
||||||
**"Gaming on NVIDIA" (before 2.12.0).** With an NVIDIA GPU the SteamOS conversion (`gaming`, and its options `boot`, `single`, `glyphs`) wasn't offered, unless
|
|
||||||
it was already on. `nvidia` ("Gaming on NVIDIA", `lib/nvidia.sh`) took its place (both would start Steam at login): it installs `steam` when missing (recorded in state `nvidia`, removed again only then) and enables the user
|
|
||||||
unit `steamify-steam-autostart.service` (`services/`, `ExecStart=/usr/bin/steam @ARGS@`, Plasma only). Its sub-option
|
unit `steamify-steam-autostart.service` (`services/`, `ExecStart=/usr/bin/steam @ARGS@`, Plasma only). Its sub-option
|
||||||
`bigpicture` ("Steam starts in Big Picture", ticked along with it) rewrites the unit with `-gamepadui` and sets
|
`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
|
`ksmserverrc [General] loginMode=emptySession` (`kset`, undone with `krevert bigpicture`), so windows of the last session
|
||||||
@@ -317,7 +256,7 @@ and boot entries are rebuilt and checked for the parameters. The early-load drop
|
|||||||
has the NVIDIA modules (mkinitcpio fails on a missing module, and `limine-mkinitcpio` then skips that kernel's boot entry):
|
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
|
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
|
`/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).
|
all of it. `tests/nvidia-hardware-test.sh check|apply|visual` is for a real NVIDIA PC (writes `~/steamify-nvidia-report.txt`). `tests/nvidia-test.sh` tests it against a fake GPU, a stub `pacman` and `systemctl`, and a temp home.
|
||||||
|
|
||||||
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`
|
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);
|
command shadowed in `/usr/local/bin`, and showed the desktop for a few seconds, then a Steam window with a black border);
|
||||||
@@ -405,7 +344,8 @@ 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 (`steam -silent`). That's refused in gaming
|
closed (`steam -shutdown`) for the edit and started again (through
|
||||||
|
`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
|
||||||
@@ -550,8 +490,7 @@ 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/autostart/steam.desktop` | the `silent` option (Steam's "Run Steam when my computer starts") |
|
| `~/.config/systemd/user/` | `steamify-update-check.*`, `steam-desktop-autostart.service` |
|
||||||
| `~/.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
|
||||||
@@ -597,9 +536,7 @@ 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`). The same step (and the online theme path) replaces Plasma's default taskbar pins, which include Discover
|
Plasma session waits for the first login (`lib/first-login.sh`).
|
||||||
(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
|
||||||
@@ -630,7 +567,6 @@ immediately, which can turn into a loop - see
|
|||||||
| `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/controllers.sh` | Extended controller support: Xbox wireless dongle (xone) and Xbox Bluetooth (xpadneo) from the CachyOS repo |
|
| `lib/controllers.sh` | Extended controller support: Xbox wireless dongle (xone) and Xbox Bluetooth (xpadneo) from the CachyOS repo |
|
||||||
| `lib/gamescope-nvidia.sh` | gamescope on NVIDIA: builds and installs the patched gamescope (GBM scan-out) from steamify-gamescope-nvidia and sets `gamescope_drm_gbm_scanout=1` for the SteamOS conversion |
|
|
||||||
| `lib/nvidia.sh` | Gaming on NVIDIA: Steam on the desktop, started at login, optionally in Big Picture (replaces the SteamOS conversion there) |
|
| `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 |
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 225 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 322 KiB After Width: | Height: | Size: 465 KiB |
+5
-9
@@ -50,7 +50,7 @@ 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+=",\"needs\":$(json_str "$([[ "$c" == silent ]] && silent_needs_boot && echo boot)")"
|
||||||
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)"
|
||||||
@@ -147,6 +147,7 @@ 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.
|
||||||
|
# (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
|
[[ "${WANTED[single]:-0}" == 1 ]] && component_available gaming && WANTED[gaming]=1
|
||||||
if component_available gaming; then
|
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; }
|
||||||
@@ -157,8 +158,8 @@ backend_apply() {
|
|||||||
[[ "${WANTED[nvsilent]:-0}" == 1 ]] && WANTED[nvidia]=1
|
[[ "${WANTED[nvsilent]:-0}" == 1 ]] && WANTED[nvidia]=1
|
||||||
[[ "${WANTED[bigpicture]:-0}" == 1 ]] && WANTED[nvsilent]=0
|
[[ "${WANTED[bigpicture]:-0}" == 1 ]] && WANTED[nvsilent]=0
|
||||||
[[ "${WANTED[nvidia]:-0}" == 0 ]] && { WANTED[bigpicture]=0; 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[silent]:-0}" == 1 ]] && component_available gaming && WANTED[gaming]=1
|
||||||
[[ "${WANTED[gaming]:-0}" == 0 ]] && { WANTED[silent]=0; WANTED[glyphs]=0; }
|
[[ "${WANTED[gaming]:-0}" == 0 ]] && WANTED[silent]=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
|
||||||
@@ -166,6 +167,7 @@ backend_apply() {
|
|||||||
# Retired: only ever removed.
|
# Retired: only ever removed.
|
||||||
WANTED[hdmi]=0
|
WANTED[hdmi]=0
|
||||||
case "$boot" in desktop) WANTED[boot]=1; WANTED[gaming]=1 ;; gamescope) WANTED[boot]=0 ;; esac
|
case "$boot" in desktop) WANTED[boot]=1; WANTED[gaming]=1 ;; gamescope) WANTED[boot]=0 ;; esac
|
||||||
|
silent_normalize
|
||||||
|
|
||||||
REAPPLY=$reapply
|
REAPPLY=$reapply
|
||||||
plan_changes
|
plan_changes
|
||||||
@@ -185,12 +187,6 @@ backend_apply() {
|
|||||||
if backend_run_component "$c" disable; then feature_record "$c" disable; else failed+=("$c"); fi
|
if backend_run_component "$c" disable; then feature_record "$c" disable; else failed+=("$c"); fi
|
||||||
done
|
done
|
||||||
for c in "${TO_ENABLE[@]}"; do
|
for c in "${TO_ENABLE[@]}"; do
|
||||||
# A sub-option of something that just failed isn't applied: it would be left on without its parent.
|
|
||||||
if [[ -n "${PARENT[$c]:-}" && " ${failed[*]:-} " == *" ${PARENT[$c]} "* ]]; then
|
|
||||||
backend_event log "\"id\":$(json_str "$c"),\"line\":$(json_str "Skipped: ${LABEL[${PARENT[$c]}]%%:*} didn't work.")"
|
|
||||||
failed+=("$c")
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
if backend_run_component "$c" enable; then is_action "$c" || feature_record "$c" enable; else failed+=("$c"); fi
|
if backend_run_component "$c" enable; then is_action "$c" || feature_record "$c" enable; else failed+=("$c"); fi
|
||||||
done
|
done
|
||||||
feature_record_unticked
|
feature_record_unticked
|
||||||
|
|||||||
+4
-9
@@ -73,16 +73,11 @@ cec_driver_enable() {
|
|||||||
cp "$CEC_DRIVER_CACHE" "$tmp/cros-ec-cec.c"
|
cp "$CEC_DRIVER_CACHE" "$tmp/cros-ec-cec.c"
|
||||||
else
|
else
|
||||||
info "Downloading Valve's Steam Machine CEC driver..."
|
info "Downloading Valve's Steam Machine CEC driver..."
|
||||||
if ! curl -fsL --retry 2 --max-time 60 "$CEC_DRIVER_URL" -o "$tmp/cros-ec-cec.c" ||
|
if ! curl -fsL --retry 2 "$CEC_DRIVER_URL" -o "$tmp/cros-ec-cec.c" ||
|
||||||
! echo "$CEC_DRIVER_SHA256 $tmp/cros-ec-cec.c" | sha256sum -c --quiet -; then
|
! echo "$CEC_DRIVER_SHA256 $tmp/cros-ec-cec.c" | sha256sum -c --quiet -; then
|
||||||
# GitHub is down, rate-limits us, or sent something else: Steamify carries the same file (checked the same way).
|
rm -rf "$tmp"
|
||||||
warn "Downloading Valve's CEC driver failed (or its checksum didn't match): using the copy Steamify carries."
|
err "Downloading Valve's CEC driver failed (or its checksum didn't match)."
|
||||||
patch_file cros-ec-cec.c > "$tmp/cros-ec-cec.c"
|
return 1
|
||||||
if ! echo "$CEC_DRIVER_SHA256 $tmp/cros-ec-cec.c" | sha256sum -c --quiet -; then
|
|
||||||
rm -rf "$tmp"
|
|
||||||
err "Steamify's own copy of Valve's CEC driver doesn't match the pinned checksum (a new pin needs a new copy in patches/)."
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
# The name carries the checksum: a newer pin gets its own file, the old one goes.
|
# The name carries the checksum: a newer pin gets its own file, the old one goes.
|
||||||
sudo find "${CEC_DRIVER_CACHE%/*}" -maxdepth 1 -name 'cros-ec-cec-*.c' ! -name "${CEC_DRIVER_CACHE##*/}" -delete 2>/dev/null
|
sudo find "${CEC_DRIVER_CACHE%/*}" -maxdepth 1 -name 'cros-ec-cec-*.c' ! -name "${CEC_DRIVER_CACHE##*/}" -delete 2>/dev/null
|
||||||
|
|||||||
+6
-17
@@ -7,25 +7,13 @@
|
|||||||
|
|
||||||
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
|
||||||
mkdir -p ~/.cache
|
curl -fsSL --max-time 30 "$WIZARD_URL" | bash -s -- --first-login
|
||||||
{ $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
|
||||||
@@ -43,9 +31,10 @@ 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
|
||||||
stop_plasmashell_for_edit
|
if single_status; then
|
||||||
taskbar_drop_discover
|
stop_plasmashell_for_edit
|
||||||
single_status && single_launcher
|
single_launcher
|
||||||
restart_plasmashell_if_stopped
|
restart_plasmashell_if_stopped
|
||||||
|
fi
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
@@ -1,308 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# gamescope's own gaming mode on NVIDIA: a patched gamescope that allocates its scan-out buffers with GBM, which cures
|
|
||||||
# the corrupted picture (https://github.com/ValveSoftware/gamescope/issues/2309). The patch is opt-in: gamescope reads
|
|
||||||
# `gamescope_drm_gbm_scanout=1` from its environment, which is set for the gaming session (gamescope-session's
|
|
||||||
# environment file, and environment.d).
|
|
||||||
#
|
|
||||||
# gamescope changes every few weeks, so the package is not carried but downloaded: the newest release of
|
|
||||||
# https://github.com/theupriser/steamify-gamescope-nvidia (CI builds it in CachyOS's container, a person merges the
|
|
||||||
# version bump), and a newer one than the installed package shows as an update of the SteamOS conversion
|
|
||||||
# (`gsn_update_pending`). What this Steamify release was tested with is the fallback: the pinned package (sha256 below),
|
|
||||||
# a copy that came with the ISO, and last a build here from the recipe and patch in patches/. Simple files that don't change
|
|
||||||
# stay in patches/ and are used as they are.
|
|
||||||
#
|
|
||||||
# Used by the SteamOS conversion (`gaming_enable`/`gaming_disable`) on every NVIDIA PC (`nvidia_present`); the kernel
|
|
||||||
# parameters and the rest of lib/nvidia.sh's setup only on a supported card (`nvidia_supported`): GTX 16 / RTX 20 series or
|
|
||||||
# newer (Turing and later, what NVIDIA's open kernel driver supports). Tested on an RTX 5080 only.
|
|
||||||
# Sourced by steamify.sh; not meant to be run on its own.
|
|
||||||
|
|
||||||
GSN_PKG=steamify-gamescope-nvidia
|
|
||||||
GSN_RELEASES="${GSN_RELEASES:-https://github.com/theupriser/steamify-gamescope-nvidia/releases}"
|
|
||||||
# The package this Steamify release was tested with (patches/gamescope-nvidia.PKGBUILD names the same version): the
|
|
||||||
# fallback. A new pin: the release's tag, the package's sha256, and the PKGBUILD's pkgver/pkgrel.
|
|
||||||
GSN_VERSION=3.16.31-3
|
|
||||||
# One build per CPU level, like CachyOS's repositories: generic is the one every x86-64 PC can run.
|
|
||||||
declare -A GSN_SHA256=(
|
|
||||||
[generic]=4c7995694d2726c356785d9aec12a11c98419b4d2e139617f03bb46c758ced56
|
|
||||||
[v3]=43c6928ca9fa67c063c4e1b993b686145e94e68de1bd46645782d3186779fa2d
|
|
||||||
[v4]=b6d4621e4b98d9aa5c600fe9a5a1cae164fef6bbf93d259fb8a6af666b098f9f
|
|
||||||
[znver4]=60f45da74a0b96d776219f6e6aa22c5d23e48b08233b3fa12b6c4d7aa6812dd9
|
|
||||||
)
|
|
||||||
# Where the ISO leaves a copy of the pinned package, for installs without GitHub.
|
|
||||||
GSN_BACKUP_DIR="${GSN_BACKUP_DIR:-/usr/local/share/steamify/gamescope}"
|
|
||||||
# How long a look at GitHub for a newer release counts (seconds), so opening the menu doesn't ask every time.
|
|
||||||
GSN_CHECK_EVERY="${GSN_CHECK_EVERY:-21600}"
|
|
||||||
GSN_ENV_LINE='gamescope_drm_gbm_scanout=1'
|
|
||||||
GSN_ENV_D="${GSN_ENV_D:-$HOME/.config/environment.d/99-steamify-gamescope-nvidia.conf}"
|
|
||||||
GSN_SESSION_ENV="${GSN_SESSION_ENV:-$HOME/.config/gamescope-session/environment}"
|
|
||||||
|
|
||||||
gsn_package_installed() { pacman -Q "$GSN_PKG" >/dev/null 2>&1; }
|
|
||||||
|
|
||||||
gsn_installed_version() { pacman -Q "$GSN_PKG" 2>/dev/null | awk '{print $2}'; }
|
|
||||||
|
|
||||||
gsn_env_set() { [[ -f "$GSN_ENV_D" ]] && grep -qsx "$GSN_ENV_LINE" "$GSN_SESSION_ENV"; }
|
|
||||||
|
|
||||||
gsn_status() { gsn_package_installed && gsn_env_set; }
|
|
||||||
|
|
||||||
gsn_newer() {
|
|
||||||
# gsn_newer <a> <b>: version a is newer than b (pacman's own comparison).
|
|
||||||
[[ "$(vercmp "$1" "$2" 2>/dev/null)" == 1 ]]
|
|
||||||
}
|
|
||||||
|
|
||||||
gsn_latest_tag() {
|
|
||||||
# The newest release's tag (<gamescope version>-<package release>), from GitHub; nothing when it can't be reached or
|
|
||||||
# there is no release. Follows the redirect of /releases/latest: no API, no rate limit, no JSON. gsn_latest_tag [seconds]
|
|
||||||
local url
|
|
||||||
url="$(curl -fsL --connect-timeout 4 --max-time "${1:-10}" -o /dev/null -w '%{url_effective}' "$GSN_RELEASES/latest" 2>/dev/null)" || return 1
|
|
||||||
url="${url##*/}"
|
|
||||||
[[ "$url" =~ ^[0-9][0-9A-Za-z._]*-[0-9]+$ ]] || return 1
|
|
||||||
echo "$url"
|
|
||||||
}
|
|
||||||
|
|
||||||
gsn_update_pending() {
|
|
||||||
# The patched gamescope is installed and GitHub has a newer release: the menu shows the conversion as an update.
|
|
||||||
# Looked up at most every GSN_CHECK_EVERY seconds (the answer is kept in the state), quickly, and silently when
|
|
||||||
# offline: no network is never a reason to show or hide anything.
|
|
||||||
gsn_package_installed || return 1
|
|
||||||
local now checked latest
|
|
||||||
now="$(date +%s)"; checked="$(state_get gamescope_nvidia checked 0)"
|
|
||||||
if (( now - ${checked:-0} > GSN_CHECK_EVERY )); then
|
|
||||||
state_set gamescope_nvidia checked "$now"
|
|
||||||
latest="$(gsn_latest_tag 5)" && state_set gamescope_nvidia latest "$latest"
|
|
||||||
fi
|
|
||||||
latest="$(state_get gamescope_nvidia latest)"
|
|
||||||
[[ -n "$latest" ]] && gsn_newer "$latest" "$(gsn_installed_version)"
|
|
||||||
}
|
|
||||||
|
|
||||||
gsn_cpu_variant() {
|
|
||||||
# The best build this CPU can run: znver4 (Ryzen 7000/9000: AMD with AVX-512 BF16), v4, v3, else generic. The
|
|
||||||
# dynamic loader knows the CPU level best ("x86-64-v4 (supported, searched)").
|
|
||||||
local help; help="$(/lib64/ld-linux-x86-64.so.2 --help 2>/dev/null)"
|
|
||||||
if grep -q 'x86-64-v4 (supported' <<< "$help"; then
|
|
||||||
if grep -q AuthenticAMD /proc/cpuinfo && grep -qw avx512_bf16 /proc/cpuinfo; then echo znver4; else echo v4; fi
|
|
||||||
elif grep -q 'x86-64-v3 (supported' <<< "$help"; then echo v3
|
|
||||||
else echo generic; fi
|
|
||||||
}
|
|
||||||
|
|
||||||
gsn_sha_of() {
|
|
||||||
# The hash a release file is expected to have: the pinned one for the pinned version, else the .sha256 next to the
|
|
||||||
# package in the same release (it shows the download wasn't damaged, not who made it). gsn_sha_of <tag> <file> <variant>
|
|
||||||
local tag="$1" file="$2" variant="$3"
|
|
||||||
if [[ "$tag" == "$GSN_VERSION" ]]; then echo "${GSN_SHA256[$variant]}"; return 0; fi
|
|
||||||
curl -fsL --connect-timeout 10 --max-time 30 "$GSN_RELEASES/download/$tag/$file.sha256" 2>/dev/null | awk 'NR==1 {print $1}'
|
|
||||||
}
|
|
||||||
|
|
||||||
gsn_download() {
|
|
||||||
# gsn_download <tag> <variant>: the release's package, verified, in the cache; prints its path.
|
|
||||||
local tag="$1" variant="$2" cache="${XDG_CACHE_HOME:-$HOME/.cache}/steamify" file want got
|
|
||||||
file="$GSN_PKG-$tag-$variant.pkg.tar.zst"
|
|
||||||
mkdir -p "$cache" || return 1
|
|
||||||
want="$(gsn_sha_of "$tag" "$file" "$variant")"
|
|
||||||
[[ "$want" =~ ^[0-9a-f]{64}$ ]] || return 1
|
|
||||||
if [[ -f "$cache/$file" ]] && [[ "$(sha256sum "$cache/$file" | awk '{print $1}')" == "$want" ]]; then echo "$cache/$file"; return 0; fi
|
|
||||||
curl -fsL --retry 2 --connect-timeout 15 --max-time 300 -o "$cache/$file.part" "$GSN_RELEASES/download/$tag/$file" || { rm -f "$cache/$file.part"; return 1; }
|
|
||||||
got="$(sha256sum "$cache/$file.part" | awk '{print $1}')"
|
|
||||||
if [[ "$got" != "$want" ]]; then rm -f "$cache/$file.part"; return 1; fi
|
|
||||||
mv -f "$cache/$file.part" "$cache/$file"
|
|
||||||
echo "$cache/$file"
|
|
||||||
}
|
|
||||||
|
|
||||||
gsn_fetch_package() {
|
|
||||||
# The package to install, as a path: the build for this CPU, then the generic one, each from the newest release on
|
|
||||||
# GitHub (not older than the pinned one), else the pinned release (GitHub, the cache, or the copy that came with the
|
|
||||||
# ISO). Only files with the expected sha256 count. gsn_fetch_package [variant]
|
|
||||||
local tag pkg v cache="${XDG_CACHE_HOME:-$HOME/.cache}/steamify" file copy
|
|
||||||
local -a variants=("${1:-$(gsn_cpu_variant)}"); [[ "${variants[0]}" == generic ]] || variants+=(generic)
|
|
||||||
tag="$(gsn_latest_tag)" || tag=""
|
|
||||||
for v in "${variants[@]}"; do
|
|
||||||
if [[ -n "$tag" && "$tag" != "$GSN_VERSION" ]] && gsn_newer "$tag" "$GSN_VERSION"; then
|
|
||||||
info "Downloading the newest patched gamescope ($tag, $v)..." >&2
|
|
||||||
if pkg="$(gsn_download "$tag" "$v")"; then echo "$pkg"; return 0; fi
|
|
||||||
warn "Downloading the newest patched gamescope ($tag, $v) failed: trying the version this Steamify was tested with ($GSN_VERSION)." >&2
|
|
||||||
fi
|
|
||||||
info "Downloading the patched gamescope ($GSN_VERSION, $v)..." >&2
|
|
||||||
if pkg="$(gsn_download "$GSN_VERSION" "$v")"; then echo "$pkg"; return 0; fi
|
|
||||||
file="$GSN_PKG-$GSN_VERSION-$v.pkg.tar.zst"
|
|
||||||
for copy in "$GSN_BACKUP_DIR/$file" "$cache/$file"; do
|
|
||||||
if [[ -f "$copy" ]] && [[ "$(sha256sum "$copy" | awk '{print $1}')" == "${GSN_SHA256[$v]}" ]]; then
|
|
||||||
info "Using the copy that came with Steamify: $copy" >&2
|
|
||||||
echo "$copy"; return 0
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
done
|
|
||||||
warn "Downloading the patched gamescope failed (or its checksum didn't match)." >&2
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
gsn_smoke_test() {
|
|
||||||
# The installed gamescope must start (headless, no screen needed): a build that crashes would leave gaming mode in a loop.
|
|
||||||
# It segfaults while shutting down headless (also unpatched builds), so what counts is that it ran the program.
|
|
||||||
timeout 25 gamescope --backend headless -W 640 -H 360 -r 60 -- true 2>&1 | grep -q 'Primary child shut down'
|
|
||||||
}
|
|
||||||
|
|
||||||
gsn_build_package() {
|
|
||||||
# Last resort: builds the pinned package from the recipe and patch Steamify carries (patches/), as the user. It
|
|
||||||
# downloads gamescope's sources (Valve's repository at the PKGBUILD's pkgver, and its submodules) and compiles them: a
|
|
||||||
# few minutes. Prints the package's path.
|
|
||||||
local dir cache="${XDG_CACHE_HOME:-$HOME/.cache}/steamify"
|
|
||||||
info "Building the patched gamescope here instead (a few minutes)..." >&2
|
|
||||||
sudo pacman -S --needed --noconfirm base-devel git >&2 || { err "Installing the build tools failed." >&2; return 1; }
|
|
||||||
# On disk, not /tmp: the installer's chroot has a tmpfs there (RAM), and the build is 1-2 GB.
|
|
||||||
mkdir -p "$cache" && dir="$(mktemp -d -p "$cache" gamescope-build.XXXXXX)" || return 1
|
|
||||||
patch_file gamescope-nvidia.PKGBUILD > "$dir/PKGBUILD" &&
|
|
||||||
patch_file gamescope-gbm-scanout.patch > "$dir/gamescope-gbm-scanout.patch" &&
|
|
||||||
patch_file gamescope-ui-native.patch > "$dir/gamescope-ui-native.patch" || {
|
|
||||||
err "Couldn't write the build files." >&2
|
|
||||||
rm -rf "$dir"; return 1
|
|
||||||
}
|
|
||||||
if ! (cd "$dir" && makepkg -sf --noconfirm --nocheck >&2); then
|
|
||||||
err "Building the patched gamescope failed (see above)." >&2
|
|
||||||
rm -rf "$dir"; return 1
|
|
||||||
fi
|
|
||||||
# Moved out, so the build folder can go.
|
|
||||||
local f built=""
|
|
||||||
for f in "$dir"/"$GSN_PKG"-*.pkg.tar.*; do
|
|
||||||
[[ -e "$f" && "$f" != *-debug-* ]] && { built="$f"; break; }
|
|
||||||
done
|
|
||||||
[[ -n "$built" ]] && mv "$built" "$cache/gamescope-local-build.pkg.tar.zst" || { rm -rf "$dir"; return 1; }
|
|
||||||
rm -rf "$dir"
|
|
||||||
echo "$cache/gamescope-local-build.pkg.tar.zst"
|
|
||||||
}
|
|
||||||
|
|
||||||
gsn_install_package() {
|
|
||||||
# The patched gamescope, newest first, each step only when the one before failed: the newest release from GitHub, the
|
|
||||||
# pinned package (GitHub, cache or the copy that came with the ISO), a build here. A package that downloaded fine but
|
|
||||||
# doesn't install (its libraries differ from this PC's) goes on to the next step too. Nothing else changes before one of
|
|
||||||
# them is installed, so a failure leaves the PC as it was, with what it had. --ask 4 lets pacman replace the stock
|
|
||||||
# gamescope it conflicts with, and an older patched one.
|
|
||||||
local pkg latest have
|
|
||||||
have="$(gsn_installed_version)"
|
|
||||||
latest="$(gsn_latest_tag)" || latest=""
|
|
||||||
# Already the newest (or, offline, the pinned version or newer): nothing to do.
|
|
||||||
if [[ -n "$have" ]]; then
|
|
||||||
if [[ -n "$latest" ]] && ! gsn_newer "$latest" "$have"; then return 0; fi
|
|
||||||
if [[ -z "$latest" ]] && ! gsn_newer "$GSN_VERSION" "$have"; then return 0; fi
|
|
||||||
fi
|
|
||||||
if pkg="$(gsn_fetch_package)" && sudo pacman -U --noconfirm --ask 4 "$pkg"; then
|
|
||||||
if ! gsn_smoke_test; then
|
|
||||||
warn "The patched gamescope for this CPU doesn't start: installing the generic build instead."
|
|
||||||
pkg="$(gsn_fetch_package generic)" && sudo pacman -U --noconfirm --ask 4 "$pkg" && gsn_smoke_test ||
|
|
||||||
{ err "The patched gamescope doesn't start on this PC."; return 1; }
|
|
||||||
fi
|
|
||||||
ok "Patched gamescope installed."
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
warn "The ready-made patched gamescope couldn't be installed."
|
|
||||||
[[ -n "$have" ]] && { warn "The installed one ($have) stays."; return 0; }
|
|
||||||
if pkg="$(gsn_build_package)" && sudo pacman -U --noconfirm --ask 4 "$pkg"; then
|
|
||||||
ok "Patched gamescope built and installed."
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
err "The patched gamescope couldn't be installed. The stock gamescope stays."
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
gsn_env_enable() {
|
|
||||||
mkdir -p "$(dirname "$GSN_ENV_D")" "$(dirname "$GSN_SESSION_ENV")"
|
|
||||||
echo "$GSN_ENV_LINE" > "$GSN_ENV_D"
|
|
||||||
touch "$GSN_SESSION_ENV"
|
|
||||||
grep -qsx "$GSN_ENV_LINE" "$GSN_SESSION_ENV" || echo "$GSN_ENV_LINE" >> "$GSN_SESSION_ENV"
|
|
||||||
}
|
|
||||||
|
|
||||||
gsn_env_disable() {
|
|
||||||
rm -f "$GSN_ENV_D"
|
|
||||||
[[ -f "$GSN_SESSION_ENV" ]] && sed -i "/^${GSN_ENV_LINE}\$/d" "$GSN_SESSION_ENV"
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
# --- The session starts gamescope on the display's own mode
|
|
||||||
#
|
|
||||||
# gamescope-session starts gamescope without a size or a refresh rate, so it takes the display's *preferred* mode, which
|
|
||||||
# many monitors declare as 60 Hz while the desktop runs them at their highest. patches/gamescope-display-wrapper.sh (put
|
|
||||||
# first in the gaming session's PATH by a drop-in of gamescope-session.service) starts it on the mode KDE has saved for
|
|
||||||
# the connected display, else the biggest mode at the highest refresh rate, read at every session start.
|
|
||||||
GSN_DISPLAY_WRAPPER="${GSN_DISPLAY_WRAPPER:-$STEAMIFY_BIN/gamescope}"
|
|
||||||
GSN_DISPLAY_DROPIN="${GSN_DISPLAY_DROPIN:-$HOME/.config/systemd/user/gamescope-session.service.d/steamify-display.conf}"
|
|
||||||
|
|
||||||
gsn_display_status() { [[ -x "$GSN_DISPLAY_WRAPPER" && -f "$GSN_DISPLAY_DROPIN" ]]; }
|
|
||||||
|
|
||||||
gsn_display_pending() {
|
|
||||||
# The patched gamescope is in use but the session still starts it on the display's preferred mode: a normal run sets it up.
|
|
||||||
gsn_package_installed && gsn_env_set && ! gsn_display_status
|
|
||||||
}
|
|
||||||
|
|
||||||
gsn_display_enable() {
|
|
||||||
patch_file gamescope-display-wrapper.sh | install_executable "$GSN_DISPLAY_WRAPPER" 755 || return 1
|
|
||||||
mkdir -p "$(dirname "$GSN_DISPLAY_DROPIN")"
|
|
||||||
cat > "$GSN_DISPLAY_DROPIN" << EOF
|
|
||||||
# Steamify: the gaming session starts gamescope on the display's own mode (see lib/gamescope-nvidia.sh). Turning the
|
|
||||||
# SteamOS conversion off removes this file.
|
|
||||||
[Service]
|
|
||||||
ExecStart=
|
|
||||||
ExecStart=/usr/bin/bash -c 'PATH="$(dirname "$GSN_DISPLAY_WRAPPER"):\$PATH" exec /usr/lib/steamos/gamescope-session'
|
|
||||||
EOF
|
|
||||||
user_systemctl daemon-reload
|
|
||||||
}
|
|
||||||
|
|
||||||
gsn_display_disable() {
|
|
||||||
# Only our own files: the wrapper is recognised by its first comment line.
|
|
||||||
grep -qs "^# Steamify: gamescope-session starts gamescope" "$GSN_DISPLAY_WRAPPER" && rm -f "$GSN_DISPLAY_WRAPPER"
|
|
||||||
[[ -f "$GSN_DISPLAY_DROPIN" ]] && rm -f "$GSN_DISPLAY_DROPIN" && rmdir "$(dirname "$GSN_DISPLAY_DROPIN")" 2>/dev/null
|
|
||||||
user_systemctl daemon-reload
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
gsn_preflight() {
|
|
||||||
# Before anything changes: what would make the install fail half way. Prints the reason and fails, or passes.
|
|
||||||
if [[ -e /var/lib/pacman/db.lck ]]; then
|
|
||||||
echo "another package manager is running (/var/lib/pacman/db.lck): finish or close it and try again"; return 1
|
|
||||||
fi
|
|
||||||
local free; free="$(df --output=avail -BM / 2>/dev/null | tail -1 | tr -dc 0-9)"
|
|
||||||
if [[ -n "$free" ]] && (( free < 1500 )); then
|
|
||||||
echo "less than 1.5 GB free on /: free some space and try again"; return 1
|
|
||||||
fi
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
gsn_fail_mark() {
|
|
||||||
# Remember a failed setup so the menu says so on the next start, and tell the user now (desktop notification).
|
|
||||||
state_set gamescope_nvidia failed "$(date '+%Y-%m-%d %H:%M'): $1"
|
|
||||||
command -v notify-send >/dev/null 2>&1 &&
|
|
||||||
notify-send -a Steamify -i dialog-warning "Steamify: gaming mode setup failed" "$1. Open Steamify and apply again." 2>/dev/null || true
|
|
||||||
}
|
|
||||||
|
|
||||||
gsn_fail_note() {
|
|
||||||
# The menu's reminder of a failed setup (nothing when the last one worked).
|
|
||||||
local f; f="$(state_get gamescope_nvidia failed)"
|
|
||||||
[[ -n "$f" ]] && warn "The last gaming mode setup for NVIDIA failed ($f). Apply the conversion again to retry."
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
gsn_enable() {
|
|
||||||
# Only on a supported NVIDIA card; elsewhere the stock gamescope is right.
|
|
||||||
nvidia_present || return 0
|
|
||||||
local why
|
|
||||||
if ! why="$(gsn_preflight)"; then err "Gaming mode for NVIDIA can't be set up: $why."; gsn_fail_mark "$why"; return 1; fi
|
|
||||||
# A PC that had "Gaming on NVIDIA" on: Steam must not also start on the desktop.
|
|
||||||
nvidia_swap_out
|
|
||||||
# What NVIDIA's DRM stack wants (lib/nvidia.sh; a supported card only, the functions check): modeset/fbdev on the
|
|
||||||
# kernel command line, the modules in the initramfs, video memory kept over suspend, the 32-bit libraries. Takes
|
|
||||||
# effect at the next boot, like the session.
|
|
||||||
nvidia_kernel_enable || return 1
|
|
||||||
nvidia_extras_enable || return 1
|
|
||||||
gsn_install_package || { gsn_fail_mark "the patched gamescope couldn't be installed"; return 1; }
|
|
||||||
state_set gamescope_nvidia failed ""
|
|
||||||
gsn_env_enable
|
|
||||||
gsn_display_enable || warn "Couldn't set up the display mode for gaming mode: gamescope takes the display's preferred mode."
|
|
||||||
ok "gamescope draws NVIDIA's picture through GBM (gamescope_drm_gbm_scanout=1) from the next gaming mode start."
|
|
||||||
}
|
|
||||||
|
|
||||||
gsn_disable() {
|
|
||||||
# The setting goes, and what nvidia_*_enable added; the packages stay (patched gamescope, 32-bit libraries), like
|
|
||||||
# the other packages of the conversion (steam, gamescope-session-cachyos).
|
|
||||||
gsn_env_disable
|
|
||||||
gsn_display_disable
|
|
||||||
nvidia_present || return 0
|
|
||||||
nvidia_extras_disable
|
|
||||||
nvidia_kernel_disable
|
|
||||||
}
|
|
||||||
@@ -94,8 +94,6 @@ gaming_enable() {
|
|||||||
# LOGIN_MANAGER (sddm with single user, else plasmalogin) is set by the
|
# LOGIN_MANAGER (sddm with single user, else plasmalogin) is set by the
|
||||||
# menu. Re-running with the other value switches over cleanly.
|
# menu. Re-running with the other value switches over cleanly.
|
||||||
install_required_packages || return 1
|
install_required_packages || return 1
|
||||||
# NVIDIA: gamescope's picture is corrupted unless it is the patched one (no-op elsewhere).
|
|
||||||
gsn_enable || return 1
|
|
||||||
case "$LOGIN_MANAGER" in
|
case "$LOGIN_MANAGER" in
|
||||||
sddm)
|
sddm)
|
||||||
switch_to_sddm || return 1
|
switch_to_sddm || return 1
|
||||||
@@ -109,8 +107,6 @@ gaming_enable() {
|
|||||||
install_session_sync
|
install_session_sync
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
# (NVIDIA with single user mode from before the conversion: its desktop autologin would pin the Plasma session.)
|
|
||||||
single_login_release
|
|
||||||
create_desktop_shortcut
|
create_desktop_shortcut
|
||||||
steam_enable
|
steam_enable
|
||||||
os_name_enable || return 1
|
os_name_enable || return 1
|
||||||
@@ -126,11 +122,8 @@ gaming_disable() {
|
|||||||
switch_to_plasmalogin
|
switch_to_plasmalogin
|
||||||
remove_desktop_shortcut
|
remove_desktop_shortcut
|
||||||
steam_disable
|
steam_disable
|
||||||
gsn_disable
|
|
||||||
krevert gaming
|
krevert gaming
|
||||||
os_name_disable
|
os_name_disable
|
||||||
# NVIDIA with single user mode still on: nothing else logs in by itself any more.
|
|
||||||
nvidia_present && single_status && single_login_enable
|
|
||||||
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)."
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+29
-32
@@ -5,19 +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 silent glyphs nvidia bigpicture nvsilent theme single launcher steamgame notify extended_controller_support vram cec machine poweroff kpin hdmi bios)
|
COMPONENTS=(gaming boot silent nvidia bigpicture nvsilent theme glyphs 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 [silent]=gaming [glyphs]=gaming [bigpicture]=nvidia [nvsilent]=nvidia [steamgame]=launcher [poweroff]=machine [kpin]=machine [hdmi]=machine [bios]=machine)
|
declare -A PARENT=([boot]=gaming [silent]=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. Extended controller support builds kernel modules for
|
# screen to confirm each step. Extended controller support builds kernel modules for
|
||||||
# every installed kernel: opt-in.
|
# every installed kernel: opt-in.
|
||||||
NO_PRESELECT=(boot silent nvsilent cec kpin hdmi extended_controller_support)
|
NO_PRESELECT=(boot 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
|
||||||
@@ -26,7 +26,7 @@ NO_PRESELECT=(boot silent nvsilent cec kpin hdmi extended_controller_support)
|
|||||||
# 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.0 [boot]=2.1.0 [silent]=2.11.0 [nvidia]=2.12.0 [bigpicture]=2.10.0 [nvsilent]=2.11.0 [theme]=2.1.0 [glyphs]=2.1.0 [single]=2.1.0
|
[gaming]=2.9.0 [boot]=2.1.0 [silent]=2.1.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 [extended_controller_support]=2.10.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 [extended_controller_support]=2.10.0
|
||||||
[kpin]=2.1.0 [hdmi]=2.1.0
|
[kpin]=2.1.0 [hdmi]=2.1.0
|
||||||
)
|
)
|
||||||
@@ -35,7 +35,7 @@ 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"
|
[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"
|
[silent]="Start Steam silently: 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)"
|
[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)"
|
[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)"
|
||||||
@@ -57,9 +57,11 @@ declare -A CURRENT WANTED
|
|||||||
|
|
||||||
component_available() {
|
component_available() {
|
||||||
case "$1" in
|
case "$1" in
|
||||||
# The SteamOS conversion is offered on NVIDIA PCs too: it installs the patched gamescope there (lib/gamescope-nvidia.sh)
|
# gamescope's own session is broken on NVIDIA: the conversion is replaced by "Gaming on NVIDIA" there (shown
|
||||||
# and turns off "Gaming on NVIDIA" (lib/nvidia.sh), which is not offered any more (nvidia_available).
|
# anyway when it's already on, so it can be turned off).
|
||||||
nvidia|bigpicture|nvsilent) nvidia_available ;;
|
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 ;;
|
||||||
# Steamify in the Steam library is for gaming mode's controller: not needed for Big Picture on the desktop (NVIDIA PCs;
|
# Steamify in the Steam library is for gaming mode's controller: not needed for Big Picture on the desktop (NVIDIA PCs;
|
||||||
@@ -79,12 +81,25 @@ boot_mode() {
|
|||||||
if [[ "$1" == 1 ]]; then echo desktop; else echo gamescope; fi
|
if [[ "$1" == 1 ]]; then echo desktop; else echo gamescope; fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
silent_needs_boot() {
|
||||||
|
# On a Steam Machine, silent start only makes sense when it boots into
|
||||||
|
# the desktop (gaming mode starts its own Steam): the option is hidden,
|
||||||
|
# and off, while "Boot into" is gaming mode.
|
||||||
|
machine_available
|
||||||
|
}
|
||||||
|
|
||||||
|
silent_normalize() {
|
||||||
|
silent_needs_boot && [[ "${WANTED[boot]:-0}" != 1 ]] && WANTED[silent]=0
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
menu_visible() {
|
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.
|
# Silent start is hidden while Steam starts in Big Picture.
|
||||||
[[ "$1" == nvsilent && "${WANTED[bigpicture]:-0}" == 1 ]] && return 1
|
[[ "$1" == nvsilent && "${WANTED[bigpicture]:-0}" == 1 ]] && return 1
|
||||||
|
[[ "$1" == silent ]] && silent_needs_boot && [[ "${WANTED[boot]:-0}" != 1 ]] && return 1
|
||||||
[[ -z "${PARENT[$1]:-}" || "${WANTED[${PARENT[$1]}]:-0}" == 1 ]]
|
[[ -z "${PARENT[$1]:-}" || "${WANTED[${PARENT[$1]}]:-0}" == 1 ]]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,11 +128,7 @@ feature_outdated() {
|
|||||||
# On, but set up by an older version of that feature (compared as
|
# On, but set up by an older version of that feature (compared as
|
||||||
# versions: 2.10.0 is newer than 2.9.0).
|
# versions: 2.10.0 is newer than 2.9.0).
|
||||||
local have want
|
local have want
|
||||||
# "Gaming on NVIDIA" is on: the SteamOS conversion replaces it, as an update of what the PC has (lib/nvidia.sh).
|
|
||||||
[[ "$1" == gaming ]] && nvidia_migration_pending && return 0
|
|
||||||
[[ "${CURRENT[$1]:-0}" == 1 ]] || return 1
|
[[ "${CURRENT[$1]:-0}" == 1 ]] || return 1
|
||||||
# NVIDIA: a newer patched gamescope is out (lib/gamescope-nvidia.sh): a normal run installs it.
|
|
||||||
[[ "$1" == gaming ]] && nvidia_present && { gsn_update_pending || gsn_display_pending; } && return 0
|
|
||||||
have="$(state_get features "$1" "$FEATURE_BASELINE")"
|
have="$(state_get features "$1" "$FEATURE_BASELINE")"
|
||||||
[[ "$have" == off ]] && have="$FEATURE_BASELINE"
|
[[ "$have" == off ]] && have="$FEATURE_BASELINE"
|
||||||
want="${FEATURE_VERSION[$1]:-$FEATURE_BASELINE}"
|
want="${FEATURE_VERSION[$1]:-$FEATURE_BASELINE}"
|
||||||
@@ -186,17 +197,6 @@ detect_components() {
|
|||||||
component_available "$c" || continue
|
component_available "$c" || continue
|
||||||
{ feature_outdated "$c" || feature_new "$c"; } && WANTED[$c]=1
|
{ feature_outdated "$c" || feature_new "$c"; } && WANTED[$c]=1
|
||||||
done
|
done
|
||||||
# "Gaming on NVIDIA" was on: its replacement, the SteamOS conversion, comes with the defaults of a first run, and the
|
|
||||||
# PC starts the way it did: Steam in Big Picture at login becomes booting into gaming mode, any other Steam start
|
|
||||||
# (a normal window, or silent in the tray) becomes booting into the desktop, with the silent start kept.
|
|
||||||
if nvidia_migration_pending; then
|
|
||||||
WANTED[glyphs]=1
|
|
||||||
if bigpicture_status; then WANTED[boot]=0
|
|
||||||
else
|
|
||||||
WANTED[boot]=1
|
|
||||||
nvsilent_status && WANTED[silent]=1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
# The kernel pin is no longer needed (the power-off fix), and HDMI
|
# The kernel pin is no longer needed (the power-off fix), and HDMI
|
||||||
# refresh boost needed the pin: whatever is left of either is unticked,
|
# refresh boost needed the pin: whatever is left of either is unticked,
|
||||||
# so a normal run removes it.
|
# so a normal run removes it.
|
||||||
@@ -220,6 +220,7 @@ detect_components() {
|
|||||||
done
|
done
|
||||||
machine_available && WANTED[cec]=1
|
machine_available && WANTED[cec]=1
|
||||||
fi
|
fi
|
||||||
|
silent_normalize
|
||||||
}
|
}
|
||||||
|
|
||||||
defaults_options() {
|
defaults_options() {
|
||||||
@@ -276,6 +277,7 @@ defaults_options() {
|
|||||||
WANTED[boot]=1 ;;
|
WANTED[boot]=1 ;;
|
||||||
gamescope) WANTED[boot]=0 ;;
|
gamescope) WANTED[boot]=0 ;;
|
||||||
esac
|
esac
|
||||||
|
silent_normalize
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -299,7 +301,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]:-}"),\"needs\":\"\",\"hideWhen\":$(json_str "$([[ "$c" == nvsilent ]] && echo bigpicture)"),\"on\":$on,\"selectable\":$sel}"
|
items+=",\"kind\":\"$kind\",\"parent\":$(json_str "${PARENT[$c]:-}"),\"needs\":$(json_str "$([[ "$c" == silent ]] && silent_needs_boot && echo boot)"),\"hideWhen\":$(json_str "$([[ "$c" == nvsilent ]] && echo bigpicture)"),\"on\":$on,\"selectable\":$sel}"
|
||||||
done
|
done
|
||||||
printf '[%s]\n' "$items"
|
printf '[%s]\n' "$items"
|
||||||
}
|
}
|
||||||
@@ -309,6 +311,7 @@ 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.
|
||||||
|
# (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" == 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.
|
||||||
@@ -319,9 +322,9 @@ toggle_component() {
|
|||||||
# Silent and Big Picture exclude each other.
|
# Silent and Big Picture exclude each other.
|
||||||
if [[ "$c" == nvsilent && "${WANTED[nvsilent]}" == 1 ]]; then WANTED[nvidia]=1; WANTED[bigpicture]=0; fi
|
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" == 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" == gaming && "${WANTED[gaming]}" == 0 ]]; then WANTED[silent]=0; fi
|
||||||
if [[ "$c" == silent && "${WANTED[silent]}" == 1 ]]; then WANTED[gaming]=1; fi
|
if [[ "$c" == silent && "${WANTED[silent]}" == 1 ]]; then WANTED[gaming]=1; fi
|
||||||
if [[ "$c" == glyphs && "${WANTED[glyphs]}" == 1 ]]; then WANTED[gaming]=1; fi
|
silent_normalize
|
||||||
# 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
|
||||||
@@ -337,7 +340,6 @@ toggle_component() {
|
|||||||
show_menu() {
|
show_menu() {
|
||||||
local i=0 c now want
|
local i=0 c now want
|
||||||
echo
|
echo
|
||||||
gsn_fail_note
|
|
||||||
printf " ${c_bold}%-3s %-6s %-6s %s${c_reset}\n" "#" "Now" "Want" "Component"
|
printf " ${c_bold}%-3s %-6s %-6s %s${c_reset}\n" "#" "Now" "Want" "Component"
|
||||||
MENU_ITEMS=()
|
MENU_ITEMS=()
|
||||||
for c in "${COMPONENTS[@]}"; do
|
for c in "${COMPONENTS[@]}"; do
|
||||||
@@ -512,11 +514,6 @@ apply_changes() {
|
|||||||
if "${c}_disable"; then feature_record "$c" disable; else failed+=("$c"); fi
|
if "${c}_disable"; then feature_record "$c" disable; else failed+=("$c"); fi
|
||||||
done
|
done
|
||||||
for c in "${TO_ENABLE[@]}"; do
|
for c in "${TO_ENABLE[@]}"; do
|
||||||
# A sub-option of something that just failed isn't applied: it would be left on without its parent.
|
|
||||||
if [[ -n "${PARENT[$c]:-}" && " ${failed[*]:-} " == *" ${PARENT[$c]} "* ]]; then
|
|
||||||
warn "Skipping ${LABEL[$c]%%:*}: ${LABEL[${PARENT[$c]}]%%:*} didn't work."
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
if [[ "$c" == boot ]]; then echo; echo -e "${c_bold}Boot into: desktop${c_reset}"
|
if [[ "$c" == boot ]]; then echo; echo -e "${c_bold}Boot into: desktop${c_reset}"
|
||||||
elif is_action "$c"; then echo; echo -e "${c_bold}Running: ${LABEL[$c]%%:*}${c_reset}"
|
elif is_action "$c"; then echo; echo -e "${c_bold}Running: ${LABEL[$c]%%:*}${c_reset}"
|
||||||
else echo; echo -e "${c_bold}Turning on: ${LABEL[$c]}${c_reset}"; fi
|
else echo; echo -e "${c_bold}Turning on: ${LABEL[$c]}${c_reset}"; fi
|
||||||
|
|||||||
+5
-77
@@ -13,11 +13,6 @@ NVIDIA_INITRAMFS_CONF=${NVIDIA_INITRAMFS_CONF:-/etc/mkinitcpio.conf.d/90-steamif
|
|||||||
# 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}
|
||||||
# Keeps video memory over suspend (with the nvidia-suspend/resume services).
|
|
||||||
NVIDIA_MODPROBE=${NVIDIA_MODPROBE:-/etc/modprobe.d/90-steamify-nvidia.conf}
|
|
||||||
NVIDIA_SLEEP_UNITS="nvidia-suspend.service nvidia-resume.service nvidia-hibernate.service"
|
|
||||||
# 32-bit parts Steam games and the 32-bit MangoHud preload need.
|
|
||||||
NVIDIA_LIB32_PKGS="lib32-nvidia-utils lib32-libxkbcommon"
|
|
||||||
# The running kernel's command line; the tests point this at a file.
|
# The running kernel's command line; the tests point this at a file.
|
||||||
NVIDIA_CMDLINE=${NVIDIA_CMDLINE:-/proc/cmdline}
|
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.
|
||||||
@@ -37,27 +32,9 @@ nvidia_present() {
|
|||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
# Not offered any more (2.12.0): the SteamOS conversion with the patched gamescope (lib/gamescope-nvidia.sh) covers NVIDIA PCs.
|
# Shown on NVIDIA PCs, unless the SteamOS conversion is already on there (it
|
||||||
# A PC that has this on keeps it until the conversion is turned on, which calls nvidia_swap_out.
|
# has to be turned off first: both would start Steam at login).
|
||||||
nvidia_available() { return 1; }
|
nvidia_available() { nvidia_present && ! gaming_status 2>/dev/null; }
|
||||||
|
|
||||||
nvidia_migration_pending() {
|
|
||||||
# "Gaming on NVIDIA" is on (set up before 2.12.0) and the SteamOS conversion that replaces it isn't: the menu ticks the
|
|
||||||
# conversion and shows it as an update, so a normal run moves the PC over (nvidia_swap_out in gsn_enable).
|
|
||||||
nvidia_present && nvidia_status && ! gaming_status 2>/dev/null
|
|
||||||
}
|
|
||||||
|
|
||||||
nvidia_swap_out() {
|
|
||||||
# The conversion takes over: Steam no longer starts by itself on the desktop at login (both would start it). Steam, the
|
|
||||||
# packages and the NVIDIA settings stay: the conversion needs them too. The state stays for the conversion's own disable.
|
|
||||||
nvidia_status || return 0
|
|
||||||
info "Gaming on NVIDIA is replaced by the SteamOS conversion: Steam no longer starts on the desktop at login."
|
|
||||||
user_systemctl disable --now "$NVIDIA_UNIT" >/dev/null 2>&1
|
|
||||||
rm -f "$(nvidia_unit_file)"
|
|
||||||
user_systemctl daemon-reload
|
|
||||||
krevert bigpicture
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
bigpicture_available() { nvidia_available; }
|
bigpicture_available() { nvidia_available; }
|
||||||
|
|
||||||
nvidia_status() {
|
nvidia_status() {
|
||||||
@@ -85,7 +62,6 @@ nvidia_enable() {
|
|||||||
nvidia_write_unit "$unit_args" || return 1
|
nvidia_write_unit "$unit_args" || return 1
|
||||||
user_systemctl enable "$NVIDIA_UNIT" >/dev/null 2>&1 || { err "Enabling $NVIDIA_UNIT failed."; return 1; }
|
user_systemctl enable "$NVIDIA_UNIT" >/dev/null 2>&1 || { err "Enabling $NVIDIA_UNIT failed."; return 1; }
|
||||||
nvidia_kernel_enable || return 1
|
nvidia_kernel_enable || return 1
|
||||||
nvidia_extras_enable || return 1
|
|
||||||
ok "Steam starts at your next login."
|
ok "Steam starts at your next login."
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,19 +70,13 @@ nvidia_disable() {
|
|||||||
user_systemctl disable --now "$NVIDIA_UNIT" >/dev/null 2>&1
|
user_systemctl disable --now "$NVIDIA_UNIT" >/dev/null 2>&1
|
||||||
rm -f "$unit"
|
rm -f "$unit"
|
||||||
user_systemctl daemon-reload
|
user_systemctl daemon-reload
|
||||||
# Swapped for the SteamOS conversion (turned on first, in the same run): it needs the same settings, they stay.
|
|
||||||
gaming_status 2>/dev/null || nvidia_extras_disable
|
|
||||||
pkgs="$(state_get nvidia installed_pkgs)"
|
pkgs="$(state_get nvidia installed_pkgs)"
|
||||||
if gaming_status 2>/dev/null; then
|
|
||||||
local p; pkgs=" $pkgs "
|
|
||||||
for p in $NVIDIA_LIB32_PKGS; do pkgs="${pkgs// $p / }"; done
|
|
||||||
fi
|
|
||||||
# Only what Steamify installed; games and the Steam folder stay.
|
# Only what Steamify installed; games and the Steam folder stay.
|
||||||
# shellcheck disable=SC2086 # a list of package names
|
# shellcheck disable=SC2086 # a list of package names
|
||||||
[[ -n "$pkgs" ]] && sudo pacman -Rns --noconfirm $pkgs >/dev/null 2>&1
|
[[ -n "$pkgs" ]] && sudo pacman -Rns --noconfirm $pkgs >/dev/null 2>&1
|
||||||
state_clear nvidia
|
state_clear nvidia
|
||||||
krevert bigpicture
|
krevert bigpicture
|
||||||
gaming_status 2>/dev/null || nvidia_kernel_disable
|
nvidia_kernel_disable
|
||||||
ok "Steam no longer starts at login."
|
ok "Steam no longer starts at login."
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,7 +118,7 @@ nvsilent_disable() {
|
|||||||
|
|
||||||
nvidia_supported() {
|
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 Turing (GTX 16 / RTX 20 series: the cards NVIDIA's open kernel driver supports), 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
|
||||||
# other card runs NVIDIA's open modules). Older cards are left alone.
|
# other card runs NVIDIA's open modules). Older cards are left alone.
|
||||||
local d
|
local d
|
||||||
@@ -284,48 +254,6 @@ nvidia_kernel_enable() {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
nvidia_extras_enable() {
|
|
||||||
# Video memory kept over sleep, the matching services and the 32-bit libraries (a supported card only).
|
|
||||||
nvidia_supported || return 0
|
|
||||||
local pkg u units="" prev missing=()
|
|
||||||
if [[ ! -f "$NVIDIA_MODPROBE" ]]; then
|
|
||||||
info "Keeping video memory over suspend (NVreg_PreserveVideoMemoryAllocations=1)..."
|
|
||||||
printf '%s\n' '# Added by Steamify (Gaming on NVIDIA)' 'options nvidia NVreg_PreserveVideoMemoryAllocations=1' |
|
|
||||||
sudo tee "$NVIDIA_MODPROBE" >/dev/null || { err "Writing $NVIDIA_MODPROBE failed."; return 1; }
|
|
||||||
# The NVIDIA modules load from the initramfs, which carries modprobe.d.
|
|
||||||
nvidia_rebuild_boot || warn "Rebuilding the initramfs failed: the suspend setting applies once it is rebuilt."
|
|
||||||
fi
|
|
||||||
for u in $NVIDIA_SLEEP_UNITS; do
|
|
||||||
systemctl is-enabled -q "$u" 2>/dev/null && continue
|
|
||||||
sudo systemctl enable "$u" >/dev/null 2>&1 && units+="${units:+ }$u"
|
|
||||||
done
|
|
||||||
if [[ -n "$units" ]]; then
|
|
||||||
prev="$(state_get nvidia enabled_units)"
|
|
||||||
state_set nvidia enabled_units "${prev:+$prev }$units"
|
|
||||||
fi
|
|
||||||
for pkg in $NVIDIA_LIB32_PKGS; do pacman -Q "$pkg" >/dev/null 2>&1 || missing+=("$pkg"); done
|
|
||||||
if [[ ${#missing[@]} -gt 0 ]]; then
|
|
||||||
info "Installing the 32-bit libraries games need: ${missing[*]}"
|
|
||||||
if sudo pacman -S --needed --noconfirm "${missing[@]}"; then
|
|
||||||
prev="$(state_get nvidia installed_pkgs)"
|
|
||||||
state_set nvidia installed_pkgs "${prev:+$prev }${missing[*]}"
|
|
||||||
else
|
|
||||||
warn "Installing ${missing[*]} failed (is [multilib] enabled in /etc/pacman.conf?): 32-bit games may not start."
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
nvidia_extras_disable() {
|
|
||||||
# Only what Steamify enabled; the 32-bit packages go with installed_pkgs.
|
|
||||||
local u
|
|
||||||
for u in $(state_get nvidia enabled_units); do sudo systemctl disable "$u" >/dev/null 2>&1; done
|
|
||||||
if [[ -f "$NVIDIA_MODPROBE" ]]; then
|
|
||||||
sudo rm -f "$NVIDIA_MODPROBE"
|
|
||||||
nvidia_rebuild_boot || true
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
nvidia_kernel_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
|
||||||
|
|||||||
@@ -58,30 +58,6 @@ bootstrap_yay() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
python_hid_shim_ensure() {
|
|
||||||
# jupiter-hw-support (a dependency of gamescope-session-cachyos) wants python-hid, which conflicts with python-hidapi, and
|
|
||||||
# a PC can need python-hidapi (liquidctl does). Only Valve's Steam Deck controller firmware updater uses python-hid, which
|
|
||||||
# a PC doesn't run: so a placeholder package that provides python-hid keeps python-hidapi and satisfies the dependency
|
|
||||||
# (also at later updates, which a one-time --assume-installed wouldn't). It stays when the conversion goes off:
|
|
||||||
# jupiter-hw-support, which stays, depends on it.
|
|
||||||
pacman -Q python-hidapi >/dev/null 2>&1 || return 0
|
|
||||||
pacman -Q python-hid steamify-python-hid-shim >/dev/null 2>&1 && return 0
|
|
||||||
local dir pkg cache="${XDG_CACHE_HOME:-$HOME/.cache}/steamify"
|
|
||||||
warn "python-hidapi is installed (liquidctl and others need it) and conflicts with python-hid, which Steam Deck's tools ask for: keeping python-hidapi, with a small placeholder package for python-hid."
|
|
||||||
sudo pacman -S --needed --noconfirm base-devel >/dev/null || { err "Installing the build tools failed."; return 1; }
|
|
||||||
mkdir -p "$cache" && dir="$(mktemp -d -p "$cache" hid-shim.XXXXXX)" || return 1
|
|
||||||
patch_file python-hid-shim.PKGBUILD > "$dir/PKGBUILD" || { rm -rf "$dir"; return 1; }
|
|
||||||
if ! (cd "$dir" && makepkg -f --noconfirm >/dev/null) ||
|
|
||||||
! pkg="$(ls "$dir"/steamify-python-hid-shim-*.pkg.tar.* 2>/dev/null | head -1)" ||
|
|
||||||
! sudo pacman -U --noconfirm "$pkg"; then
|
|
||||||
rm -rf "$dir"
|
|
||||||
err "Couldn't set up the python-hid placeholder: python-hidapi and python-hid conflict, so the packages can't be installed."
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
rm -rf "$dir"
|
|
||||||
ok "python-hidapi kept; python-hid is covered by a placeholder."
|
|
||||||
}
|
|
||||||
|
|
||||||
install_required_packages() {
|
install_required_packages() {
|
||||||
# Step 2: gamescope/Steam and the desktop helpers the rest of the setup uses.
|
# Step 2: gamescope/Steam and the desktop helpers the rest of the setup uses.
|
||||||
local -a MISSING
|
local -a MISSING
|
||||||
@@ -89,7 +65,6 @@ install_required_packages() {
|
|||||||
mapfile -t MISSING < <(pacman -T gamescope-session-cachyos steam mangohud xterm ttf-liberation wqy-zenhei plasma-keyboard)
|
mapfile -t MISSING < <(pacman -T gamescope-session-cachyos steam mangohud xterm ttf-liberation wqy-zenhei plasma-keyboard)
|
||||||
|
|
||||||
if [[ ${#MISSING[@]} -gt 0 ]]; then
|
if [[ ${#MISSING[@]} -gt 0 ]]; then
|
||||||
python_hid_shim_ensure || return 1
|
|
||||||
info "Installing missing packages: ${MISSING[*]}"
|
info "Installing missing packages: ${MISSING[*]}"
|
||||||
sudo pacman -S --needed --noconfirm "${MISSING[@]}" || { err "Package installation failed."; return 1; }
|
sudo pacman -S --needed --noconfirm "${MISSING[@]}" || { err "Package installation failed."; return 1; }
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -140,15 +140,6 @@ EOF
|
|||||||
remove_sddm_base_autologin
|
remove_sddm_base_autologin
|
||||||
}
|
}
|
||||||
|
|
||||||
single_login_release() {
|
|
||||||
# The SteamOS conversion logs in by itself, and picks the session (gamescope, or the desktop with "Boot into"): the
|
|
||||||
# desktop autologin above, which sorts last, would pin the Plasma session and "Return to Gaming Mode" would open KDE
|
|
||||||
# again. Called when the conversion is turned on; turning it off sets it up again (gaming_disable).
|
|
||||||
[[ -f "$SINGLE_AUTOLOGIN" ]] || return 0
|
|
||||||
info "The SteamOS conversion logs in by itself: removing the desktop autologin of single user mode."
|
|
||||||
sudo rm -f "$SINGLE_AUTOLOGIN"
|
|
||||||
}
|
|
||||||
|
|
||||||
single_login_disable() {
|
single_login_disable() {
|
||||||
[[ -f "$SINGLE_AUTOLOGIN" ]] || return 0
|
[[ -f "$SINGLE_AUTOLOGIN" ]] || return 0
|
||||||
sudo rm -f "$SINGLE_AUTOLOGIN"
|
sudo rm -f "$SINGLE_AUTOLOGIN"
|
||||||
|
|||||||
+14
-31
@@ -16,51 +16,34 @@ steam_enable() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# Sub-option of the SteamOS conversion: Steam starts silently (in the tray,
|
# 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
|
# no window) on the Plasma desktop.
|
||||||
# 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
|
|
||||||
|
|
||||||
silent_status() {
|
silent_status() {
|
||||||
# The old systemd unit counts as on too (until it is migrated by an update of this option).
|
[[ -f "$HOME/.config/systemd/user/steam-desktop-autostart.service" ]]
|
||||||
grep -qs '^Exec=.*-silent' "$STEAM_AUTOSTART" ||
|
|
||||||
[[ -f "$HOME/.config/systemd/user/steam-desktop-autostart.service" ]]
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
silent_enable() {
|
silent_enable() {
|
||||||
silent_old_unit_remove
|
local systemd_user_dir="$HOME/.config/systemd/user"
|
||||||
mkdir -p "$(dirname "$STEAM_AUTOSTART")"
|
mkdir -p "$systemd_user_dir"
|
||||||
if [[ -f "$STEAM_SYSTEM_DESKTOP" ]]; then
|
service_file steam-desktop-autostart.service > "$systemd_user_dir/steam-desktop-autostart.service"
|
||||||
sed 's|^Exec=/usr/bin/steam %U$|Exec=/usr/bin/steam -silent %U|' "$STEAM_SYSTEM_DESKTOP" > "$STEAM_AUTOSTART"
|
# Clean out old .desktop shortcut so they don't fight
|
||||||
fi
|
rm -f "$HOME/.config/autostart/steam.desktop"
|
||||||
silent_status || printf '%s\n' '[Desktop Entry]' 'Name=Steam' 'Exec=/usr/bin/steam -silent %U' \
|
user_systemctl daemon-reload
|
||||||
'Icon=steam' 'Terminal=false' 'Type=Application' 'Categories=Network;FileTransfer;Game;' > "$STEAM_AUTOSTART"
|
user_systemctl enable --now steam-desktop-autostart.service
|
||||||
ok "Steam starts silently on the desktop from the next login."
|
ok "Steam starts silently on the desktop."
|
||||||
}
|
}
|
||||||
|
|
||||||
silent_disable() {
|
silent_disable() {
|
||||||
silent_old_unit_remove
|
user_systemctl disable --now steam-desktop-autostart.service 2>/dev/null
|
||||||
silent_status && rm -f "$STEAM_AUTOSTART"
|
rm -f "$HOME/.config/systemd/user/steam-desktop-autostart.service"
|
||||||
|
user_systemctl daemon-reload
|
||||||
ok "Steam no longer starts by itself on the desktop."
|
ok "Steam no longer starts by itself on the desktop."
|
||||||
}
|
}
|
||||||
|
|
||||||
steam_disable() {
|
steam_disable() {
|
||||||
info "Removing Steam desktop settings..."
|
info "Removing Steam desktop settings..."
|
||||||
# The autostart entry is the `silent` option's: removed with it, and here
|
# The autostart unit is the `silent` option's: removed with it, and here
|
||||||
# too for when the conversion goes off by itself.
|
# too for when the conversion goes off by itself.
|
||||||
silent_status && silent_disable
|
silent_status && silent_disable
|
||||||
silent_old_unit_remove
|
|
||||||
rm -f "$HOME/.config/environment.d/99-kde-virtual-keyboard.conf"
|
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)."
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-2
@@ -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 (silently, in the tray).
|
# again if it was running (through our autostart unit when that's there).
|
||||||
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,7 +72,11 @@ steamgame_edit() {
|
|||||||
fi
|
fi
|
||||||
"$1"; local rc=$?
|
"$1"; local rc=$?
|
||||||
if [[ "$was_running" == true ]]; then
|
if [[ "$was_running" == true ]]; then
|
||||||
systemd-run --user --collect -q steam -silent >/dev/null 2>&1
|
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
|
||||||
|
fi
|
||||||
info "Steam is starting again."
|
info "Steam is starting again."
|
||||||
fi
|
fi
|
||||||
return "$rc"
|
return "$rc"
|
||||||
|
|||||||
@@ -407,12 +407,9 @@ 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() {
|
||||||
|
|||||||
+7
-22
@@ -106,32 +106,17 @@ 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, and the default taskbar pins.
|
# The new layout has a new launcher, without single user's settings.
|
||||||
sleep 3
|
if single_status; then
|
||||||
stop_plasmashell_for_edit
|
sleep 3
|
||||||
taskbar_drop_discover
|
stop_plasmashell_for_edit
|
||||||
single_status && single_launcher
|
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..."
|
||||||
|
|||||||
@@ -16,9 +16,3 @@ read and reviewed on their own. `lib/*.sh` reads them with `patch_file
|
|||||||
| `steamify-os-release.sh`, `steamify-os-release.hook` | `lib/login-manager.sh` (SteamOS conversion) | What Steam's System settings show besides the OS name (which stays CachyOS's): `VERSION_ID=steamos-X.Y`, `VERSION_CODENAME=steam-machine`, `VARIANT`/`VARIANT_ID` Steamify with its version, in `/etc/os-release`; the pacman hook runs it again after cachyos-hooks (`fill SCRIPT=... VERSION=... STEAMOS=...`) |
|
| `steamify-os-release.sh`, `steamify-os-release.hook` | `lib/login-manager.sh` (SteamOS conversion) | What Steam's System settings show besides the OS name (which stays CachyOS's): `VERSION_ID=steamos-X.Y`, `VERSION_CODENAME=steam-machine`, `VARIANT`/`VARIANT_ID` Steamify with its version, in `/etc/os-release`; the pacman hook runs it again after cachyos-hooks (`fill SCRIPT=... VERSION=... STEAMOS=...`) |
|
||||||
| `steamify-nvidia-initramfs.sh`, `steamify-nvidia-initramfs.hook` | `lib/nvidia.sh` (SteamOS conversion, NVIDIA fix) | The pacman hook (before the initramfs is built, after DKMS) and its script: the NVIDIA modules go into the initramfs only while every installed kernel has them, decided again at every kernel or driver change (`fill SCRIPT=...`) |
|
| `steamify-nvidia-initramfs.sh`, `steamify-nvidia-initramfs.hook` | `lib/nvidia.sh` (SteamOS conversion, NVIDIA fix) | The pacman hook (before the initramfs is built, after DKMS) and its script: the NVIDIA modules go into the initramfs only while every installed kernel has them, decided again at every kernel or driver change (`fill SCRIPT=...`) |
|
||||||
| `cros-ec-cec-single-port.patch` | `lib/cec.sh` (HDMI-CEC) | Makes Valve's Steam Machine CEC driver find amdgpu's HDMI port |
|
| `cros-ec-cec-single-port.patch` | `lib/cec.sh` (HDMI-CEC) | Makes Valve's Steam Machine CEC driver find amdgpu's HDMI port |
|
||||||
| `gamescope-gbm-scanout.patch` | `lib/gamescope-nvidia.sh` (gamescope on NVIDIA) | gamescope 3.16.31 patch: scan-out buffers allocated with GBM (opt-in, `gamescope_drm_gbm_scanout=1`), which cures the corrupted picture on NVIDIA; from farnoy/gamescope, see the header of the file |
|
|
||||||
| `gamescope-nvidia.PKGBUILD` | `lib/gamescope-nvidia.sh` (gamescope on NVIDIA) | The recipe for the patched gamescope package (CI builds it per CPU level; here it is only the local-build fallback) (`steamify-gamescope-nvidia`, provides and conflicts with `gamescope`): Valve's gamescope at `pkgver` plus `gamescope-gbm-scanout.patch`; written with the patch to a temporary folder and built with `makepkg` |
|
|
||||||
| `cros-ec-cec.c` | `lib/cec.sh` (HDMI-CEC) | Valve's Steam Machine CEC driver (GPL-2.0+, from evlaV/linux-integration at the pinned commit): the backup when downloading it from GitHub fails; used only if its sha256 equals `CEC_DRIVER_SHA256` (a new pin needs a new copy) |
|
|
||||||
| `python-hid-shim.PKGBUILD` | `lib/packages.sh` (required packages) | An empty package that provides `python-hid`, for PCs that keep `python-hidapi` (they conflict; jupiter-hw-support, a dependency of gamescope-session-cachyos, wants python-hid, only the Steam Deck controller updater uses it): built with `makepkg` and installed before the conversion's packages |
|
|
||||||
| `gamescope-ui-native.patch` | `lib/gamescope-nvidia.sh` (gamescope on NVIDIA) | Small patch after the GBM one: keeps Steam's UI X server at the display's size when Steam (with `-steamos3`) asks for 1920x1080; `gamescope_xwayland_ui_native=0` turns it off |
|
|
||||||
| `gamescope-display-wrapper.sh` | `lib/gamescope-nvidia.sh` (gamescope on NVIDIA) | Installed as `gamescope` in Steamify's bin folder and put first in the gaming session's PATH: starts gamescope on the mode KDE has saved for the connected display, else the biggest mode at the highest refresh rate (modetest + `kwinoutputconfig.json`) |
|
|
||||||
@@ -1,621 +0,0 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0+
|
|
||||||
/*
|
|
||||||
* CEC driver for ChromeOS Embedded Controller
|
|
||||||
*
|
|
||||||
* Copyright (c) 2018 BayLibre, SAS
|
|
||||||
* Author: Neil Armstrong <narmstrong@baylibre.com>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <linux/kernel.h>
|
|
||||||
#include <linux/module.h>
|
|
||||||
#include <linux/mod_devicetable.h>
|
|
||||||
#include <linux/platform_device.h>
|
|
||||||
#include <linux/dmi.h>
|
|
||||||
#include <linux/pci.h>
|
|
||||||
#include <linux/cec.h>
|
|
||||||
#include <linux/slab.h>
|
|
||||||
#include <linux/interrupt.h>
|
|
||||||
#include <linux/platform_data/cros_ec_commands.h>
|
|
||||||
#include <linux/platform_data/cros_ec_proto.h>
|
|
||||||
#include <media/cec.h>
|
|
||||||
#include <media/cec-notifier.h>
|
|
||||||
|
|
||||||
#define DRV_NAME "cros-ec-cec"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* struct cros_ec_cec_port - Driver data for a single EC CEC port
|
|
||||||
*
|
|
||||||
* @port_num: port number
|
|
||||||
* @adap: CEC adapter
|
|
||||||
* @notify: CEC notifier pointer
|
|
||||||
* @rx_msg: storage for a received message
|
|
||||||
* @cros_ec_cec: pointer to the parent struct
|
|
||||||
*/
|
|
||||||
struct cros_ec_cec_port {
|
|
||||||
int port_num;
|
|
||||||
struct cec_adapter *adap;
|
|
||||||
struct cec_notifier *notify;
|
|
||||||
struct cec_msg rx_msg;
|
|
||||||
struct cros_ec_cec *cros_ec_cec;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* struct cros_ec_cec - Driver data for EC CEC
|
|
||||||
*
|
|
||||||
* @cros_ec: Pointer to EC device
|
|
||||||
* @notifier: Notifier info for responding to EC events
|
|
||||||
* @write_cmd_version: Highest supported version of EC_CMD_CEC_WRITE_MSG.
|
|
||||||
* @num_ports: Number of CEC ports
|
|
||||||
* @ports: Array of ports
|
|
||||||
*/
|
|
||||||
struct cros_ec_cec {
|
|
||||||
struct cros_ec_device *cros_ec;
|
|
||||||
struct notifier_block notifier;
|
|
||||||
int write_cmd_version;
|
|
||||||
int num_ports;
|
|
||||||
struct cros_ec_cec_port *ports[EC_CEC_MAX_PORTS];
|
|
||||||
};
|
|
||||||
|
|
||||||
static void cros_ec_cec_received_message(struct cros_ec_cec_port *port,
|
|
||||||
uint8_t *msg, uint8_t len)
|
|
||||||
{
|
|
||||||
if (len > CEC_MAX_MSG_SIZE)
|
|
||||||
len = CEC_MAX_MSG_SIZE;
|
|
||||||
|
|
||||||
port->rx_msg.len = len;
|
|
||||||
memcpy(port->rx_msg.msg, msg, len);
|
|
||||||
|
|
||||||
cec_received_msg(port->adap, &port->rx_msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void handle_cec_message(struct cros_ec_cec *cros_ec_cec)
|
|
||||||
{
|
|
||||||
struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec;
|
|
||||||
uint8_t *cec_message = cros_ec->event_data.data.cec_message;
|
|
||||||
unsigned int len = cros_ec->event_size;
|
|
||||||
struct cros_ec_cec_port *port;
|
|
||||||
/*
|
|
||||||
* There are two ways of receiving CEC messages:
|
|
||||||
* 1. Old EC firmware which only supports one port sends the data in a
|
|
||||||
* cec_message MKBP event.
|
|
||||||
* 2. New EC firmware which supports multiple ports uses
|
|
||||||
* EC_MKBP_CEC_HAVE_DATA to notify that data is ready and
|
|
||||||
* EC_CMD_CEC_READ_MSG to read it.
|
|
||||||
* Check that the EC only has one CEC port, and then we can assume the
|
|
||||||
* message is from port 0.
|
|
||||||
*/
|
|
||||||
if (cros_ec_cec->num_ports != 1) {
|
|
||||||
dev_err(cros_ec->dev,
|
|
||||||
"received cec_message on device with %d ports\n",
|
|
||||||
cros_ec_cec->num_ports);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
port = cros_ec_cec->ports[0];
|
|
||||||
|
|
||||||
cros_ec_cec_received_message(port, cec_message, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void cros_ec_cec_read_message(struct cros_ec_cec_port *port)
|
|
||||||
{
|
|
||||||
struct cros_ec_device *cros_ec = port->cros_ec_cec->cros_ec;
|
|
||||||
struct ec_params_cec_read params = {
|
|
||||||
.port = port->port_num,
|
|
||||||
};
|
|
||||||
struct ec_response_cec_read response;
|
|
||||||
int ret = 0;
|
|
||||||
int count = 0;
|
|
||||||
|
|
||||||
/* NOTE read as many messages as we can, return value from cros_ec_cmd
|
|
||||||
* here should either equal to the bytes transferred or a negative
|
|
||||||
* error code, so as long as we get positive integers we are
|
|
||||||
* reading messages!
|
|
||||||
*/
|
|
||||||
do {
|
|
||||||
ret = cros_ec_cmd(cros_ec, 0, EC_CMD_CEC_READ_MSG, ¶ms,
|
|
||||||
sizeof(params), &response, sizeof(response));
|
|
||||||
if (ret > 0) {
|
|
||||||
++count;
|
|
||||||
cros_ec_cec_received_message(port, response.msg, response.msg_len);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while (ret > 0);
|
|
||||||
|
|
||||||
if (ret < 0 && count == 0) {
|
|
||||||
dev_err(cros_ec->dev,
|
|
||||||
"error reading CEC message on EC: %d\n", ret);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void handle_cec_event(struct cros_ec_cec *cros_ec_cec)
|
|
||||||
{
|
|
||||||
struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec;
|
|
||||||
uint32_t cec_events = cros_ec->event_data.data.cec_events;
|
|
||||||
uint32_t port_num = EC_MKBP_EVENT_CEC_GET_PORT(cec_events);
|
|
||||||
uint32_t events = EC_MKBP_EVENT_CEC_GET_EVENTS(cec_events);
|
|
||||||
struct cros_ec_cec_port *port;
|
|
||||||
|
|
||||||
if (port_num >= cros_ec_cec->num_ports) {
|
|
||||||
dev_err(cros_ec->dev,
|
|
||||||
"received CEC event for invalid port %d\n", port_num);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
port = cros_ec_cec->ports[port_num];
|
|
||||||
|
|
||||||
if (events & EC_MKBP_CEC_SEND_OK)
|
|
||||||
cec_transmit_attempt_done(port->adap, CEC_TX_STATUS_OK);
|
|
||||||
|
|
||||||
/* FW takes care of all retries, tell core to avoid more retries */
|
|
||||||
if (events & EC_MKBP_CEC_SEND_FAILED)
|
|
||||||
cec_transmit_attempt_done(port->adap,
|
|
||||||
CEC_TX_STATUS_MAX_RETRIES |
|
|
||||||
CEC_TX_STATUS_NACK);
|
|
||||||
|
|
||||||
if (events & EC_MKBP_CEC_HAVE_DATA)
|
|
||||||
cros_ec_cec_read_message(port);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cros_ec_cec_event(struct notifier_block *nb,
|
|
||||||
unsigned long queued_during_suspend,
|
|
||||||
void *_notify)
|
|
||||||
{
|
|
||||||
struct cros_ec_cec *cros_ec_cec;
|
|
||||||
struct cros_ec_device *cros_ec;
|
|
||||||
|
|
||||||
cros_ec_cec = container_of(nb, struct cros_ec_cec, notifier);
|
|
||||||
cros_ec = cros_ec_cec->cros_ec;
|
|
||||||
|
|
||||||
if (cros_ec->event_data.event_type == EC_MKBP_EVENT_CEC_EVENT) {
|
|
||||||
handle_cec_event(cros_ec_cec);
|
|
||||||
return NOTIFY_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cros_ec->event_data.event_type == EC_MKBP_EVENT_CEC_MESSAGE) {
|
|
||||||
handle_cec_message(cros_ec_cec);
|
|
||||||
return NOTIFY_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NOTIFY_DONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cros_ec_cec_set_log_addr(struct cec_adapter *adap, u8 logical_addr)
|
|
||||||
{
|
|
||||||
struct cros_ec_cec_port *port = adap->priv;
|
|
||||||
struct cros_ec_cec *cros_ec_cec = port->cros_ec_cec;
|
|
||||||
struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec;
|
|
||||||
struct ec_params_cec_set params = {
|
|
||||||
.cmd = CEC_CMD_LOGICAL_ADDRESS,
|
|
||||||
.port = port->port_num,
|
|
||||||
.val = logical_addr,
|
|
||||||
};
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = cros_ec_cmd(cros_ec, 0, EC_CMD_CEC_SET, ¶ms, sizeof(params),
|
|
||||||
NULL, 0);
|
|
||||||
if (ret < 0) {
|
|
||||||
dev_err(cros_ec->dev,
|
|
||||||
"error setting CEC logical address on EC: %d\n", ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cros_ec_cec_transmit(struct cec_adapter *adap, u8 attempts,
|
|
||||||
u32 signal_free_time, struct cec_msg *cec_msg)
|
|
||||||
{
|
|
||||||
struct cros_ec_cec_port *port = adap->priv;
|
|
||||||
struct cros_ec_cec *cros_ec_cec = port->cros_ec_cec;
|
|
||||||
struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec;
|
|
||||||
struct ec_params_cec_write params;
|
|
||||||
struct ec_params_cec_write_v1 params_v1;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (cros_ec_cec->write_cmd_version == 0) {
|
|
||||||
memcpy(params.msg, cec_msg->msg, cec_msg->len);
|
|
||||||
ret = cros_ec_cmd(cros_ec, 0, EC_CMD_CEC_WRITE_MSG, ¶ms,
|
|
||||||
cec_msg->len, NULL, 0);
|
|
||||||
} else {
|
|
||||||
params_v1.port = port->port_num;
|
|
||||||
params_v1.msg_len = cec_msg->len;
|
|
||||||
memcpy(params_v1.msg, cec_msg->msg, cec_msg->len);
|
|
||||||
ret = cros_ec_cmd(cros_ec, cros_ec_cec->write_cmd_version,
|
|
||||||
EC_CMD_CEC_WRITE_MSG, ¶ms_v1,
|
|
||||||
sizeof(params_v1), NULL, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ret < 0) {
|
|
||||||
dev_err(cros_ec->dev,
|
|
||||||
"error writing CEC msg on EC: %d\n", ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cros_ec_cec_adap_enable(struct cec_adapter *adap, bool enable)
|
|
||||||
{
|
|
||||||
struct cros_ec_cec_port *port = adap->priv;
|
|
||||||
struct cros_ec_cec *cros_ec_cec = port->cros_ec_cec;
|
|
||||||
struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec;
|
|
||||||
struct ec_params_cec_set params = {
|
|
||||||
.cmd = CEC_CMD_ENABLE,
|
|
||||||
.port = port->port_num,
|
|
||||||
.val = enable,
|
|
||||||
};
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = cros_ec_cmd(cros_ec, 0, EC_CMD_CEC_SET, ¶ms, sizeof(params),
|
|
||||||
NULL, 0);
|
|
||||||
if (ret < 0) {
|
|
||||||
dev_err(cros_ec->dev,
|
|
||||||
"error %sabling CEC on EC: %d\n",
|
|
||||||
(enable ? "en" : "dis"), ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct cec_adap_ops cros_ec_cec_ops = {
|
|
||||||
.adap_enable = cros_ec_cec_adap_enable,
|
|
||||||
.adap_log_addr = cros_ec_cec_set_log_addr,
|
|
||||||
.adap_transmit = cros_ec_cec_transmit,
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef CONFIG_PM_SLEEP
|
|
||||||
static int cros_ec_cec_suspend(struct device *dev)
|
|
||||||
{
|
|
||||||
struct platform_device *pdev = to_platform_device(dev);
|
|
||||||
struct cros_ec_cec *cros_ec_cec = dev_get_drvdata(&pdev->dev);
|
|
||||||
|
|
||||||
if (device_may_wakeup(dev))
|
|
||||||
enable_irq_wake(cros_ec_cec->cros_ec->irq);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cros_ec_cec_resume(struct device *dev)
|
|
||||||
{
|
|
||||||
struct platform_device *pdev = to_platform_device(dev);
|
|
||||||
struct cros_ec_cec *cros_ec_cec = dev_get_drvdata(&pdev->dev);
|
|
||||||
|
|
||||||
if (device_may_wakeup(dev))
|
|
||||||
disable_irq_wake(cros_ec_cec->cros_ec->irq);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static SIMPLE_DEV_PM_OPS(cros_ec_cec_pm_ops,
|
|
||||||
cros_ec_cec_suspend, cros_ec_cec_resume);
|
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_PCI) && IS_ENABLED(CONFIG_DMI)
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Specify the DRM device name handling the HDMI output and the HDMI connector
|
|
||||||
* corresponding to each CEC port. The order of connectors must match the order
|
|
||||||
* in the EC (first connector is EC port 0, ...), and the number of connectors
|
|
||||||
* must match the number of ports in the EC (which can be queried using the
|
|
||||||
* EC_CMD_CEC_PORT_COUNT host command).
|
|
||||||
*/
|
|
||||||
|
|
||||||
struct cec_dmi_match {
|
|
||||||
const char *sys_vendor;
|
|
||||||
const char *product_name;
|
|
||||||
const char *devname;
|
|
||||||
const char *const *conns;
|
|
||||||
};
|
|
||||||
|
|
||||||
static const char *const port_b_conns[] = { "Port B", NULL };
|
|
||||||
static const char *const port_c_conns[] = { "Port C", NULL };
|
|
||||||
static const char *const port_db_conns[] = { "Port D", "Port B", NULL };
|
|
||||||
static const char *const port_ba_conns[] = { "Port B", "Port A", NULL };
|
|
||||||
static const char *const port_ab_conns[] = { "Port A", "Port B", NULL };
|
|
||||||
static const char *const port_d_conns[] = { "Port D", NULL };
|
|
||||||
|
|
||||||
static const struct cec_dmi_match cec_dmi_match_table[] = {
|
|
||||||
/* AMD Lilac */
|
|
||||||
{ "AMD", "Lilac", "0000:03:00.0", port_c_conns },
|
|
||||||
/* Valve Fremont */
|
|
||||||
{ "OEM", "F7F", "0000:03:00.0", port_c_conns },
|
|
||||||
{ "Valve", "Fremont", "0000:03:00.0", port_c_conns },
|
|
||||||
/* Google Fizz */
|
|
||||||
{ "Google", "Fizz", "0000:00:02.0", port_b_conns },
|
|
||||||
/* Google Brask */
|
|
||||||
{ "Google", "Brask", "0000:00:02.0", port_b_conns },
|
|
||||||
/* Google Moli */
|
|
||||||
{ "Google", "Moli", "0000:00:02.0", port_b_conns },
|
|
||||||
/* Google Kinox */
|
|
||||||
{ "Google", "Kinox", "0000:00:02.0", port_b_conns },
|
|
||||||
/* Google Kuldax */
|
|
||||||
{ "Google", "Kuldax", "0000:00:02.0", port_b_conns },
|
|
||||||
/* Google Aurash */
|
|
||||||
{ "Google", "Aurash", "0000:00:02.0", port_b_conns },
|
|
||||||
/* Google Gladios */
|
|
||||||
{ "Google", "Gladios", "0000:00:02.0", port_b_conns },
|
|
||||||
/* Google Lisbon */
|
|
||||||
{ "Google", "Lisbon", "0000:00:02.0", port_b_conns },
|
|
||||||
/* Google Dibbi */
|
|
||||||
{ "Google", "Dibbi", "0000:00:02.0", port_db_conns },
|
|
||||||
/* Google Constitution */
|
|
||||||
{ "Google", "Constitution", "0000:00:02.0", port_ba_conns },
|
|
||||||
/* Google Boxy */
|
|
||||||
{ "Google", "Boxy", "0000:00:02.0", port_d_conns },
|
|
||||||
/* Google Taranza */
|
|
||||||
{ "Google", "Taranza", "0000:00:02.0", port_db_conns },
|
|
||||||
/* Google Dexi */
|
|
||||||
{ "Google", "Dexi", "0000:00:02.0", port_db_conns },
|
|
||||||
/* Google Dita */
|
|
||||||
{ "Google", "Dita", "0000:00:02.0", port_db_conns },
|
|
||||||
/* Google Dirks */
|
|
||||||
{ "Google", "Dirks", "0000:00:02.0", port_ab_conns },
|
|
||||||
/* Google Moxie */
|
|
||||||
{ "Google", "Moxie", "0000:00:02.0", port_b_conns },
|
|
||||||
/* AMD Lilac */
|
|
||||||
{ "AMD", "Lilac", "0000:06:00.0", port_c_conns },
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct device *cros_ec_cec_find_hdmi_dev(struct device *dev,
|
|
||||||
const char * const **conns)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0 ; i < ARRAY_SIZE(cec_dmi_match_table) ; ++i) {
|
|
||||||
const struct cec_dmi_match *m = &cec_dmi_match_table[i];
|
|
||||||
|
|
||||||
if (dmi_match(DMI_SYS_VENDOR, m->sys_vendor) &&
|
|
||||||
dmi_match(DMI_PRODUCT_NAME, m->product_name)) {
|
|
||||||
struct device *d;
|
|
||||||
|
|
||||||
/* Find the device, bail out if not yet registered */
|
|
||||||
d = bus_find_device_by_name(&pci_bus_type, NULL,
|
|
||||||
m->devname);
|
|
||||||
if (!d)
|
|
||||||
return ERR_PTR(-EPROBE_DEFER);
|
|
||||||
put_device(d);
|
|
||||||
*conns = m->conns;
|
|
||||||
return d;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Hardware support must be added in the cec_dmi_match_table */
|
|
||||||
dev_warn(dev, "CEC notifier not configured for this hardware\n");
|
|
||||||
|
|
||||||
return ERR_PTR(-ENODEV);
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
static struct device *cros_ec_cec_find_hdmi_dev(struct device *dev,
|
|
||||||
const char * const **conns)
|
|
||||||
{
|
|
||||||
return ERR_PTR(-ENODEV);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static int cros_ec_cec_get_num_ports(struct cros_ec_cec *cros_ec_cec)
|
|
||||||
{
|
|
||||||
struct ec_response_cec_port_count response;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = cros_ec_cmd(cros_ec_cec->cros_ec, 0, EC_CMD_CEC_PORT_COUNT, NULL,
|
|
||||||
0, &response, sizeof(response));
|
|
||||||
if (ret < 0) {
|
|
||||||
/*
|
|
||||||
* Old EC firmware only supports one port and does not support
|
|
||||||
* the port count command, so fall back to assuming one port.
|
|
||||||
*/
|
|
||||||
cros_ec_cec->num_ports = 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (response.port_count == 0) {
|
|
||||||
dev_err(cros_ec_cec->cros_ec->dev,
|
|
||||||
"EC reports 0 CEC ports\n");
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (response.port_count > EC_CEC_MAX_PORTS) {
|
|
||||||
dev_err(cros_ec_cec->cros_ec->dev,
|
|
||||||
"EC reports too many ports: %d\n", response.port_count);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
cros_ec_cec->num_ports = response.port_count;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cros_ec_cec_get_write_cmd_version(struct cros_ec_cec *cros_ec_cec)
|
|
||||||
{
|
|
||||||
struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec;
|
|
||||||
struct ec_params_get_cmd_versions_v1 params = {
|
|
||||||
.cmd = EC_CMD_CEC_WRITE_MSG,
|
|
||||||
};
|
|
||||||
struct ec_response_get_cmd_versions response;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = cros_ec_cmd(cros_ec, 1, EC_CMD_GET_CMD_VERSIONS, ¶ms,
|
|
||||||
sizeof(params), &response, sizeof(response));
|
|
||||||
if (ret < 0) {
|
|
||||||
dev_err(cros_ec->dev,
|
|
||||||
"error getting CEC write command version: %d\n", ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (response.version_mask & EC_VER_MASK(1)) {
|
|
||||||
cros_ec_cec->write_cmd_version = 1;
|
|
||||||
} else {
|
|
||||||
if (cros_ec_cec->num_ports != 1) {
|
|
||||||
dev_err(cros_ec->dev,
|
|
||||||
"v0 write command only supports 1 port, %d reported\n",
|
|
||||||
cros_ec_cec->num_ports);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
cros_ec_cec->write_cmd_version = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cros_ec_cec_init_port(struct device *dev,
|
|
||||||
struct cros_ec_cec *cros_ec_cec,
|
|
||||||
int port_num, struct device *hdmi_dev,
|
|
||||||
const char * const *conns)
|
|
||||||
{
|
|
||||||
struct cros_ec_cec_port *port;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
|
|
||||||
if (!port)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
port->cros_ec_cec = cros_ec_cec;
|
|
||||||
port->port_num = port_num;
|
|
||||||
|
|
||||||
port->adap = cec_allocate_adapter(&cros_ec_cec_ops, port, DRV_NAME,
|
|
||||||
CEC_CAP_DEFAULTS |
|
|
||||||
CEC_CAP_CONNECTOR_INFO, 1);
|
|
||||||
if (IS_ERR(port->adap))
|
|
||||||
return PTR_ERR(port->adap);
|
|
||||||
|
|
||||||
if (!conns[port_num]) {
|
|
||||||
dev_err(dev, "no conn for port %d\n", port_num);
|
|
||||||
ret = -ENODEV;
|
|
||||||
goto out_probe_adapter;
|
|
||||||
}
|
|
||||||
|
|
||||||
port->notify = cec_notifier_cec_adap_register(hdmi_dev, conns[port_num],
|
|
||||||
port->adap);
|
|
||||||
if (!port->notify) {
|
|
||||||
ret = -ENOMEM;
|
|
||||||
goto out_probe_adapter;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = cec_register_adapter(port->adap, dev);
|
|
||||||
if (ret < 0)
|
|
||||||
goto out_probe_notify;
|
|
||||||
|
|
||||||
cros_ec_cec->ports[port_num] = port;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
out_probe_notify:
|
|
||||||
cec_notifier_cec_adap_unregister(port->notify, port->adap);
|
|
||||||
out_probe_adapter:
|
|
||||||
cec_delete_adapter(port->adap);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cros_ec_cec_probe(struct platform_device *pdev)
|
|
||||||
{
|
|
||||||
struct cros_ec_dev *ec_dev = dev_get_drvdata(pdev->dev.parent);
|
|
||||||
struct cros_ec_device *cros_ec = ec_dev->ec_dev;
|
|
||||||
struct cros_ec_cec *cros_ec_cec;
|
|
||||||
struct cros_ec_cec_port *port;
|
|
||||||
struct device *hdmi_dev;
|
|
||||||
const char * const *conns = NULL;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
hdmi_dev = cros_ec_cec_find_hdmi_dev(&pdev->dev, &conns);
|
|
||||||
if (IS_ERR(hdmi_dev))
|
|
||||||
return PTR_ERR(hdmi_dev);
|
|
||||||
|
|
||||||
cros_ec_cec = devm_kzalloc(&pdev->dev, sizeof(*cros_ec_cec),
|
|
||||||
GFP_KERNEL);
|
|
||||||
if (!cros_ec_cec)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
platform_set_drvdata(pdev, cros_ec_cec);
|
|
||||||
cros_ec_cec->cros_ec = cros_ec;
|
|
||||||
|
|
||||||
device_init_wakeup(&pdev->dev, 1);
|
|
||||||
|
|
||||||
ret = cros_ec_cec_get_num_ports(cros_ec_cec);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
ret = cros_ec_cec_get_write_cmd_version(cros_ec_cec);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
for (int i = 0; i < cros_ec_cec->num_ports; i++) {
|
|
||||||
ret = cros_ec_cec_init_port(&pdev->dev, cros_ec_cec, i,
|
|
||||||
hdmi_dev, conns);
|
|
||||||
if (ret)
|
|
||||||
goto unregister_ports;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get CEC events from the EC. */
|
|
||||||
cros_ec_cec->notifier.notifier_call = cros_ec_cec_event;
|
|
||||||
ret = blocking_notifier_chain_register(&cros_ec->event_notifier,
|
|
||||||
&cros_ec_cec->notifier);
|
|
||||||
if (ret) {
|
|
||||||
dev_err(&pdev->dev, "failed to register notifier\n");
|
|
||||||
goto unregister_ports;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
unregister_ports:
|
|
||||||
/*
|
|
||||||
* Unregister any adapters which have been registered. We don't add the
|
|
||||||
* port to the array until the adapter has been registered successfully,
|
|
||||||
* so any non-NULL ports must have been registered.
|
|
||||||
*/
|
|
||||||
for (int i = 0; i < cros_ec_cec->num_ports; i++) {
|
|
||||||
port = cros_ec_cec->ports[i];
|
|
||||||
if (!port)
|
|
||||||
break;
|
|
||||||
cec_notifier_cec_adap_unregister(port->notify, port->adap);
|
|
||||||
cec_unregister_adapter(port->adap);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void cros_ec_cec_remove(struct platform_device *pdev)
|
|
||||||
{
|
|
||||||
struct cros_ec_cec *cros_ec_cec = platform_get_drvdata(pdev);
|
|
||||||
struct device *dev = &pdev->dev;
|
|
||||||
struct cros_ec_cec_port *port;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* blocking_notifier_chain_unregister() only fails if the notifier isn't
|
|
||||||
* in the list. We know it was added to it by .probe(), so there should
|
|
||||||
* be no need for error checking. Be cautious and still check.
|
|
||||||
*/
|
|
||||||
ret = blocking_notifier_chain_unregister(
|
|
||||||
&cros_ec_cec->cros_ec->event_notifier,
|
|
||||||
&cros_ec_cec->notifier);
|
|
||||||
if (ret)
|
|
||||||
dev_err(dev, "failed to unregister notifier\n");
|
|
||||||
|
|
||||||
for (int i = 0; i < cros_ec_cec->num_ports; i++) {
|
|
||||||
port = cros_ec_cec->ports[i];
|
|
||||||
cec_notifier_cec_adap_unregister(port->notify, port->adap);
|
|
||||||
cec_unregister_adapter(port->adap);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct platform_device_id cros_ec_cec_id[] = {
|
|
||||||
{ DRV_NAME, 0 },
|
|
||||||
{}
|
|
||||||
};
|
|
||||||
MODULE_DEVICE_TABLE(platform, cros_ec_cec_id);
|
|
||||||
|
|
||||||
static struct platform_driver cros_ec_cec_driver = {
|
|
||||||
.probe = cros_ec_cec_probe,
|
|
||||||
.remove = cros_ec_cec_remove,
|
|
||||||
.driver = {
|
|
||||||
.name = DRV_NAME,
|
|
||||||
.pm = &cros_ec_cec_pm_ops,
|
|
||||||
},
|
|
||||||
.id_table = cros_ec_cec_id,
|
|
||||||
};
|
|
||||||
|
|
||||||
module_platform_driver(cros_ec_cec_driver);
|
|
||||||
|
|
||||||
MODULE_DESCRIPTION("CEC driver for ChromeOS ECs");
|
|
||||||
MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
|
|
||||||
MODULE_LICENSE("GPL");
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# Steamify: gamescope-session starts gamescope without a size or a refresh rate, so it takes the display's *preferred* mode,
|
|
||||||
# which many monitors declare as 60 Hz (the faster modes sit in an extension block of the EDID). This starts it the way the
|
|
||||||
# desktop runs that display: the mode KDE has saved for the connected display (System Settings > Display), when the display
|
|
||||||
# still has it, else its biggest mode at the highest refresh rate.
|
|
||||||
# Read at every session start (modetest, part of libdrm which gamescope needs, and KDE's ~/.config/kwinoutputconfig.json), so
|
|
||||||
# changing the resolution in KDE, another monitor or a TV just works. Anything unclear (no modetest output, no modes, more than
|
|
||||||
# one display connected: gamescope chooses which one it uses) leaves gamescope's own choice alone.
|
|
||||||
real=/usr/bin/gamescope
|
|
||||||
|
|
||||||
modes() {
|
|
||||||
# One line per mode of every connected connector: "<connector> <width> <height> <refresh>"
|
|
||||||
local m
|
|
||||||
for m in nvidia-drm amdgpu i915 xe nouveau radeon; do
|
|
||||||
timeout 10 modetest -M "$m" -c 2>/dev/null | awk '
|
|
||||||
/^[0-9]+[ \t]+[0-9]+[ \t]+(connected|disconnected|unknown)/ { conn = ($3 == "connected") ? $4 : ""; next }
|
|
||||||
conn != "" && /^[ \t]+#[0-9]+ [0-9]+x[0-9]+ [0-9.]+ / && !/interlace/ {
|
|
||||||
split($2, wh, "x"); printf "%s %d %d %.0f\n", conn, wh[1], wh[2], $3
|
|
||||||
}'
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
kde_mode() {
|
|
||||||
# kde_mode <connector>: "<width> <height> <refresh>" as KDE has it saved for that connector, or nothing.
|
|
||||||
python3 -I - "$1" "${XDG_CONFIG_HOME:-$HOME/.config}/kwinoutputconfig.json" 2>/dev/null << 'EOF'
|
|
||||||
import json, sys
|
|
||||||
try:
|
|
||||||
for block in json.load(open(sys.argv[2])):
|
|
||||||
if block.get("name") == "outputs":
|
|
||||||
for o in block.get("data", []):
|
|
||||||
m = o.get("mode")
|
|
||||||
if o.get("connectorName") == sys.argv[1] and m:
|
|
||||||
print(m["width"], m["height"], round(m["refreshRate"] / 1000))
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
EOF
|
|
||||||
}
|
|
||||||
|
|
||||||
args=()
|
|
||||||
all="$(modes)"
|
|
||||||
conn="$(awk '{print $1}' <<< "$all" | sort -u)"
|
|
||||||
if [[ -n "$conn" && "$(wc -l <<< "$conn")" == 1 ]]; then
|
|
||||||
read -r w h r <<< "$(kde_mode "$conn")"
|
|
||||||
# KDE's mode only counts when the display really has it (a refresh rate within 1 Hz).
|
|
||||||
if [[ -z "${w:-}" ]] || ! awk -v w="$w" -v h="${h:-0}" -v r="${r:-0}" '$2 == w && $3 == h && ($4 - r < 2 && r - $4 < 2) {f = 1} END {exit !f}' <<< "$all"; then
|
|
||||||
read -r _ w h r < <(awk '{print $2 * $3, $2, $3, $4}' <<< "$all" | sort -k1,1nr -k4,4nr | head -1 | awk '{print "x", $2, $3, $4}')
|
|
||||||
fi
|
|
||||||
[[ "${w:-0}" -gt 0 && "${h:-0}" -gt 0 && "${r:-0}" -gt 0 ]] && args=(-W "$w" -H "$h" -r "$r")
|
|
||||||
fi
|
|
||||||
if [[ "${1:-}" == --print-args ]]; then echo "${args[*]}"; exit 0; fi
|
|
||||||
exec "$real" "${args[@]}" "$@"
|
|
||||||
File diff suppressed because it is too large.
Load diff
@@ -1,128 +0,0 @@
|
|||||||
# Maintainer: theupriser
|
|
||||||
# Based on Arch Linux's gamescope PKGBUILD (Maxime Gauduin, Giancarlo Razzolini, Sven-Hendrik Haase and contributors).
|
|
||||||
#
|
|
||||||
# gamescope with GBM-allocated scan-out buffers for NVIDIA (opt-in: gamescope_drm_gbm_scanout=1).
|
|
||||||
# The patches are gamescope-gbm-scanout.patch and gamescope-ui-native.patch (next to this file, applied in this order); see the
|
|
||||||
# README for where they come from.
|
|
||||||
# UPSTREAM_VERSION (next to this file) names the gamescope tag the patches are made for.
|
|
||||||
|
|
||||||
pkgname=steamify-gamescope-nvidia
|
|
||||||
_srcname=gamescope
|
|
||||||
pkgver=3.16.31
|
|
||||||
pkgrel=3
|
|
||||||
pkgdesc='SteamOS session compositing window manager, with GBM scan-out for NVIDIA (opt-in: gamescope_drm_gbm_scanout=1)'
|
|
||||||
arch=(x86_64)
|
|
||||||
url=https://github.com/theupriser/steamify-gamescope-nvidia
|
|
||||||
license=(
|
|
||||||
BSD-2-Clause
|
|
||||||
BSD-3-Clause
|
|
||||||
LicenseRef-Reshade
|
|
||||||
)
|
|
||||||
provides=("gamescope=$pkgver")
|
|
||||||
conflicts=(gamescope gamescope-nvidia-gbm)
|
|
||||||
replaces=(gamescope-nvidia-gbm)
|
|
||||||
depends=(
|
|
||||||
glibc
|
|
||||||
mesa
|
|
||||||
libstdc++
|
|
||||||
libgcc
|
|
||||||
lcms2
|
|
||||||
libavif
|
|
||||||
libcap.so
|
|
||||||
libdecor
|
|
||||||
libdrm
|
|
||||||
libei
|
|
||||||
libinput
|
|
||||||
libpipewire-0.3.so
|
|
||||||
libx11
|
|
||||||
libxcb
|
|
||||||
libxcomposite
|
|
||||||
libxcursor
|
|
||||||
libxdamage
|
|
||||||
libxext
|
|
||||||
libxfixes
|
|
||||||
libxi
|
|
||||||
libxkbcommon.so
|
|
||||||
libxmu
|
|
||||||
libxrender
|
|
||||||
libxres
|
|
||||||
libxtst
|
|
||||||
libxxf86vm
|
|
||||||
luajit
|
|
||||||
pixman
|
|
||||||
sdl2
|
|
||||||
seatd
|
|
||||||
systemd-libs
|
|
||||||
vulkan-icd-loader
|
|
||||||
wayland
|
|
||||||
xcb-util-errors
|
|
||||||
xcb-util-wm
|
|
||||||
xorg-server-xwayland
|
|
||||||
)
|
|
||||||
makedepends=(
|
|
||||||
benchmark
|
|
||||||
cmake
|
|
||||||
git
|
|
||||||
glslang
|
|
||||||
meson
|
|
||||||
ninja
|
|
||||||
vulkan-headers
|
|
||||||
wayland-protocols
|
|
||||||
catch2
|
|
||||||
)
|
|
||||||
source=(
|
|
||||||
gamescope::git+https://github.com/ValveSoftware/gamescope.git#commit=${pkgver}
|
|
||||||
gamescope-gbm-scanout.patch
|
|
||||||
gamescope-ui-native.patch
|
|
||||||
git+https://gitlab.freedesktop.org/emersion/libdisplay-info.git
|
|
||||||
git+https://gitlab.freedesktop.org/emersion/libliftoff.git
|
|
||||||
git+https://github.com/ValveSoftware/openvr.git
|
|
||||||
git+https://github.com/Joshua-Ashton/reshade.git
|
|
||||||
git+https://github.com/KhronosGroup/SPIRV-Headers.git
|
|
||||||
git+https://github.com/Joshua-Ashton/vkroots.git
|
|
||||||
git+https://gitlab.freedesktop.org/wlroots/wlroots.git
|
|
||||||
)
|
|
||||||
b2sums=('SKIP'
|
|
||||||
'SKIP'
|
|
||||||
'SKIP'
|
|
||||||
'SKIP'
|
|
||||||
'SKIP'
|
|
||||||
'SKIP'
|
|
||||||
'SKIP'
|
|
||||||
'SKIP'
|
|
||||||
'SKIP'
|
|
||||||
'SKIP')
|
|
||||||
|
|
||||||
prepare() {
|
|
||||||
cd gamescope
|
|
||||||
|
|
||||||
# GBM scan-out for NVIDIA. If it no longer applies to this gamescope version, stop here: the build must not
|
|
||||||
# silently produce an unpatched gamescope under this package's name.
|
|
||||||
git apply --check ../gamescope-gbm-scanout.patch || { echo "gbm patch does not apply to gamescope ${pkgver}" >&2; return 1; }
|
|
||||||
git apply ../gamescope-gbm-scanout.patch
|
|
||||||
git apply --check ../gamescope-ui-native.patch || { echo "ui-native patch does not apply to gamescope ${pkgver}" >&2; return 1; }
|
|
||||||
git apply ../gamescope-ui-native.patch
|
|
||||||
|
|
||||||
meson subprojects download
|
|
||||||
|
|
||||||
for submodule in src/reshade subprojects/{libdisplay-info,libliftoff,openvr,vkroots,wlroots} thirdparty/SPIRV-Headers; do
|
|
||||||
git submodule init ${submodule}
|
|
||||||
git config submodule.${submodule}.url ../${submodule##*/}
|
|
||||||
done
|
|
||||||
git -c protocol.file.allow=always submodule update
|
|
||||||
}
|
|
||||||
|
|
||||||
build() {
|
|
||||||
arch-meson gamescope build \
|
|
||||||
-Dforce_fallback_for=glm,stb,libdisplay-info,libliftoff,vkroots \
|
|
||||||
-Dpipewire=enabled
|
|
||||||
meson compile -C build
|
|
||||||
}
|
|
||||||
|
|
||||||
package() {
|
|
||||||
DESTDIR="${pkgdir}" meson install -C build \
|
|
||||||
--skip-subprojects
|
|
||||||
install -Dm 644 gamescope/LICENSE -t "${pkgdir}"/usr/share/licenses/${pkgname}/
|
|
||||||
}
|
|
||||||
|
|
||||||
# vim: ts=2 sw=2 et:
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
Keeps Steam's UI X server (server 0) at the output size when Steam asks for a smaller one.
|
|
||||||
|
|
||||||
With -steamos3 (what gamescope-session-cachyos passes) Steam sets its UI to 1920x1080 right after it starts
|
|
||||||
(GAMESCOPE_XWAYLAND_MODE_CONTROL), so on a bigger display, and on one that isn't 16:9, the whole interface is a scaled-up
|
|
||||||
1080p picture. Games already run at the display's size. With this the server stays at the output size and Steam draws its
|
|
||||||
window to match; Steam's SteamOS features (settings pages, game launching) keep working. Written for Steamify on an NVIDIA
|
|
||||||
PC (RTX 5080, 3440x1440@175, tested with Steam's UI and a Proton game); not part of the farnoy patch. On by default; the
|
|
||||||
setting gamescope_xwayland_ui_native=0 (in gamescope's environment) turns it off.
|
|
||||||
Applies with `git apply` after gamescope-gbm-scanout.patch (it ignores these lines).
|
|
||||||
|
|
||||||
diff --git a/src/steamcompmgr.cpp b/src/steamcompmgr.cpp
|
|
||||||
index 2cb5eb5..ce14c8d 100644
|
|
||||||
--- a/src/steamcompmgr.cpp
|
|
||||||
+++ b/src/steamcompmgr.cpp
|
|
||||||
@@ -129,6 +129,8 @@ LogScope g_WaitableLog("waitable");
|
|
||||||
|
|
||||||
gamescope::ConVar<bool> cv_overlay_unmultiplied_alpha{ "overlay_unmultiplied_alpha", false };
|
|
||||||
|
|
||||||
+gamescope::ConVar<bool> cv_xwayland_ui_native( "xwayland_ui_native", true, "Keep the Steam UI X server (server 0) at the output size when Steam asks for a smaller one." );
|
|
||||||
+
|
|
||||||
gamescope::ConVar<bool> cv_vr_show_forwarded_overlays{ "vr_show_forwarded_overlays", false };
|
|
||||||
|
|
||||||
std::string *g_pVROverlayKey = nullptr;
|
|
||||||
@@ -7240,6 +7242,15 @@ handle_property_notify(xwayland_ctx_t *ctx, XPropertyEvent *ev)
|
|
||||||
height = std::min<int>(height, currentOutputHeight);
|
|
||||||
}
|
|
||||||
|
|
||||||
+ // Steam asks for a smaller size for its own UI (server 0, 1920x1080 with -steamos3), which makes the whole
|
|
||||||
+ // interface a scaled-up picture on a bigger display, and on one that isn't 16:9 as well. The UI server
|
|
||||||
+ // stays at the output size: Steam sizes its window to the server.
|
|
||||||
+ if ( server_idx == 0 && cv_xwayland_ui_native )
|
|
||||||
+ {
|
|
||||||
+ width = currentOutputWidth;
|
|
||||||
+ height = currentOutputHeight;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
gamescope_xwayland_server_t *server = wlserver_get_xwayland_server( server_idx );
|
|
||||||
if ( server )
|
|
||||||
{
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
# Maintainer: theupriser
|
|
||||||
# An empty package that only tells pacman "python-hid is there". For a PC that keeps python-hidapi (liquidctl needs it):
|
|
||||||
# the real python-hid conflicts with it, and jupiter-hw-support (a dependency of gamescope-session-cachyos) wants python-hid.
|
|
||||||
# Only Valve's Steam Deck controller firmware updater in jupiter-hw-support uses it, which a PC doesn't run.
|
|
||||||
# Steamify (lib/packages.sh) builds it with makepkg and installs it before the conversion's packages.
|
|
||||||
pkgname=steamify-python-hid-shim
|
|
||||||
pkgver=1
|
|
||||||
pkgrel=1
|
|
||||||
pkgdesc='Placeholder: python-hid for PCs that keep python-hidapi (they conflict)'
|
|
||||||
arch=(any)
|
|
||||||
license=(MIT)
|
|
||||||
depends=(python-hidapi)
|
|
||||||
provides=('python-hid=99')
|
|
||||||
|
|
||||||
package() {
|
|
||||||
:
|
|
||||||
}
|
|
||||||
@@ -7,11 +7,6 @@
|
|||||||
* leaves set on GPIO pin 18 (_SB.PCI0.GPP6) stays set, and the machine starts again right after powering off.
|
* leaves set on GPIO pin 18 (_SB.PCI0.GPP6) stays set, and the machine starts again right after powering off.
|
||||||
* Valve's kernel clears that bit at probe on Fremont (not for upstream);
|
* Valve's kernel clears that bit at probe on Fremont (not for upstream);
|
||||||
* this does the same right before power-off, for kernels without it.
|
* this does the same right before power-off, for kernels without it.
|
||||||
*
|
|
||||||
* What it does follows Valve's Steam Machine kernel
|
|
||||||
* (https://github.com/evlaV/linux-integration, GPL-2.0 like the rest of the
|
|
||||||
* Linux kernel); this module is Steamify's own implementation of it, also
|
|
||||||
* GPL-2.0. Not affiliated with or endorsed by Valve Corporation.
|
|
||||||
*/
|
*/
|
||||||
#include <linux/acpi.h>
|
#include <linux/acpi.h>
|
||||||
#include <linux/bits.h>
|
#include <linux/bits.h>
|
||||||
|
|||||||
@@ -12,5 +12,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` |
|
||||||
| `steamify-steam-autostart.service` | `lib/nvidia.sh` (Gaming on NVIDIA) | Steam at login on the Plasma desktop, normal or in Big Picture (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) |
|
||||||
|
| `steam-desktop-autostart.service` | `lib/steam-desktop.sh` (SteamOS conversion) | Steam in the background on the Plasma desktop (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) |
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Steam Background Autostart for Virtual Keyboard
|
||||||
|
After=graphical-session.target
|
||||||
|
PartOf=graphical-session.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
# Only in the Plasma desktop session; gamescope-session starts its own Steam.
|
||||||
|
ExecCondition=/bin/sh -c '[ "$XDG_CURRENT_DESKTOP" = KDE ]'
|
||||||
|
ExecStart=/usr/bin/steam -silent
|
||||||
|
Restart=on-failure
|
||||||
|
RestartSec=5
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=graphical-session.target
|
||||||
+2
-2
@@ -15,11 +15,11 @@
|
|||||||
set -uo pipefail
|
set -uo pipefail
|
||||||
|
|
||||||
# Release version, see CHANGELOG.md.
|
# Release version, see CHANGELOG.md.
|
||||||
VERSION=2.12.0
|
VERSION=2.11.0
|
||||||
|
|
||||||
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 gamescope-nvidia controllers 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
|
||||||
|
|||||||
@@ -0,0 +1,84 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Tests lib/controllers.sh (extended controller support: xone, the Xbox wireless dongle, and xpadneo, Xbox Bluetooth) with a stub pacman
|
||||||
|
# and a temp home. No root, VM or hardware needed: bash tests/controllers-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"; HOME="$T/home"; mkdir -p "$HOME"
|
||||||
|
source lib/common.sh; source lib/state.sh; source lib/controllers.sh; source lib/menu.sh
|
||||||
|
# Runs as the user, and refuses anything under the real system folders: a test must never touch them.
|
||||||
|
sudo() { local a; for a in "$@"; do case "$a" in /etc/*|/usr/*|/boot/*|/var/*) echo "REFUSED sudo $*" >&2; return 1 ;; esac; done; "$@"; }
|
||||||
|
info() { :; }; ok() { :; }; warn() { :; }; err() { echo "ERR $*"; }
|
||||||
|
kwriteconfig6() { local f="" k="" v=""; while [[ $# -gt 0 ]]; do case "$1" in --file) f="$2"; shift ;; --key) k="$2"; shift ;; --group) shift ;; *) v="$1" ;; esac; shift; done; mkdir -p "$(dirname "$f")"; sed -i "/^$k=/d" "$f" 2>/dev/null; printf '%s=%s\n' "$k" "$v" >> "$f"; }
|
||||||
|
kreadconfig6() { local f="" k=""; while [[ $# -gt 0 ]]; do case "$1" in --file) f="$2"; shift ;; --key) k="$2"; shift ;; --group|--default) shift ;; esac; shift; done; sed -n "s/^$k=//p" "$f" 2>/dev/null; }
|
||||||
|
# A pretend package database.
|
||||||
|
PKGS=""; PACMAN_LOG="$T/pacman.log"; : > "$PACMAN_LOG"; PACMAN_FAIL=0
|
||||||
|
pacman() {
|
||||||
|
case "$1" in
|
||||||
|
-Q) local p; for p in "${@:2}"; do [[ " $PKGS " == *" $p "* ]] || return 1; done ;;
|
||||||
|
-S) [[ $PACMAN_FAIL == 1 ]] && return 1; echo "S ${*:4}" >> "$PACMAN_LOG"; PKGS+=" ${*:4}" ;;
|
||||||
|
-Rns) echo "R ${*:3}" >> "$PACMAN_LOG"; local p; for p in ${*:3}; do PKGS=" ${PKGS// $p / } "; done ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
HEADERS=0; install_kernel_headers() { HEADERS=$((HEADERS + 1)); }
|
||||||
|
|
||||||
|
check "off to begin with" '! extended_controller_support_status'
|
||||||
|
extended_controller_support_enable
|
||||||
|
check "installs the repo's xpadneo-dkms, xone-dkms and the dongle firmware" 'pacman -Q xpadneo-dkms xone-dkms xone-dongle-firmware'
|
||||||
|
check "kernel headers are made sure of first" '[[ $HEADERS == 1 ]]'
|
||||||
|
check "what we installed is recorded" '[[ "$(state_get extended_controller_support installed_pkgs)" == "xpadneo-dkms xone-dkms xone-dongle-firmware" ]]'
|
||||||
|
check "it is on" extended_controller_support_status
|
||||||
|
n="$(wc -l < "$PACMAN_LOG")"; extended_controller_support_enable
|
||||||
|
check "a second run installs nothing again" '[[ "$(wc -l < "$PACMAN_LOG")" == "$n" ]]'
|
||||||
|
extended_controller_support_disable
|
||||||
|
check "off: the three packages are removed again" '! pacman -Q xpadneo-dkms 2>/dev/null && ! pacman -Q xone-dkms 2>/dev/null && ! pacman -Q xone-dongle-firmware 2>/dev/null && [[ -z "$(state_get extended_controller_support installed_pkgs)" ]]'
|
||||||
|
|
||||||
|
# The AUR's xone-dkms-git conflicts with the repo's xone-dkms: it counts, and is kept.
|
||||||
|
PKGS=" xone-dkms-git xone-dongle-firmware xpadneo-dkms"; : > "$PACMAN_LOG"
|
||||||
|
check "xone-dkms-git counts as xone: already on" extended_controller_support_status
|
||||||
|
extended_controller_support_enable; extended_controller_support_disable
|
||||||
|
check "with xone-dkms-git: nothing installed and nothing removed" '[[ ! -s "$PACMAN_LOG" ]] && pacman -Q xone-dkms-git xpadneo-dkms xone-dongle-firmware'
|
||||||
|
PKGS=" xone-dkms-git"
|
||||||
|
extended_controller_support_enable
|
||||||
|
check "xone-dkms-git present: only the missing ones are installed, never xone-dkms" 'grep -q "^S xpadneo-dkms xone-dongle-firmware$" "$PACMAN_LOG" && ! pacman -Q xone-dkms 2>/dev/null'
|
||||||
|
extended_controller_support_disable
|
||||||
|
check "and off removes only those two, xone-dkms-git stays" 'pacman -Q xone-dkms-git && ! pacman -Q xpadneo-dkms 2>/dev/null'
|
||||||
|
|
||||||
|
# A failed install is an error and records nothing.
|
||||||
|
PKGS=""; PACMAN_FAIL=1
|
||||||
|
check "a failed pacman is an error" '! extended_controller_support_enable >/dev/null'
|
||||||
|
check "...and records nothing" '[[ -z "$(state_get extended_controller_support installed_pkgs)" ]]'
|
||||||
|
PACMAN_FAIL=0
|
||||||
|
|
||||||
|
# Packages that were already there are never removed by turning it off.
|
||||||
|
PKGS=" xpadneo-dkms xone-dkms xone-dongle-firmware"; : > "$PACMAN_LOG"
|
||||||
|
extended_controller_support_enable; extended_controller_support_disable
|
||||||
|
check "packages you had before stay" 'pacman -Q xpadneo-dkms xone-dkms xone-dongle-firmware && [[ ! -s "$PACMAN_LOG" ]]'
|
||||||
|
|
||||||
|
# The menu.
|
||||||
|
check "offered on every PC" 'component_available extended_controller_support'
|
||||||
|
check "not preselected: it builds kernel modules for every kernel" '[[ " ${NO_PRESELECT[*]} " == *" extended_controller_support "* ]]'
|
||||||
|
check "a top-level item with a label" '[[ -z "${PARENT[extended_controller_support]:-}" && -n "${LABEL[extended_controller_support]}" ]]'
|
||||||
|
|
||||||
|
# The "new" badge: an opt-in option added after setup shows it, but is never ticked for you.
|
||||||
|
component_selectable() { return 0; }
|
||||||
|
declare -A CURRENT=([gaming]=1 [nvidia]=0 [extended_controller_support]=0 [vram]=0 [boot]=0)
|
||||||
|
rm -f "$STATE_DIR/features.state"
|
||||||
|
check "new opt-in option (conversion on, no record): the new badge" 'feature_new_optin extended_controller_support'
|
||||||
|
check "...but it is not ticked for you (not a new default option)" '! feature_new extended_controller_support'
|
||||||
|
check "...and the menu label says (new)" '[[ "$(menu_label extended_controller_support)" == *"(new)"* ]]'
|
||||||
|
check "a new default option is still ticked for you, and is not the opt-in kind" 'feature_new vram && ! feature_new_optin vram'
|
||||||
|
check "Boot into never gets the badge (it is a choice row)" '! feature_new_optin boot'
|
||||||
|
state_set_features() { kwriteconfig6 --file "$STATE_DIR/features.state" --group State --key "$1" "$2"; }
|
||||||
|
state_set_features extended_controller_support off
|
||||||
|
check "once a run recorded it as off, the badge is gone" '! feature_new_optin extended_controller_support'
|
||||||
|
rm -f "$STATE_DIR/features.state"
|
||||||
|
CURRENT[gaming]=0; CURRENT[nvidia]=1
|
||||||
|
check "on an NVIDIA PC (Gaming on NVIDIA on, no conversion) it shows too" 'feature_new_optin extended_controller_support'
|
||||||
|
CURRENT[nvidia]=0
|
||||||
|
check "with neither the conversion nor Gaming on NVIDIA on (a fresh PC) nothing is new" '! feature_new_optin extended_controller_support && ! feature_new vram'
|
||||||
|
CURRENT[gaming]=1; CURRENT[extended_controller_support]=1
|
||||||
|
check "already on: not new" '! feature_new_optin extended_controller_support'
|
||||||
|
exit $fail
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
#!/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
|
||||||
|
# patch_file (lib/common.sh) reads the hook script from $SCRIPT_DIR/patches.
|
||||||
|
SCRIPT_DIR="$PWD"
|
||||||
|
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
|
||||||
@@ -0,0 +1,206 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Tests lib/nvidia.sh ("Gaming on NVIDIA" and its Big Picture option) and the menu rules around it, against a fake RTX 5080
|
||||||
|
# (PCI 10de:2c02) beside an Intel iGPU, a stub modinfo, pacman and systemctl, and a temp home. 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"; HOME="$T/home"; mkdir -p "$HOME"
|
||||||
|
source lib/common.sh; source lib/state.sh; source lib/login-manager.sh; source lib/single-user.sh; source lib/hdmi-refresh.sh; source lib/vram-booster.sh; source lib/nvidia.sh; source lib/menu.sh
|
||||||
|
# Runs as the user, and refuses anything under the real system folders: a test must never touch them.
|
||||||
|
sudo() { local a; for a in "$@"; do case "$a" in /etc/*|/usr/*|/boot/*|/var/*) echo "REFUSED sudo $*" >&2; return 1 ;; esac; done; "$@"; }
|
||||||
|
info() { :; }; ok() { :; }; warn() { :; }; err() { echo "ERR $*"; }
|
||||||
|
# KDE's config tools on plain files under the temp home (a relative file name is relative to ~/.config, as in KDE).
|
||||||
|
kwriteconfig6() {
|
||||||
|
local f="" k="" v="" del=0
|
||||||
|
while [[ $# -gt 0 ]]; do case "$1" in --file) f="$2"; shift ;; --key) k="$2"; shift ;; --group) shift ;; --delete) del=1 ;; *) v="$1" ;; esac; shift; done
|
||||||
|
[[ "$f" == /* ]] || f="$HOME/.config/$f"; mkdir -p "$(dirname "$f")"
|
||||||
|
if [[ $del == 1 ]]; then sed -i "/^$k=/d" "$f" 2>/dev/null; else sed -i "/^$k=/d" "$f" 2>/dev/null; printf '%s=%s\n' "$k" "$v" >> "$f"; fi
|
||||||
|
}
|
||||||
|
kreadconfig6() {
|
||||||
|
local f="" k="" d="" r
|
||||||
|
while [[ $# -gt 0 ]]; do case "$1" in --file) f="$2"; shift ;; --key) k="$2"; shift ;; --default) d="$2"; shift ;; --group) shift ;; esac; shift; done
|
||||||
|
[[ "$f" == /* ]] || f="$HOME/.config/$f"
|
||||||
|
r="$(sed -n "s/^$k=//p" "$f" 2>/dev/null)"; printf '%s\n' "${r:-$d}"
|
||||||
|
}
|
||||||
|
# A pretend package database and systemd: what the tests assert on.
|
||||||
|
PKGS=""; PACMAN_LOG="$T/pacman.log"; : > "$PACMAN_LOG"; ENABLED=0
|
||||||
|
pacman() {
|
||||||
|
case "$1" in
|
||||||
|
-Q) [[ " $PKGS " == *" $2 "* ]] ;;
|
||||||
|
-S) echo "S $*" >> "$PACMAN_LOG"; PKGS+=" ${*: -1}" ;;
|
||||||
|
-Rns) echo "R $*" >> "$PACMAN_LOG"; PKGS=" ${PKGS//${*: -1}/} " ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
user_systemctl() {
|
||||||
|
case "$1" in
|
||||||
|
enable) ENABLED=1 ;;
|
||||||
|
disable) ENABLED=0 ;;
|
||||||
|
is-enabled) [[ $ENABLED == 1 ]] ;;
|
||||||
|
esac
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
FAKE_DRIVER=1; modinfo() { [[ "$FAKE_DRIVER" == 1 ]]; }
|
||||||
|
GAMING_ON=0; gaming_status() { [[ "$GAMING_ON" == 1 ]]; }
|
||||||
|
UNIT="$HOME/.config/systemd/user/$NVIDIA_UNIT"
|
||||||
|
|
||||||
|
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"
|
||||||
|
backup_file() { [[ -f "$1.bak" ]] || cp "$1" "$1.bak"; }
|
||||||
|
REBUILDS=0; nvidia_rebuild_boot() { REBUILDS=$((REBUILDS + 1)); }
|
||||||
|
: > "$T/cmdline"; NVIDIA_CMDLINE="$T/cmdline" # the running kernel's command line: without the parameters
|
||||||
|
NVIDIA_INITRAMFS_CONF="$T/90-steamify-nvidia.conf"
|
||||||
|
NVIDIA_SCRIPT="$T/libexec/steamify-nvidia-initramfs"; NVIDIA_HOOK="$T/hooks/85-steamify-nvidia-initramfs.hook"
|
||||||
|
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_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"
|
||||||
|
# The component's kernel step edits this boot loader file (systemd-boot's) in the tests, never a real one.
|
||||||
|
printf 'LINUX_OPTIONS="quiet"\n' > "$T/sdboot-manage.conf"; nvidia_boot_file() { echo "$T/sdboot-manage.conf"; }
|
||||||
|
|
||||||
|
# --- detection
|
||||||
|
check "finds the NVIDIA card as card1 beside an iGPU" nvidia_present
|
||||||
|
FAKE_DRIVER=0; check "no nvidia_drm module (nouveau): not an NVIDIA PC" '! nvidia_present'
|
||||||
|
FAKE_DRIVER=1; NVIDIA_DRM_DIR="$T/none"; check "no NVIDIA GPU: not an NVIDIA PC" '! nvidia_present'
|
||||||
|
NVIDIA_DRM_DIR="$T/drm"
|
||||||
|
|
||||||
|
# --- which items the menu shows
|
||||||
|
check "NVIDIA PC: the SteamOS conversion and its gamescope options are hidden" '! component_available gaming && ! component_available boot && ! component_available glyphs'
|
||||||
|
check "NVIDIA PC: Gaming on NVIDIA and Big Picture are shown" 'component_available nvidia && component_available bigpicture'
|
||||||
|
GAMING_ON=1
|
||||||
|
check "NVIDIA PC with the conversion already on: it is shown, so it can be turned off" 'component_available gaming && component_available boot'
|
||||||
|
check "...and Gaming on NVIDIA is hidden (both would start Steam)" '! component_available nvidia && ! component_available bigpicture'
|
||||||
|
GAMING_ON=0; NVIDIA_DRM_DIR="$T/none"
|
||||||
|
check "no NVIDIA: the conversion is shown as before" 'component_available gaming && component_available boot'
|
||||||
|
check "...and Gaming on NVIDIA is hidden" '! component_available nvidia && ! component_available bigpicture'
|
||||||
|
NVIDIA_DRM_DIR="$T/drm"
|
||||||
|
|
||||||
|
# --- "Add as non-Steam game" is for gaming mode's controller: not offered on an NVIDIA PC (unless already on)
|
||||||
|
steamgame_available() { return 0; }; STEAMGAME_ON=0; steamgame_status() { [[ "$STEAMGAME_ON" == 1 ]]; }
|
||||||
|
check "NVIDIA PC: Add as non-Steam game is hidden" '! component_available steamgame'
|
||||||
|
STEAMGAME_ON=1; check "...unless it is already on (so it can be turned off)" 'component_available steamgame'; STEAMGAME_ON=0
|
||||||
|
NVIDIA_DRM_DIR="$T/none"; check "no NVIDIA: it is offered as before" 'component_available steamgame'
|
||||||
|
steamgame_available() { return 1; }; check "no NVIDIA, no Steam account yet: still not offered" '! component_available steamgame'
|
||||||
|
steamgame_available() { return 0; }; NVIDIA_DRM_DIR="$T/drm"
|
||||||
|
|
||||||
|
# --- turning it on
|
||||||
|
check "off to begin with" '! nvidia_status && ! bigpicture_status'
|
||||||
|
nvidia_enable
|
||||||
|
check "Steam is installed when missing, and recorded as ours" 'grep -q "^S " "$PACMAN_LOG" && [[ "$(state_get nvidia installed_pkgs)" == steam ]]'
|
||||||
|
check "the autostart unit is written: Steam without arguments" 'grep -q "^ExecStart=/usr/bin/steam $" "$UNIT"'
|
||||||
|
check "it is on" 'nvidia_status && ! bigpicture_status'
|
||||||
|
n="$(wc -l < "$PACMAN_LOG")"; nvidia_enable
|
||||||
|
check "a second run installs nothing again" '[[ "$(wc -l < "$PACMAN_LOG")" == "$n" ]]'
|
||||||
|
|
||||||
|
# --- Big Picture
|
||||||
|
bigpicture_enable
|
||||||
|
check "Big Picture: Steam starts with -gamepadui" 'grep -q "^ExecStart=/usr/bin/steam -gamepadui$" "$UNIT" && bigpicture_status'
|
||||||
|
nvidia_enable
|
||||||
|
check "turning Gaming on NVIDIA on again keeps Big Picture" 'bigpicture_status'
|
||||||
|
check "Big Picture: Plasma starts with an empty session" '[[ "$(kreadconfig6 --file ksmserverrc --group General --key loginMode)" == emptySession ]]'
|
||||||
|
bigpicture_disable
|
||||||
|
check "Big Picture off: Steam's normal window again" '! bigpicture_status && nvidia_status'
|
||||||
|
check "...and the session setting is back as it was (not set)" '[[ -z "$(kreadconfig6 --file ksmserverrc --group General --key loginMode)" ]]'
|
||||||
|
|
||||||
|
# --- turning it off
|
||||||
|
bigpicture_enable; nvidia_disable
|
||||||
|
check "off: the unit is gone and Steam, which we installed, is removed" '! nvidia_status && [[ ! -e "$UNIT" ]] && ! pacman -Q steam && [[ -z "$(state_get nvidia installed_pkgs)" ]]'
|
||||||
|
check "Big Picture without the unit does nothing" 'bigpicture_enable && bigpicture_disable && [[ ! -e "$UNIT" ]]'
|
||||||
|
|
||||||
|
# --- Steam that was there already is never removed
|
||||||
|
PKGS=" steam"; : > "$PACMAN_LOG"
|
||||||
|
nvidia_enable; nvidia_disable
|
||||||
|
check "Steam installed before is kept, and not installed again" '[[ ! -s "$PACMAN_LOG" ]] && pacman -Q steam'
|
||||||
|
|
||||||
|
# --- kernel parameters and early modules (a supported card only: RTX 20 series or newer)
|
||||||
|
check "RTX 5080 (2c02) is supported: no chwd legacy lists" nvidia_supported
|
||||||
|
printf '1c03\n1b80\n' > "$T/chwd/nvidia-580.ids" # a GTX 1060 and a GTX 1080: chwd's 580xx legacy list
|
||||||
|
check "RTX 5080 is not on a legacy list" 'nvidia_supported && ! nvidia_legacy_gpu'
|
||||||
|
echo 0x1c03 > "$T/drm/card1/device/device"
|
||||||
|
check "GTX 1060 (older than RTX 20): no kernel setup, but still an NVIDIA PC" '! nvidia_supported && nvidia_legacy_gpu && nvidia_present'
|
||||||
|
echo 0x2c02 > "$T/drm/card1/device/device"
|
||||||
|
|
||||||
|
for loader in limine limineplus sdboot grub; do
|
||||||
|
case $loader in
|
||||||
|
limine) F="$T/limine"; printf 'KERNEL_CMDLINE[default]="quiet splash"\n' > "$F" ;;
|
||||||
|
# CachyOS writes its line as "+=" and may already have nvidia_drm.modeset=1 in it.
|
||||||
|
limineplus) F="$T/limine"; printf 'KERNEL_CMDLINE[default]+="quiet splash nvidia_drm.modeset=1"\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_kernel_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_kernel_enable
|
||||||
|
check "$loader: second run changes nothing" '[[ "$(cat "$F")" == "$SUM" && $REBUILDS == 1 ]]'
|
||||||
|
nvidia_kernel_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_kernel_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_kernel_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_kernel_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_kernel_enable >/dev/null && [[ $REBUILDS == 0 ]]'
|
||||||
|
FAKE_DRIVER=0; NVIDIA_DRM_DIR="$T/drm"; printf 'LINUX_OPTIONS="quiet"\n' > "$T/sdboot"; F="$T/sdboot"; REBUILDS=0; nvidia_kernel_enable
|
||||||
|
check "no NVIDIA driver: nothing touched" '[[ "$(cat "$F")" == "LINUX_OPTIONS=\"quiet\"" && $REBUILDS == 0 ]]'
|
||||||
|
|
||||||
|
# --- single user mode on NVIDIA: its own login step (SDDM, autologin into Plasma) without the conversion
|
||||||
|
FAKE_DRIVER=1; NVIDIA_DRM_DIR="$T/drm" # an earlier section ended without the driver
|
||||||
|
SW="$T/switches.log"; : > "$SW"; TARGET_USER=tester; SINGLE_AUTOLOGIN="$T/sddm.conf.d/zzz-steamify-autologin.conf"
|
||||||
|
switch_to_sddm() { echo sddm >> "$SW"; }; switch_to_plasmalogin() { echo plasmalogin >> "$SW"; }
|
||||||
|
remove_sddm_base_autologin() { :; } # would look at the real /etc/sddm.conf
|
||||||
|
GAMING_ON=0
|
||||||
|
check "single user mode is offered on NVIDIA without the conversion..." 'component_available single'
|
||||||
|
GAMING_ON=1; check "...and with it" 'component_available single'; GAMING_ON=0
|
||||||
|
single_login_enable
|
||||||
|
check "single user: SDDM, autologin of the user into the Plasma session" 'grep -qx "User=tester" "$SINGLE_AUTOLOGIN" && grep -qx "Session=plasma.desktop" "$SINGLE_AUTOLOGIN" && grep -qx "Relogin=true" "$SINGLE_AUTOLOGIN" && grep -qx sddm "$SW"'
|
||||||
|
c1="$(cat "$SINGLE_AUTOLOGIN")"; single_login_enable
|
||||||
|
check "single user login: a second run changes nothing" '[[ "$(cat "$SINGLE_AUTOLOGIN")" == "$c1" ]]'
|
||||||
|
single_login_disable
|
||||||
|
check "single user off: the file is gone and plasma-login-manager is the login manager again" '[[ ! -e "$SINGLE_AUTOLOGIN" ]] && grep -qx plasmalogin "$SW"'
|
||||||
|
: > "$SW"; GAMING_ON=1; single_login_enable
|
||||||
|
check "with the conversion on, single user mode leaves the login to it" '[[ ! -e "$SINGLE_AUTOLOGIN" && ! -s "$SW" ]]'
|
||||||
|
GAMING_ON=0
|
||||||
|
# --- the menu rules
|
||||||
|
declare -A WANTED=([nvidia]=1 [bigpicture]=1 [gaming]=0 [boot]=0 [single]=0 [machine]=0 [poweroff]=0 [launcher]=0 [steamgame]=0)
|
||||||
|
component_selectable() { return 0; }
|
||||||
|
toggle_component nvidia
|
||||||
|
check "unticking Gaming on NVIDIA unticks Big Picture" '[[ "${WANTED[nvidia]}" == 0 && "${WANTED[bigpicture]}" == 0 ]]'
|
||||||
|
toggle_component bigpicture
|
||||||
|
check "ticking Big Picture ticks Gaming on NVIDIA" '[[ "${WANTED[nvidia]}" == 1 && "${WANTED[bigpicture]}" == 1 ]]'
|
||||||
|
WANTED[single]=0; WANTED[gaming]=0; toggle_component single
|
||||||
|
check "ticking single user mode does not tick the conversion where it isn't offered" '[[ "${WANTED[single]}" == 1 && "${WANTED[gaming]}" == 0 ]]'
|
||||||
|
check "Big Picture follows Gaming on NVIDIA in the menu" '[[ " ${COMPONENTS[*]} " == *" nvidia bigpicture "* && "${PARENT[bigpicture]}" == nvidia ]]'
|
||||||
|
|
||||||
|
exit $fail
|
||||||
+5
-8
@@ -38,8 +38,8 @@ 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 || []
|
||||||
// Hidden: Big Picture excludes a silent start.
|
// Hidden: Big Picture excludes a silent start; on a Steam Machine a silent start needs "Boot into" desktop.
|
||||||
function hidden(i) { return i.id === "nvsilent" && want.bigpicture; }
|
function hidden(i) { return (i.id === "nvsilent" && want.bigpicture) || (i.needs === "boot" && boot !== "desktop"); }
|
||||||
readonly property var rows: items.filter(function (i) { return (!i.parent || want[i.parent]) && !hidden(i); })
|
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
|
||||||
|
|
||||||
@@ -65,8 +65,7 @@ Item {
|
|||||||
var w = {};
|
var w = {};
|
||||||
for (var i = 0; i < items.length; i++) w[items[i].id] = items[i].kind === "action" ? false : items[i].wanted;
|
for (var i = 0; i < items.length; i++) w[items[i].id] = items[i].kind === "action" ? false : items[i].wanted;
|
||||||
want = w;
|
want = w;
|
||||||
// (What the PC has, or what the backend ticked: "Gaming on NVIDIA" moving to the conversion keeps how Steam started.)
|
boot = nowOn("boot") ? "desktop" : "gamescope";
|
||||||
boot = want.boot ? "desktop" : "gamescope";
|
|
||||||
if (sel > rows.length) sel = 0;
|
if (sel > rows.length) sel = 0;
|
||||||
}
|
}
|
||||||
Connections { target: backend; function onStatusChanged() { if (app.screen === "menu" || app.screen === "done") app.syncFromStatus(); } }
|
Connections { target: backend; function onStatusChanged() { if (app.screen === "menu" || app.screen === "done") app.syncFromStatus(); } }
|
||||||
@@ -79,14 +78,13 @@ Item {
|
|||||||
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).
|
||||||
var hasGaming = items.some(function (i) { return i.id === "gaming"; });
|
var hasGaming = items.some(function (i) { return i.id === "gaming"; });
|
||||||
if (id === "gaming" && !w.gaming) { w.single = false; w.silent = false; w.glyphs = false; }
|
if (id === "gaming" && !w.gaming) { w.single = false; w.silent = false; }
|
||||||
if (id === "single" && w.single && hasGaming) w.gaming = true;
|
if (id === "single" && w.single && hasGaming) w.gaming = true;
|
||||||
if (id === "nvidia") w.bigpicture = w.nvidia;
|
if (id === "nvidia") w.bigpicture = w.nvidia;
|
||||||
if (id === "bigpicture" && w.bigpicture) { w.nvidia = true; w.nvsilent = false; }
|
if (id === "bigpicture" && w.bigpicture) { w.nvidia = true; w.nvsilent = false; }
|
||||||
if (id === "nvsilent" && w.nvsilent) { w.nvidia = true; w.bigpicture = false; }
|
if (id === "nvsilent" && w.nvsilent) { w.nvidia = true; w.bigpicture = false; }
|
||||||
if (id === "nvidia" && !w.nvidia) w.nvsilent = false;
|
if (id === "nvidia" && !w.nvidia) w.nvsilent = false;
|
||||||
if (id === "silent" && w.silent) w.gaming = true;
|
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;
|
||||||
@@ -102,8 +100,7 @@ Item {
|
|||||||
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 (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; }
|
||||||
// (An item that is off but flagged "update" replaces what the PC has: the conversion for "Gaming on NVIDIA".)
|
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: it.update ? "update" : "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" });
|
||||||
else if (want[it.id] && (reapply || it.update)) p.push({ id: it.id, action: reapply ? "again" : "update" });
|
else if (want[it.id] && (reapply || it.update)) p.push({ id: it.id, action: reapply ? "again" : "update" });
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -6,11 +6,11 @@ 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"] },
|
changes: ["Autologin into gamescope", "Return to Gaming Mode shortcut", "Steam starts silently on the desktop"] },
|
||||||
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",
|
silent: { label: "Start Steam silently", 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.",
|
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"] },
|
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",
|
nvidia: { label: "Gaming on NVIDIA", hint: "Steam on the desktop, started at login",
|
||||||
|
|||||||
Reference in new issue
Block a user