|
|
|
@@ -9,17 +9,12 @@ A 4th-generation Core i7 (Haswell) on a UEFI board with an NVIDIA GeForce GTX
|
|
|
|
|
is driven from the sofa with a Bluetooth controller; keyboard and mouse are
|
|
|
|
|
supported but secondary.
|
|
|
|
|
|
|
|
|
|
## Not installed yet
|
|
|
|
|
## Disk
|
|
|
|
|
|
|
|
|
|
`hardware-configuration.nix` in this host directory is a **placeholder**, not a
|
|
|
|
|
hardware scan. It exists so the flake evaluates in CI and assumes the install
|
|
|
|
|
labels its partitions `nixos` (root, ext4) and `BOOT` (ESP, vfat). Replace the
|
|
|
|
|
whole file with the output of `nixos-generate-config` run on the machine and
|
|
|
|
|
commit that. If the labels do not match, the boot fails on a missing device
|
|
|
|
|
rather than touching the wrong disk.
|
|
|
|
|
|
|
|
|
|
Partition the disk GPT with an ESP (vfat, 512 MB is comfortable). Nothing else
|
|
|
|
|
in the host config depends on the disk layout.
|
|
|
|
|
`hardware-configuration.nix` is a real `nixos-generate-config` scan from the
|
|
|
|
|
installed machine: GPT with a vfat ESP at `/boot` and an ext4 root, both
|
|
|
|
|
addressed by UUID, and no swap device. Nothing else in the host config depends
|
|
|
|
|
on the disk layout.
|
|
|
|
|
|
|
|
|
|
## Bootloader
|
|
|
|
|
|
|
|
|
@@ -88,7 +83,7 @@ to ReGreet, where the ordinary Sway session is available for everything else.
|
|
|
|
|
`services.greetd.restart` defaults to `false` once `initial_session` is set,
|
|
|
|
|
which is what stops a logout looping straight back into autologin.
|
|
|
|
|
|
|
|
|
|
Two details worth knowing:
|
|
|
|
|
Three details worth knowing:
|
|
|
|
|
|
|
|
|
|
- The launcher is referenced as `/run/current-system/sw/bin/steam-gamescope`.
|
|
|
|
|
The steam module builds that script privately and only adds it to
|
|
|
|
@@ -96,17 +91,92 @@ Two details worth knowing:
|
|
|
|
|
- `programs.gamescope.capSysNice = true` installs gamescope as a setcap wrapper
|
|
|
|
|
in `/run/wrappers/bin` instead of the system profile. That path precedes the
|
|
|
|
|
system profile on `PATH`, so `steam-gamescope` still resolves it.
|
|
|
|
|
- greetd gives the session the VT for its standard streams, so anything the
|
|
|
|
|
Steam session prints as it dies is erased the moment the greeter repaints.
|
|
|
|
|
`initial_session` therefore runs the launcher under `systemd-cat`, and the
|
|
|
|
|
output is readable after the fact with `journalctl -b -t steam-session`.
|
|
|
|
|
|
|
|
|
|
### When the television lands on ReGreet instead of Steam
|
|
|
|
|
|
|
|
|
|
greetd starts `initial_session` **once per boot** — the check is the presence of
|
|
|
|
|
`/run/greetd.run` — and if the session process starts and then exits, greetd
|
|
|
|
|
falls through to `default_session`, i.e. ReGreet. A gamescope that dies on
|
|
|
|
|
startup is therefore indistinguishable from autologin never having run, unless
|
|
|
|
|
the logs are read:
|
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
journalctl -b -t steam-session # what the session itself said
|
|
|
|
|
journalctl -b -u greetd # whether greetd started it at all
|
|
|
|
|
ls -l /run/greetd.run # exists => greetd has already had its one go
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
If greetd never even reaches the session, it prints `unable to start greeter`
|
|
|
|
|
and **exits** — there is no greeter to fall back to and the screen stays blank.
|
|
|
|
|
Recover over SSH (`modules/ssh.nix`), or hold space at power-on and boot the
|
|
|
|
|
previous generation.
|
|
|
|
|
|
|
|
|
|
To reproduce a session failure by hand, switch to a free VT and run
|
|
|
|
|
`steam-gamescope` there. Running it from inside Sway is not the same test:
|
|
|
|
|
gamescope picks its nested Wayland backend when `WAYLAND_DISPLAY` is set, and it
|
|
|
|
|
is the DRM backend — the one the boot session uses — that is in question.
|
|
|
|
|
|
|
|
|
|
The greeter is **Dvorak**, like every other host here (`modules/sway.nix` forces
|
|
|
|
|
`XKB_DEFAULT_VARIANT=dvorak` on cage). Only relevant if someone else has to type
|
|
|
|
|
a password.
|
|
|
|
|
|
|
|
|
|
### Adding RetroArch and Clone Hero to Big Picture
|
|
|
|
|
### The Sway session behind it
|
|
|
|
|
|
|
|
|
|
Both are installed system-wide but are not Steam titles. Add each once, from a
|
|
|
|
|
Sway session, via Steam's **Games → Add a Non-Steam Game**; they then appear in
|
|
|
|
|
Big Picture and inherit Steam Input, so the controller works in them without
|
|
|
|
|
further configuration.
|
|
|
|
|
Two fleet-wide rules in `home/sway.nix` matter more on a television than
|
|
|
|
|
anywhere else:
|
|
|
|
|
|
|
|
|
|
- Any output running at 4K is forced to **scale 2** (1920x1080 logical). Sway's
|
|
|
|
|
config cannot key an output rule on resolution, so a small user service
|
|
|
|
|
applies it at session start and again on every output event — which is what
|
|
|
|
|
makes it survive the TV being switched off and on.
|
|
|
|
|
- The emulators inhibit idle **while focused**, not only while fullscreen.
|
|
|
|
|
PCSX2 and Dolphin default to borderless-windowed rather than compositor
|
|
|
|
|
fullscreen, so the generic `inhibit_idle fullscreen` rules never fired and
|
|
|
|
|
swaylock cut in mid-game.
|
|
|
|
|
|
|
|
|
|
Neither applies in the Steam session: `swayidle` is a home-manager user service
|
|
|
|
|
wanted by `graphical-session.target` and conditional on `WAYLAND_DISPLAY`, and
|
|
|
|
|
the gamescope session starts neither, so nothing locks the screen in Big
|
|
|
|
|
Picture.
|
|
|
|
|
|
|
|
|
|
### Adding non-Steam titles to Big Picture
|
|
|
|
|
|
|
|
|
|
RetroArch, PCSX2, Dolphin and Clone Hero are installed system-wide but are not
|
|
|
|
|
Steam titles. Added as Steam shortcuts they appear in Big Picture and inherit
|
|
|
|
|
Steam Input, so the controller works in them without further configuration.
|
|
|
|
|
|
|
|
|
|
Steam's own **Games → Add a Non-Steam Game** is the documented route and is also
|
|
|
|
|
the one that does not work here: the dialog never appears at all. That dialog's
|
|
|
|
|
file browsing goes through the XDG desktop portal `FileChooser` interface, and
|
|
|
|
|
when the portal is unreachable the client falls back to a legacy chooser that is
|
|
|
|
|
blank or inert — Valve
|
|
|
|
|
[#9447](https://github.com/ValveSoftware/steam-for-linux/issues/9447), not fixed.
|
|
|
|
|
Check the portal side before blaming the client:
|
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
busctl --user introspect org.freedesktop.portal.Desktop \
|
|
|
|
|
/org/freedesktop/portal/desktop | grep FileChooser
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
`modules/sway.nix` enables `xdg-desktop-portal-gtk`, which is the backend that
|
|
|
|
|
implements `FileChooser` (`xdg-desktop-portal-wlr` implements only screenshot
|
|
|
|
|
and screencast), and the generated `sway-portals.conf` routes everything but
|
|
|
|
|
those two to `gtk`. If the interface is missing from the introspection above,
|
|
|
|
|
the backend is not running and that is the fault to chase.
|
|
|
|
|
|
|
|
|
|
Independent of the dialog, `steamtinkerlaunch` writes `shortcuts.vdf` directly:
|
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
# Steam must be closed -- it rewrites shortcuts.vdf on exit.
|
|
|
|
|
steamtinkerlaunch addnonsteamgame -an="RetroArch" -ep="$(command -v retroarch)"
|
|
|
|
|
steamtinkerlaunch addnonsteamgame -an="PCSX2" -ep="$(command -v pcsx2-qt)"
|
|
|
|
|
steamtinkerlaunch addnonsteamgame -an="Dolphin" -ep="$(command -v dolphin-emu)"
|
|
|
|
|
steamtinkerlaunch addnonsteamgame -an="Clone Hero" -ep="$(command -v clonehero)"
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## Emulation — RetroArch
|
|
|
|
|
|
|
|
|
@@ -167,15 +237,15 @@ system directory on this host:
|
|
|
|
|
Be honest about the two heaviest cores. `dolphin` and `pcsx2` are libretro ports
|
|
|
|
|
of emulators whose upstream effort goes into their **standalone** builds; the
|
|
|
|
|
cores lag on compatibility and are the first place to look when a GameCube, Wii
|
|
|
|
|
or PS2 title misbehaves. If a game does not cooperate, add the standalone
|
|
|
|
|
emulators to `environment.systemPackages` in `gaming.nix`:
|
|
|
|
|
or PS2 title misbehaves.
|
|
|
|
|
|
|
|
|
|
```nix
|
|
|
|
|
pkgs.dolphin-emu # GameCube / Wii
|
|
|
|
|
pkgs.pcsx2 # PlayStation 2
|
|
|
|
|
```
|
|
|
|
|
That has already happened for PS2: the LRPS2 core was not good enough in
|
|
|
|
|
practice. **`pkgs.pcsx2` and `pkgs.dolphin-emu` are both installed** in
|
|
|
|
|
`gaming.nix` alongside their cores, and are what PS2, GameCube and Wii titles
|
|
|
|
|
should be run through. The cores stay for the sake of a single frontend and a
|
|
|
|
|
shared save/state layout.
|
|
|
|
|
|
|
|
|
|
Both are controller-driven and can be added to Big Picture the same way as
|
|
|
|
|
Both are controller-driven and are added to Big Picture the same way as
|
|
|
|
|
RetroArch. The hardware is not the limit here — a GTX 1070 and a Haswell i7 run
|
|
|
|
|
PS2 and Wii comfortably.
|
|
|
|
|
|
|
|
|
@@ -226,10 +296,56 @@ RetroArch is pointed at these paths declaratively. The other two have to be told
|
|
|
|
|
once, in their own UIs:
|
|
|
|
|
|
|
|
|
|
- **Steam** — Settings → Storage → the `+` control → add `/srv/games/steam` as a
|
|
|
|
|
library folder. Games installed there survive a reinstall of the OS.
|
|
|
|
|
library folder. Games installed there survive a reinstall of the OS. See
|
|
|
|
|
[When Steam will not register the library folder](#when-steam-will-not-register-the-library-folder)
|
|
|
|
|
below; it does not currently take.
|
|
|
|
|
|
|
|
|
|
- **Clone Hero** — set the song library path to `/srv/games/clonehero/songs` from
|
|
|
|
|
its settings screen. Clone Hero keeps its own config in `~/.clonehero`.
|
|
|
|
|
|
|
|
|
|
### When Steam will not register the library folder
|
|
|
|
|
|
|
|
|
|
Current behaviour on this host: the file picker opens, Steam creates the
|
|
|
|
|
directory structure at `/srv/games/steam`, and the library then never appears in
|
|
|
|
|
the Storage UI. So this is not the portal problem the non-Steam-game dialog has
|
|
|
|
|
— the picker works and Steam can write. The failure is in the validation Steam
|
|
|
|
|
runs before it records the folder in `libraryfolders.vdf`.
|
|
|
|
|
|
|
|
|
|
That validation is a write-and-execute probe: Steam drops a
|
|
|
|
|
`.steam_exec_test.sh` in the candidate folder, marks it executable and runs it.
|
|
|
|
|
If either step fails the folder is silently dropped, which is
|
|
|
|
|
[#8450](https://github.com/ValveSoftware/steam-for-linux/issues/8450) and is
|
|
|
|
|
usually a `noexec` mount or an ownership problem — neither of which is obviously
|
|
|
|
|
true here, since `/srv` is on the ext4 root and the tree is
|
|
|
|
|
`lyrathorpe:users` 2775.
|
|
|
|
|
|
|
|
|
|
Reproduce the probe **inside Steam's FHS sandbox**, which is where the client
|
|
|
|
|
actually runs it — `steam-run` is installed by the steam module for exactly this
|
|
|
|
|
kind of thing:
|
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
steam-run sh -c '
|
|
|
|
|
printf "#!/bin/sh\nexit 0\n" > /srv/games/steam/.steam_exec_test.sh &&
|
|
|
|
|
chmod +x /srv/games/steam/.steam_exec_test.sh &&
|
|
|
|
|
/srv/games/steam/.steam_exec_test.sh &&
|
|
|
|
|
echo "probe ok"
|
|
|
|
|
'
|
|
|
|
|
rm -f /srv/games/steam/.steam_exec_test.sh
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Then ask the client directly. Steam's console reports a reason where the UI
|
|
|
|
|
says nothing — open Steam with `steam -console`, pick the **CONSOLE** tab and
|
|
|
|
|
run:
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
library_folder_add /srv/games/steam
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
The directory must already exist and be writable by the user Steam runs as,
|
|
|
|
|
which `systemd.tmpfiles` guarantees; the command does not create it. Whatever it
|
|
|
|
|
prints, plus `~/.steam/steam/logs/content_log.txt`, is the evidence to work
|
|
|
|
|
from.
|
|
|
|
|
|
|
|
|
|
## Steam and Proton
|
|
|
|
|
|
|
|
|
|
`programs.steam.enable` already arranges most of what Proton needs, and it is
|
|
|
|
@@ -311,17 +427,27 @@ wired 360 pads — as well as `mt76x2u`, and pulls in proprietary dongle firmwar
|
|
|
|
|
Not worth the side effects unless that dongle is actually in use, and if it ever
|
|
|
|
|
is, the 360 pads have to be re-tested.
|
|
|
|
|
|
|
|
|
|
## Untested claims
|
|
|
|
|
## Open problems
|
|
|
|
|
|
|
|
|
|
This host has not been built or booted yet. Two things are worth watching on
|
|
|
|
|
first boot:
|
|
|
|
|
The machine is installed and Sway works. Still outstanding:
|
|
|
|
|
|
|
|
|
|
- **gamescope on the proprietary NVIDIA driver.** `gaming.nix` sets
|
|
|
|
|
`GBM_BACKEND=nvidia-drm` and `__GLX_VENDOR_LIBRARY_NAME=nvidia` for the
|
|
|
|
|
session, which is the standard fix, but the combination has a history of
|
|
|
|
|
needing tweaks. If the session dies at startup, switch the greeter back to
|
|
|
|
|
interactive by commenting out `services.greetd.settings.initial_session`, log
|
|
|
|
|
into Sway, and read `journalctl --user -b`.
|
|
|
|
|
- **Autologin into Steam does not happen** — the television comes up on ReGreet.
|
|
|
|
|
Not yet root-caused; the config side is correct (`initial_session` is present
|
|
|
|
|
in the generated `greetd.toml` and `services.greetd.restart` evaluates to
|
|
|
|
|
`false`), so the suspicion is that gamescope starts and dies on the
|
|
|
|
|
proprietary NVIDIA driver, which greetd treats as a finished session and
|
|
|
|
|
answers by starting the greeter. `gaming.nix` sets `GBM_BACKEND=nvidia-drm`
|
|
|
|
|
and `__GLX_VENDOR_LIBRARY_NAME=nvidia`, the standard fix, but the combination
|
|
|
|
|
has a history of needing more. Read `journalctl -b -t steam-session` first —
|
|
|
|
|
see [When the television lands on ReGreet instead of Steam](#when-the-television-lands-on-regreet-instead-of-steam).
|
|
|
|
|
- **Steam will not register `/srv/games/steam` as a library folder.** The picker
|
|
|
|
|
opens and the directory structure gets created; the library never appears in
|
|
|
|
|
the Storage UI. Not the portal — see
|
|
|
|
|
[When Steam will not register the library folder](#when-steam-will-not-register-the-library-folder).
|
|
|
|
|
- **Steam's Add a Non-Steam Game dialog never appears.** Separate symptom,
|
|
|
|
|
probably the portal `FileChooser`; `steamtinkerlaunch` writes the shortcuts
|
|
|
|
|
without it in the meantime.
|
|
|
|
|
- **Boot into Big Picture has not been exercised**, since autologin has not run.
|
|
|
|
|
- **Television resolution and refresh.** gamescope takes the output's native
|
|
|
|
|
mode by default. Add `gamescopeSession.args = [ "-W" "3840" "-H" "2160" "-r"
|
|
|
|
|
"60" ]` if a specific mode is wanted.
|
|
|
|
|