From 7a7f2711fe0f6b6a601d014febab6c0c8c2fbbc7 Mon Sep 17 00:00:00 2001 From: Alexandre Pires Date: Tue, 28 Oct 2025 19:24:43 +0100 Subject: [PATCH] feat: Add Gamescope and Sunshine configuration files and update session management --- .../game_station/gamescope/gamescope.conf | 5 + .../files/game_station/sunshine/sunshine.conf | 2 +- .../game_station/system/launch_session.sh | 41 +++++++-- .../files/game_station/system/launch_steam.sh | 3 - .../system/steamos-session-select | 2 +- .../systemd/system/gamescope-session.service | 29 ------ .../game_station/systemd/user/gamescope.slice | 3 - .../game_station/systemd/user/session.service | 10 ++ .../files/game_station/user/update_roms.sh | 24 +++++ ansible/playbook_game_station.yml | 91 ++++++++++++++----- 10 files changed, 139 insertions(+), 71 deletions(-) create mode 100644 ansible/files/game_station/gamescope/gamescope.conf delete mode 100644 ansible/files/game_station/systemd/system/gamescope-session.service delete mode 100644 ansible/files/game_station/systemd/user/gamescope.slice create mode 100644 ansible/files/game_station/systemd/user/session.service create mode 100644 ansible/files/game_station/user/update_roms.sh diff --git a/ansible/files/game_station/gamescope/gamescope.conf b/ansible/files/game_station/gamescope/gamescope.conf new file mode 100644 index 0000000..cb6e1de --- /dev/null +++ b/ansible/files/game_station/gamescope/gamescope.conf @@ -0,0 +1,5 @@ +OUTPUT_CONNECTOR={{ output_connector }} +FRAMERATE={{ framerate }} +RESOLUTION={{ screen_resolution }} +HDR_ENABLED={{ hdr_enabled }} +DRM_DEVICE={{ drm_device }} diff --git a/ansible/files/game_station/sunshine/sunshine.conf b/ansible/files/game_station/sunshine/sunshine.conf index 62dcfab..c8be7cd 100644 --- a/ansible/files/game_station/sunshine/sunshine.conf +++ b/ansible/files/game_station/sunshine/sunshine.conf @@ -1,2 +1,2 @@ system_tray=disable -log_path = /home/{{ user_name }}/.local/logs/sunshine.log +log_path = /home/{{ user_name }}/.local/logs/sunshine.log \ No newline at end of file diff --git a/ansible/files/game_station/system/launch_session.sh b/ansible/files/game_station/system/launch_session.sh index 7a896c4..5e42106 100644 --- a/ansible/files/game_station/system/launch_session.sh +++ b/ansible/files/game_station/system/launch_session.sh @@ -4,7 +4,6 @@ LOG_FILE="$HOME/.local/logs/session.log" log() { echo "[$(date --iso-8601=seconds)] $*" | tee -a "$LOG_FILE"; } - start_gamescope() { log "Starting Gamescope session..." @@ -17,11 +16,11 @@ start_gamescope() { WIDTH="${RESOLUTION%x*}" HEIGHT="${RESOLUTION#*x}" - export __GL_GSYNC_ALLOWED=1 - export __GL_VRR_ALLOWED=1 - # export __GL_THREADED_OPTIMIZATIONS=1 - export __GL_SHADER_DISK_CACHE=1 - export __GL_SYNC_TO_VBLANK=0 + # export __GL_GSYNC_ALLOWED=1 + # export __GL_VRR_ALLOWED=1 + # # export __GL_THREADED_OPTIMIZATIONS=1 + # export __GL_SHADER_DISK_CACHE=1 + # export __GL_SYNC_TO_VBLANK=0 GAMESCOPE_BIN="$(command -v gamescope || true)" if [ -z "$GAMESCOPE_BIN" ]; then @@ -37,9 +36,28 @@ start_gamescope() { log "HDR disabled, no HDR flag added" fi - GAMESCOPE_ARGS="--generate-drm-mode fixed --fade-out-duration 200 --cursor-scale-height 720 -f -w $WIDTH -h $HEIGHT --rt --mangoapp -e -O \"$OUTPUT_CONNECTOR\" -r $FRAMERATE $HDR_FLAG" - log "Launching Gamescope: $GAMESCOPE_BIN $GAMESCOPE_ARGS -- $@" - exec dbus-run-session -- "$GAMESCOPE_BIN" ${GAMESCOPE_ARGS} -- "$@" >>"$LOG_FILE" 2>&1 + # Build gamescope argument array for safe quoting and readability + GAMESCOPE_ARGS=( + --generate-drm-mode fixed + --fade-out-duration 200 + --cursor-scale-height 720 + -f + -W "$WIDTH" -H "$HEIGHT" + -w "$WIDTH" -h "$HEIGHT" + --rt --mangoapp -e + -O "$OUTPUT_CONNECTOR" + -r "$FRAMERATE" + ) + + # Append HDR flag if enabled + if [ -n "${HDR_FLAG:-}" ]; then + GAMESCOPE_ARGS+=("$HDR_FLAG") + fi + + log "Launching Gamescope: $GAMESCOPE_BIN ${GAMESCOPE_ARGS[*]} -- $*" + + # Execute gamescope inside a DBus session, preserving proper argument quoting + exec dbus-run-session -- "$GAMESCOPE_BIN" "${GAMESCOPE_ARGS[@]}" -- "$@" >>"$LOG_FILE" 2>&1 } start_kwin() { @@ -64,6 +82,11 @@ start_kwin() { exec dbus-run-session -- "$KWIN_BIN" ${KWIN_ARGS} "$@" >>"$LOG_FILE" 2>&1 } + +export XDG_SEAT=seat0 +export XDG_RUNTIME_DIR=/run/user/$(id -u) +export DBUS_SESSION_BUS_ADDRESS=unix:path=$XDG_RUNTIME_DIR/bus + if [[ -f "$HOME/.desktop-session-plasma" ]]; then log "Plasma session selected." rm "$HOME/.desktop-session-plasma" diff --git a/ansible/files/game_station/system/launch_steam.sh b/ansible/files/game_station/system/launch_steam.sh index 16f69ce..e20c8ea 100644 --- a/ansible/files/game_station/system/launch_steam.sh +++ b/ansible/files/game_station/system/launch_steam.sh @@ -101,9 +101,6 @@ log "Updating steam: /opt/steamcmd/steamcmd.sh +quit" exit 1 } -log "Updating Steam ROM Manager" -srm add >> "$LOGFILE" 2>&1 || log "ERROR: Steam ROM Manager update failed" - log "Launching Steam" STEAM_ARGS=("-steamdeck" "-steamos3" "-steampal" "-gamepadui" "-pipewire-dmabuf") systemd-run --user --scope --quiet \ diff --git a/ansible/files/game_station/system/steamos-session-select b/ansible/files/game_station/system/steamos-session-select index b95fa92..c58d571 100644 --- a/ansible/files/game_station/system/steamos-session-select +++ b/ansible/files/game_station/system/steamos-session-select @@ -37,4 +37,4 @@ if systemctl --user is-active --quiet sunshine.scope; then fi log "Restarting graphical session service..." -sudo systemctl restart gamescope-session.service \ No newline at end of file +systemctl --user restart session.service \ No newline at end of file diff --git a/ansible/files/game_station/systemd/system/gamescope-session.service b/ansible/files/game_station/systemd/system/gamescope-session.service deleted file mode 100644 index bf91a6b..0000000 --- a/ansible/files/game_station/systemd/system/gamescope-session.service +++ /dev/null @@ -1,29 +0,0 @@ -[Unit] -Description=Weston Wayland compositor for user gameuser -Wants=graphical.target -Conflicts=getty@tty1.service -After=getty@tty1.service -After=rc-local.service plymouth-start.service systemd-user-sessions.service - -[Service] -Slice=gamescope.slice -User=gameuser -PAMName=login -TTYPath=/dev/tty1 -TTYReset=yes -TTYVHangup=yes -StandardInput=tty -StandardOutput=journal -StandardError=journal -UtmpIdentifier=tty1 -UtmpMode=user -Environment=XDG_SEAT=seat0 -Environment=XDG_RUNTIME_DIR=/run/user/%U -Environment=DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/%U/bus -ExecStartPre=/usr/bin/chvt 1 -ExecStart=/usr/bin/bash /usr/local/bin/launch_session.sh -Restart=always -KeyringMode=shared - -[Install] -WantedBy=graphical.target diff --git a/ansible/files/game_station/systemd/user/gamescope.slice b/ansible/files/game_station/systemd/user/gamescope.slice deleted file mode 100644 index 4618983..0000000 --- a/ansible/files/game_station/systemd/user/gamescope.slice +++ /dev/null @@ -1,3 +0,0 @@ -[Slice] -CPUWeight=100 -AllowedCPUs={{ general_cores }} diff --git a/ansible/files/game_station/systemd/user/session.service b/ansible/files/game_station/systemd/user/session.service new file mode 100644 index 0000000..e6f3c7f --- /dev/null +++ b/ansible/files/game_station/systemd/user/session.service @@ -0,0 +1,10 @@ +[Unit] +Description=User session service +After=graphical-session.target systemd-user-sessions.service + +[Service] +ExecStart=/usr/bin/bash /usr/local/bin/launch_session.sh +Restart=on-failure + +[Install] +WantedBy=default.target \ No newline at end of file diff --git a/ansible/files/game_station/user/update_roms.sh b/ansible/files/game_station/user/update_roms.sh new file mode 100644 index 0000000..d255e82 --- /dev/null +++ b/ansible/files/game_station/user/update_roms.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +set -euo pipefail +LOGFILE="$HOME/.local/logs/update_roms.log" + +log() { echo "[$(date --iso-8601=seconds)] $*" | tee -a "$LOGFILE"; } + +ROM_MANAGER_BIN="$(command -v srm || true)" +if [ -z "$ROM_MANAGER_BIN" ]; then + log "ERROR: srm (Steam ROM Manager) not found in PATH" + exit 127 +fi +log "Updating Steam ROM Manager" +$ROM_MANAGER_BIN add >> "$LOGFILE" 2>&1 || { + log "ERROR: Steam ROM Manager update failed" + exit 1 +} +log "Steam ROM Manager update completed successfully, restarting Steam service if running" +if systemctl --user is-active --quiet steam.scope; then + log "Restarting Steam service to apply changes" + systemctl --user restart steam.scope + log "Steam service restarted" +else + log "Steam service is not running, no need to restart" +fi \ No newline at end of file diff --git a/ansible/playbook_game_station.yml b/ansible/playbook_game_station.yml index a513b5b..f0437ca 100644 --- a/ansible/playbook_game_station.yml +++ b/ansible/playbook_game_station.yml @@ -12,6 +12,22 @@ system_cores: "0,8" general_cores: "2-7,10-15" sunshine_cores: "1,9" + screen_resolution: "{{ lookup('env', 'GAME_RESOLUTION') | d('1280x720', true) }}" + screen_width: "{{ screen_resolution.split('x')[0] }}" + screen_height: "{{ screen_resolution.split('x')[1] }}" + hdr_enabled: "{{ lookup('env', 'HDR_ENABLED') | d('false', true) }}" + output_connector: "{{ lookup('env', 'OUTPUT_CONNECTOR') | d('HDMI-A-1', true) }}" + framerate: "{{ lookup('env', 'FRAMERATE') | d('60', true) }}" + drm_device: "{{ lookup('env', 'DRM_DEVICE') | d('/dev/dri/card1', true) }}" + grub_options: + - quiet + - splash + - amd_pstate=active + - nvidia_drm.modeset=1 + - mitigations=off + - threadirqs + - nohz_full=1-7,9-15 + - rcu_nocbs=1-7,9-15 tasks: # --- Base dependencies --- @@ -42,6 +58,8 @@ - weston - bubblewrap - waypipe + - drm-utils + - ethtool state: present - name: Ensure user namespaces are enabled @@ -68,13 +86,19 @@ enabled: true state: started + - name: Enable wake-on-lan on primary network interface + become: true + ansible.builtin.command: ethtool -s $(ip route show default | awk '/default/ {print $5}') wol g + changed_when: false + failed_when: false + # --- Performance kernel options --- - name: Tune kernel command line for isolation become: true ansible.builtin.lineinfile: path: "{{ grub_cfg }}" regexp: "^GRUB_CMDLINE_LINUX_DEFAULT=" - line: 'GRUB_CMDLINE_LINUX_DEFAULT="quiet splash amd_pstate=active mitigations=off threadirqs nohz_full=1-7,9-15 rcu_nocbs=1-7,9-15"' + line: 'GRUB_CMDLINE_LINUX_DEFAULT="{{ grub_options | join(" ") }}"' notify: Update grub - name: Ensure cpupower governor is performance @@ -108,7 +132,11 @@ owner: root group: root loop: "{{ query('fileglob', 'game_station/systemd/system/*') }}" - notify: Reload systemd daemon for system services + + - name: Reload systemd daemon for system services + become: true + ansible.builtin.systemd: + daemon_reload: true - name: Install System scripts become: true @@ -130,6 +158,26 @@ mode: "0755" loop: - /root/.local/logs + - "{{ systemd_system_dir }}/getty@tty1.service.d" + + - name: Create override for getty on tty1 + become: true + ansible.builtin.copy: + dest: "{{ systemd_system_dir }}/getty@tty1.service.d/override.conf" + owner: root + group: root + mode: "0644" + content: | + [Service] + ExecStart= + ExecStart=-/usr/bin/agetty --autologin {{ user_name }} --noclear %I $TERM + Type=idle + + - name: Enable user lingering for game user + become: true + ansible.builtin.command: loginctl enable-linger {{ user_name }} + changed_when: false + failed_when: false - name: Create log file for Jupiter BIOS update (dummy file) become: true @@ -204,7 +252,13 @@ group: "{{ user_name }}" mode: "0644" loop: "{{ query('fileglob', 'game_station/systemd/user/*') }}" - notify: Reload systemd daemon for user services + + - name: Reload systemd daemon for user services + become: true + become_user: "{{ user_name }}" + ansible.builtin.systemd: + daemon_reload: true + scope: user - name: Download steamtools become: true @@ -256,16 +310,13 @@ - name: Write Gamescope configuration become: true - ansible.builtin.copy: - dest: "{{ user_config_dir }}/gamescope/gamescope.conf" + ansible.builtin.template: + src: "{{ item }}" + dest: "{{ user_config_dir }}/gamescope/{{ item | basename }}" owner: "{{ user_name }}" + group: "{{ user_name }}" mode: "0644" - content: | - OUTPUT_CONNECTOR=HDMI-A-1 - FRAMERATE=120 - RESOLUTION={{ lookup('env', 'GAME_RESOLUTION') | default('1920x1080') }} - HDR_ENABLED={{ lookup('env', 'HDR_ENABLED') | default('false') }} - DRM_DEVICE=/dev/dri/card1 + loop: "{{ query('fileglob', 'game_station/gamescope/*') }}" - name: Install Sunshine files become: true @@ -277,27 +328,17 @@ mode: "0644" loop: "{{ query('fileglob', 'game_station/sunshine/*') }}" - - name: Enable Gamescope session service on boot + - name: Enable User session service login become: true + become_user: "{{ user_name }}" ansible.builtin.systemd: - name: gamescope-session.service + name: session.service enabled: true state: started + scope: user handlers: - name: Update grub ansible.builtin.command: grub2-mkconfig -o /boot/grub2/grub.cfg become: true changed_when: false - - - name: Reload systemd daemon for system services - become: true - ansible.builtin.systemd: - daemon_reload: true - - - name: Reload systemd daemon for user services - become: true - become_user: "{{ user_name }}" - ansible.builtin.systemd: - daemon_reload: true - scope: user