This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

machines.coaxmetal: sway kiosk so nested gamescope keeps its wayland backend

Replace the greetd gamescope-session (which required STROM_NO_GAMESCOPE and
rendered games directly in the session compositor) with greetd launching sway.

A game's nested gamescope prefers its wayland backend, which needs wlroots
protocols that cage (and, differently, an outer gamescope session) do not give
it. Under those it fell back to gamescope's SDL backend, whose Vulkan swapchain
remake loops and aborts on this RADV RENOIR iGPU (rendervulkan.cpp
vulkan_remake_swapchain) - crashing e.g. Baba Is You a couple seconds in. sway
exposes those protocols, so gamescope inits its wayland backend and never hits
the crashing SDL path. Every game keeps its own gamescope (render resolution,
in-game exit chord, bare-tty portability); no per-game workaround needed.

Also resolve STROM_FLAKE to the /home/strom/strom checkout when present (github
fallback) so changes can be tested on the box before pushing upstream.

+55 -24
+55 -24
machines/coaxmetal/strom.nix
··· 4 4 ... 5 5 }: 6 6 let 7 - # Run the patched launcher from the on-disk strom checkout at 8 - # /home/strom/strom (it carries STROM_NO_GAMESCOPE support until that lands 9 - # upstream). With the kiosk itself being a gamescope session (below), games 10 - # are launched as <slug>.no-gamescope so they render directly in the session 11 - # compositor instead of nesting a per-game gamescope. 7 + # Run the launcher + games from the on-disk strom checkout at 8 + # /home/strom/strom when it exists, else the public github flake (see the 9 + # STROM_FLAKE selection in strom-session below). 10 + # 11 + # Compositor: sway (wlroots) via greetd autologin - NOT cage, and NOT an outer 12 + # gamescope session. Each game still brings its own gamescope, nested ONCE 13 + # inside sway. 14 + # 15 + # Why sway and not cage: a game's nested gamescope prefers its WAYLAND backend, 16 + # which needs wlroots protocols that cage (a minimal kiosk compositor) does not 17 + # expose. Under cage gamescope's wayland backend fails ("Couldn't create 18 + # Wayland objects") and silently falls back to its SDL backend, whose Vulkan 19 + # swapchain remake loops and aborts on this RADV RENOIR iGPU 20 + # (rendervulkan.cpp vulkan_remake_swapchain) - that is what crashed Baba Is You 21 + # a couple seconds in. sway exposes those protocols, so gamescope inits its 22 + # wayland backend and never touches the crashing SDL path. (An outer gamescope 23 + # session instead double-nests gamescope-in-gamescope, which is worse.) 24 + # Keeping per-game gamescope preserves render resolution/scaling, the in-game 25 + # exit chord, and bare-tty portability - hence no STROM_NO_GAMESCOPE. 12 26 strom-session = pkgs.writeShellScript "strom-session" '' 13 27 set -u 14 28 # xpadneo owns the Xbox pad's hidraw node, so force SDL (pygame launcher and ··· 19 33 # powered on after the launcher starts is never seen. Force SDL to poll 20 34 # /dev/input instead, which reliably picks up pads as they connect/disconnect. 21 35 export SDL_JOYSTICK_DISABLE_UDEV=1 22 - # Under cage the launcher window never reports input focus, and SDL suppresses 23 - # joystick (not keyboard) events while unfocused - so keyboard works but the 24 - # pad does not. Allow joystick events regardless of focus. 36 + # In the kiosk the launcher window may not report input focus, and SDL 37 + # suppresses joystick (not keyboard) events while unfocused - so allow 38 + # joystick events regardless of focus. 25 39 export SDL_JOYSTICK_ALLOW_BACKGROUND_EVENTS=1 26 - # The kiosk compositor is already gamescope on DRM (see services.greetd 27 - # below), so tell the launcher to run games directly in it rather than 28 - # nesting a per-game gamescope (which double-nests and, on this GPU, storms 29 - # the Vulkan swapchain and crashes games like Baba Is You). 30 - export STROM_NO_GAMESCOPE=1 40 + # Resolve the strom flake once: prefer the on-disk checkout at 41 + # /home/strom/strom (edit + test there before pushing to github), and fall 42 + # back to the public flake when it is absent. The launcher runs from this 43 + # ref, and pkgs/launcher resolves each game's ref from STROM_FLAKE too (it 44 + # sets the default with := so this export wins). 45 + if [ -d /home/strom/strom ]; then 46 + STROM_FLAKE=/home/strom/strom 47 + else 48 + STROM_FLAKE=github:kraftwerk-gaming/strom 49 + fi 50 + export STROM_FLAKE 31 51 # strom-run (the per-game supervisor) needs a delegated cgroup v2 so it can 32 52 # mkdir a child cgroup and cgroup.kill the game tree atomically. The greetd 33 53 # PAM session drops us into a root-owned logind session scope ··· 43 63 done 44 64 # Relaunch whenever the couch launcher exits (gamepad B / Esc) so the kiosk 45 65 # never drops to a blank screen. The loop runs inside the delegated scope so 46 - # every game inherits a writable cgroup; the gamescope compositor stays up 47 - # (it is the session's other child) across relaunches. 66 + # every game inherits a writable cgroup; sway stays up (the launcher is just 67 + # one of its clients) across relaunches. 48 68 # 49 69 # setpriv --ambient-caps=-all: the login session may carry an ambient 50 70 # capability (e.g. cap_wake_alarm) that every child inherits. bwrap refuses ··· 56 76 --quiet --collect -- \ 57 77 ${pkgs.util-linux}/bin/setpriv --ambient-caps=-all \ 58 78 ${pkgs.bash}/bin/bash -c 'while true; do 59 - ${config.nix.package}/bin/nix run /home/strom/strom#scripts.launcher 79 + ${config.nix.package}/bin/nix run "$STROM_FLAKE#scripts.launcher" 60 80 sleep 2 61 81 done' 62 82 ''; 63 83 84 + # Bare wlroots kiosk: no window chrome, every toplevel fullscreen, no idle 85 + # blanking. Its whole reason to exist over cage is that it exposes the wlroots 86 + # protocols each game's nested gamescope needs for its wayland backend (see 87 + # the top-of-file note). 88 + sway-kiosk = pkgs.writeText "sway-kiosk.conf" '' 89 + default_border none 90 + default_floating_border none 91 + gaps inner 0 92 + gaps outer 0 93 + # Fullscreen every toplevel: the launcher grid and each game's gamescope. 94 + for_window [app_id=".*"] fullscreen enable 95 + for_window [class=".*"] fullscreen enable 96 + # No swaybar / no swayidle -> no bar, no DPMS blank (mains-powered kiosk). 97 + exec ${strom-session} 98 + ''; 64 99 in 65 100 { 66 101 # Dedicated, unprivileged kiosk user. Gamepad input comes through evdev ··· 76 111 ]; 77 112 }; 78 113 79 - # Kiosk autostart: a gamescope session on DRM (via greetd autologin), 80 - # replacing cage. gamescope presents straight to the display, so there is no 81 - # nested Wayland swapchain for RADV to storm on this Vega iGPU. greetd gives 82 - # the strom user a real seat/VT (DRM master) and a delegated user manager, 83 - # which the launcher's systemd-run --user --scope relies on for game cgroups. 114 + # Kiosk autostart: greetd autologins the strom user on tty1 into sway, which 115 + # runs the couch launcher as its sole fullscreen client. default_session 116 + # re-runs the same session if sway ever exits. 84 117 services.greetd = { 85 118 enable = true; 86 119 settings = 87 120 let 88 121 session = { 89 - command = "${pkgs.gamescope}/bin/gamescope -- ${strom-session}"; 122 + command = "${pkgs.sway}/bin/sway --config ${sway-kiosk}"; 90 123 user = "strom"; 91 124 }; 92 125 in 93 126 { 94 - # initial_session autologins on boot with no prompt; default_session 95 - # re-runs it (also autologin) if the gamescope session ever exits. 96 127 initial_session = session; 97 128 default_session = session; 98 129 };