diff --git a/hosts/mainframe/sunshine/apps.json b/hosts/mainframe/sunshine/apps.json index bde2842..b322b53 100644 --- a/hosts/mainframe/sunshine/apps.json +++ b/hosts/mainframe/sunshine/apps.json @@ -1,34 +1,24 @@ { "env": { - "PATH": "$(PATH):$(HOME)/.local/bin" + "PATH": "$(PATH):$(HOME)/.local/bin:$(HOME)/.dotfiles/common/bin" }, "apps": [ { "name": "Desktop", "image-path": "desktop.png" }, - { - "name": "Low Res Desktop", - "image-path": "desktop.png", - "prep-cmd": [ - { - "do": "xrandr --output HDMI-1 --mode 1920x1080", - "undo": "xrandr --output HDMI-1 --mode 1920x1200" - } - ] - }, { "name": "Steam Big Picture", + "image-path": "steam.png", "detached": [ - "setsid steam steam://open/bigpicture" + "setsid steam -gamepadui" ], "prep-cmd": [ { "do": "", - "undo": "setsid steam steam://close/bigpicture" + "undo": "setsid steam -shutdown" } - ], - "image-path": "steam.png" + ] } ] } diff --git a/hosts/mainframe/sunshine/sunshine.conf b/hosts/mainframe/sunshine/sunshine.conf index 483562a..72a44ff 100644 --- a/hosts/mainframe/sunshine/sunshine.conf +++ b/hosts/mainframe/sunshine/sunshine.conf @@ -1 +1,17 @@ +# RTX 3060 (01:00.0). The Intel iGPU is renderD128 and owns the only physically +# connected output; this machine deliberately captures a virtual output on the +# NVIDIA card instead, so capture and NVENC happen without a cross-GPU copy. adapter_name = /dev/dri/renderD129 + +# The single output created by hosts/mainframe/sway/headless.conf. +output_name = HEADLESS-1 + +# wlroots screencopy rather than a KMS grab. This is why the sunshine binary +# needs no cap_sys_admin here. +capture = wlr + +encoder = nvenc +nvenc_preset = 1 +nvenc_twopass = quarter_res + +min_log_level = warning diff --git a/hosts/mainframe/sway/headless.conf b/hosts/mainframe/sway/headless.conf new file mode 100644 index 0000000..705177e --- /dev/null +++ b/hosts/mainframe/sway/headless.conf @@ -0,0 +1,22 @@ +# A compositor that exists only so Sunshine has something to capture. +# mainframe has no desktop: the only connected output (HDMI-A-2) hangs off the +# Intel iGPU, while the RTX 3060 that does the encoding drives no monitor at +# all. Capturing the real output would mean grabbing on Intel and encoding on +# NVIDIA — a cross-GPU copy every frame. A virtual output on the 3060 keeps +# capture and NVENC on one card. + +output HEADLESS-1 mode 1920x1080@60Hz position 0,0 +output HEADLESS-1 background #101920 solid_color + +# Sunshine is a systemd user unit, so it needs WAYLAND_DISPLAY in the user +# manager's environment. Import it before starting Sunshine, not after. +exec systemctl --user import-environment WAYLAND_DISPLAY XDG_CURRENT_DESKTOP +exec systemctl --user start sunshine.service + +# Nothing is attached to this session locally, so keybinds are only useful +# through a Moonlight client. Keep the set minimal. +set $mod Mod4 +bindsym $mod+Shift+q kill +bindsym $mod+Shift+e exec swaymsg exit + +# No bar, no idle daemon, no lock screen — there is no one sitting here. diff --git a/hosts/mainframe/systemd/sunshine.service b/hosts/mainframe/systemd/sunshine.service new file mode 100644 index 0000000..96c461e --- /dev/null +++ b/hosts/mainframe/systemd/sunshine.service @@ -0,0 +1,23 @@ +[Unit] +Description=Sunshine game stream host for Moonlight +Documentation=https://docs.lizardbyte.dev/projects/sunshine/ +# Singleton: binds the streaming ports. Same guard as every other unit here. +ConditionHost=mainframe +# Nothing to capture without the compositor, and Sunshine should die with it. +Requires=sway-headless.service +After=sway-headless.service +PartOf=sway-headless.service + +[Service] +Type=simple +# Our own unit rather than a drop-in: the AUR source package ships +# sunshine.service and the -bin package ships +# app-dev.lizardbyte.app.Sunshine.service, so a drop-in silently stops +# applying the moment you switch between them. +ExecStart=/usr/bin/sunshine +Restart=on-failure +RestartSec=5s +StartLimitBurst=3 + +[Install] +WantedBy=sway-headless.service diff --git a/hosts/mainframe/systemd/sway-headless.service b/hosts/mainframe/systemd/sway-headless.service new file mode 100644 index 0000000..6ea0b31 --- /dev/null +++ b/hosts/mainframe/systemd/sway-headless.service @@ -0,0 +1,22 @@ +[Unit] +Description=Headless Wayland compositor for Sunshine +Documentation=https://docs.lizardbyte.dev/projects/sunshine/ +ConditionHost=mainframe + +[Service] +Type=simple +# headless backend: no seat, no input devices, one virtual output. +Environment=WLR_BACKENDS=headless +Environment=WLR_LIBINPUT_NO_DEVICES=1 +# Pin the compositor to the NVIDIA card (card0 = 01:00.0, renderD129), which is +# also what sunshine.conf names as its encoder. Without this wlroots picks the +# Intel iGPU and every captured frame crosses GPUs. +Environment=WLR_DRM_DEVICES=/dev/dri/card0 +Environment=XDG_CURRENT_DESKTOP=sway +ExecStart=/usr/bin/sway -c %h/.config/sway/headless.conf +ExecStopPost=/usr/bin/systemctl --user stop sunshine.service +Restart=on-failure +RestartSec=5s + +[Install] +WantedBy=default.target diff --git a/meta/hosts/mainframe.conf.yaml b/meta/hosts/mainframe.conf.yaml index 789bdce..38b1b95 100644 --- a/meta/hosts/mainframe.conf.yaml +++ b/meta/hosts/mainframe.conf.yaml @@ -10,6 +10,9 @@ force: true - link: + ~/.config/sway/headless.conf: hosts/mainframe/sway/headless.conf + ~/.config/systemd/user/sway-headless.service: hosts/mainframe/systemd/sway-headless.service + ~/.config/systemd/user/sunshine.service: hosts/mainframe/systemd/sunshine.service ~/.config/inbox-tidy: hosts/mainframe/config/inbox-tidy ~/.config/llmfit: hosts/mainframe/config/llmfit ~/.ssh/config.local: hosts/mainframe/ssh/config.local @@ -38,3 +41,5 @@ description: Reloading user units - command: systemctl --user enable --now inbox-tidy.timer movie-recs.timer rent-utilities.timer ddns.timer description: Enabling the singleton timers (mainframe only) + - command: systemctl --user enable sway-headless.service sunshine.service + description: Enabling the headless compositor and Sunshine (not started here — it takes the GPU) diff --git a/packages/mainframe.aur b/packages/mainframe.aur index 01d45ee..57ee97f 100644 --- a/packages/mainframe.aur +++ b/packages/mainframe.aur @@ -9,5 +9,5 @@ paru paru-debug pistol-bin scc-bin -sunshine-git +sunshine-bin swayfx diff --git a/packages/mainframe.pacman b/packages/mainframe.pacman index c0360a1..510bec8 100644 --- a/packages/mainframe.pacman +++ b/packages/mainframe.pacman @@ -146,6 +146,7 @@ steam stress-ng sudo sushi +swaybg sysbench tecla tldr