From 0cf0261359ac8cb3600ec16b2c091d519d8ace58 Mon Sep 17 00:00:00 2001 From: Alexandre Pires Date: Mon, 10 Nov 2025 14:07:12 +0100 Subject: [PATCH] feat: Update launch scripts for improved Gamescope and Steam integration, add custom EDID firmware, and enhance session management --- .../game_station/bin/system/launch_session.sh | 31 +-- .../game_station/bin/system/launch_steam.sh | 9 +- .../bin/system/steamos-session-select | 8 +- .../files/game_station/firmware/aoc28e850.bin | 5 + ansible/playbook_game_station.yml | 213 +++++++++++++++++- 5 files changed, 241 insertions(+), 25 deletions(-) create mode 100644 ansible/files/game_station/firmware/aoc28e850.bin diff --git a/ansible/files/game_station/bin/system/launch_session.sh b/ansible/files/game_station/bin/system/launch_session.sh index 959e2c1..1131d12 100644 --- a/ansible/files/game_station/bin/system/launch_session.sh +++ b/ansible/files/game_station/bin/system/launch_session.sh @@ -10,17 +10,19 @@ start_gamescope() { CONF_FILE="$HOME/.config/gamescope/gamescope.conf" [ -f "$CONF_FILE" ] && source "$CONF_FILE" - OUTPUT_CONNECTOR=${OUTPUT_CONNECTOR:-HDMI-A-1} FRAMERATE=${FRAMERATE:-60} RESOLUTION=${RESOLUTION:-1920x1080} 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_SHADER_DISK_CACHE=1 + export __GL_SYNC_TO_VBLANK=0 + export LIBVA_DRIVER_NAME=nvidia + export __GLX_VENDOR_LIBRARY_NAME=nvidia + export NVD_BACKEND=direct + # export __GL_THREADED_OPTIMIZATIONS=1 GAMESCOPE_BIN="$(command -v gamescope || true)" if [ -z "$GAMESCOPE_BIN" ]; then @@ -36,8 +38,6 @@ start_gamescope() { log "HDR disabled, no HDR flag added" fi - env | tee -a "$LOG_FILE" - # Build gamescope argument array for safe quoting and readability GAMESCOPE_ARGS=( --generate-drm-mode fixed @@ -47,7 +47,6 @@ start_gamescope() { -W "$WIDTH" -H "$HEIGHT" -w "$WIDTH" -h "$HEIGHT" --rt --mangoapp -e - -O "$OUTPUT_CONNECTOR" -r "$FRAMERATE" ) @@ -56,8 +55,12 @@ start_gamescope() { GAMESCOPE_ARGS+=("$HDR_FLAG") fi - log "Launching Gamescope: $GAMESCOPE_BIN ${GAMESCOPE_ARGS[*]} -- $*" + export XDG_CURRENT_DESKTOP=gamescope + export XDG_SESSION_TYPE=wayland + export DESKTOP_SESSION=gamescope + log "Launching Gamescope: $GAMESCOPE_BIN ${GAMESCOPE_ARGS[*]} -- $*" + sudo setcap 'CAP_SYS_NICE=eip' "$GAMESCOPE_BIN" # Execute gamescope inside a DBus session, preserving proper argument quoting exec dbus-run-session -- "$GAMESCOPE_BIN" "${GAMESCOPE_ARGS[@]}" -- "$@" >>"$LOG_FILE" 2>&1 } @@ -72,10 +75,7 @@ start_kwin() { export XDG_CURRENT_DESKTOP=plasma export XDG_SESSION_TYPE=wayland - export XDG_DATA_DIRS=/usr/local/share/:/usr/share/ - export XDG_CONFIG_DIRS=/usr/local/etc/xdg:/etc/xdg - export XDG_CURRENT_DESKTOP=KDE - export XDG_RUNTIME_DIR=/run/user/$(id -u) + export DESKTOP_SESSION=plasma-wayland # Ensure we don't run nested; width/height/fullscreen are for the windowed backend. unset DISPLAY WAYLAND_DISPLAY @@ -85,6 +85,9 @@ start_kwin() { } export XDG_SEAT=seat0 +export XDG_RUNTIME_DIR=/run/user/$(id -u) +export XDG_DATA_DIRS=/usr/local/share/:/usr/share/ +export XDG_CONFIG_DIRS=/usr/local/etc/xdg:/etc/xdg if [[ -f "$HOME/.desktop-session-plasma" ]]; then log "Plasma session selected." diff --git a/ansible/files/game_station/bin/system/launch_steam.sh b/ansible/files/game_station/bin/system/launch_steam.sh index e20c8ea..543f7ec 100644 --- a/ansible/files/game_station/bin/system/launch_steam.sh +++ b/ansible/files/game_station/bin/system/launch_steam.sh @@ -3,8 +3,6 @@ set -euo pipefail LOGFILE="$HOME/.local/logs/steam.log" export PATH="$HOME/.local/bin:$PATH" -export XDG_RUNTIME_DIR=/run/user/$(id -u) - export SDL_VIDEO_MINIMIZE_ON_FOCUS_LOSS=0 # There is no way to set a color space for an NV12 @@ -59,6 +57,13 @@ export STEAM_GAMESCOPE_VIRTUAL_WHITE=1 # Temporary crutch until dummy plane interactions / etc are figured out export GAMESCOPE_DISABLE_ASYNC_FLIPS=1 +# Use Vulkan for the Steam Overlay +export STEAM_OVERLAY_RENDERER=vk + +# Set input method modules for Qt/GTK that will show the Steam keyboard +export QT_IM_MODULE=steam +export GTK_IM_MODULE=Steam + export XCURSOR_THEME=steam export XCURSOR_SCALE=256 diff --git a/ansible/files/game_station/bin/system/steamos-session-select b/ansible/files/game_station/bin/system/steamos-session-select index 61e4a0d..845d297 100644 --- a/ansible/files/game_station/bin/system/steamos-session-select +++ b/ansible/files/game_station/bin/system/steamos-session-select @@ -23,6 +23,10 @@ case "$session" in ;; esac +if systemctl --user is-active --quiet sunshine.scope; then + log "Stopping sunshine.scope" + systemctl --user stop sunshine.scope +fi if systemctl --user is-active --quiet steam.scope; then log "Stopping steam.scope" systemctl --user stop steam.scope @@ -31,10 +35,6 @@ if systemctl --user is-active --quiet plasma.scope; then log "Stopping plasma.scope" systemctl --user stop plasma.scope fi -if systemctl --user is-active --quiet sunshine.scope; then - log "Stopping sunshine.scope" - systemctl --user stop sunshine.scope -fi sleep 5 log "Restarting graphical session service..." systemctl --user restart session.service \ No newline at end of file diff --git a/ansible/files/game_station/firmware/aoc28e850.bin b/ansible/files/game_station/firmware/aoc28e850.bin new file mode 100644 index 0000000..730d04f --- /dev/null +++ b/ansible/files/game_station/firmware/aoc28e850.bin @@ -0,0 +1,5 @@ +AP///////wAhVwkhutc0AQ8iAQOARid4AiiVp1VOoyYPUFQhCADRwIHAAQABAAEAAQABAAEAAjqA +GHE4LUBYLEUAxI4hAAAeAAAA/QAYVR5kHgAKICAgICAgAAAA/ABIRCBUTyBVU0IKICAgAAAAEAAA +AAAAAAAAAAAAAAAAAZYCAzBxThAfIiEgBBM+PTxfZAUUIwkHB4MBAABuAwwAEAAAPCAAgAECAwTl +DmFgZmVqXgCgoKApUDAgJQCwEzIAABgZZACAo6AsULAQNRCwEzIAABgAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAArw== \ No newline at end of file diff --git a/ansible/playbook_game_station.yml b/ansible/playbook_game_station.yml index eb735e8..a68d3fb 100644 --- a/ansible/playbook_game_station.yml +++ b/ansible/playbook_game_station.yml @@ -12,7 +12,7 @@ system_cores: "0,8" general_cores: "2-7,10-15" sunshine_cores: "1,9" - screen_resolution: "{{ lookup('env', 'GAME_RESOLUTION') | d('1280x720', true) }}" + screen_resolution: "{{ lookup('env', 'GAME_RESOLUTION') | d('1920x1080', true) }}" screen_width: "{{ screen_resolution.split('x')[0] }}" screen_height: "{{ screen_resolution.split('x')[1] }}" hdr_enabled: "{{ lookup('env', 'HDR_ENABLED') | d('false', true) }}" @@ -29,19 +29,171 @@ - threadirqs - nohz_full=1-7,9-15 - rcu_nocbs=1-7,9-15 + - drm.edid_firmware=DP-1:edid/aoc28e850.bin + - video=DP-1:e nvidia_modules: - nvidia - nvidia_modeset - nvidia_uvm - nvidia_drm + appimages: + - name: Steam ROM Manager + url: "https://github.com/SteamGridDB/steam-rom-manager/releases/download/v2.5.30/Steam-ROM-Manager-2.5.30.AppImage" + executable: "SteamRomManager.AppImage" + link: "srm" + - name: RPCS3 + url: "https://github.com/RPCS3/rpcs3-binaries-linux/releases/download/build-cc8929ef4a6142fa5b240d2f5ec19ead54cc6efa/rpcs3-v0.0.38-18287-cc8929ef_linux64.AppImage" + executable: "rpcs3.AppImage" + link: "rpcs3" + - name: Eden + url: "https://github.com/eden-emulator/Releases/releases/download/v0.0.4-rc1/Eden-Linux-v0.0.4-rc1-amd64-clang-standard.AppImage" + executable: "Eden.AppImage" + link: "eden" tasks: # --- Base dependencies --- - - name: Run 'dnf copr enable lizardbyte/stable' + - name: Enable COPR repositories become: true - ansible.builtin.command: dnf copr enable -y lizardbyte/stable - failed_when: false + community.general.copr: + name: "{{ item }}" + state: enabled + loop: + - lizardbyte/stable + - atim/heroic-games-launcher + + # --- CachyOS Kernel (conditional) --- + - name: Detect supported x86_64 ISA levels + ansible.builtin.shell: + cmd: | + set -euo pipefail; + /lib64/ld-linux-x86-64.so.2 --help | grep -F "(supported, searched)" + register: glibc_loader_help changed_when: false + failed_when: false + + - name: Determine CPU support for CachyOS kernel + ansible.builtin.set_fact: + has_x86_64_v3: "{{ ('x86-64-v3' in glibc_loader_help.stdout) or ('x86_64_v3' in glibc_loader_help.stdout) }}" + has_x86_64_v2: "{{ ('x86-64-v2' in glibc_loader_help.stdout) or ('x86_64_v2' in glibc_loader_help.stdout) }}" + + - name: Debug CPU ISA detection + ansible.builtin.debug: + msg: "CPU supports x86_64_v3: {{ has_x86_64_v3 }}, x86_64_v2: {{ has_x86_64_v2 }}" + + - name: Enable CachyOS COPR repository (kernel) + become: true + community.general.copr: + name: bieszczaders/kernel-cachyos + state: enabled + when: has_x86_64_v3 | bool or has_x86_64_v2 | bool + + - name: Enable CachyOS COPR repository (addons) + become: true + community.general.copr: + name: bieszczaders/kernel-cachyos-addons + state: enabled + when: has_x86_64_v3 | bool or has_x86_64_v2 | bool + + - name: Install CachyOS kernel for x86_64_v3 CPUs + become: true + ansible.builtin.dnf: + name: + - pesign + - openssl + - kernel-devel + - mokutil + - keyutils + - kernel-cachyos + - kernel-cachyos-devel + state: present + when: has_x86_64_v3 | bool + + - name: Ensures user is on /etc/pesign/users + become: true + ansible.builtin.lineinfile: + path: /etc/pesign/users + line: "{{ ansible_user }}" + state: present + when: has_x86_64_v3 | bool + notify: Run pesign + + - name: Run /usr/libexec/pesign/pesign-authorize + become: true + ansible.builtin.command: /usr/libexec/pesign/pesign-authorize + when: has_x86_64_v3 | bool + changed_when: false + + # - name: Generate certificate for CachyOS kernel signing + # become: true + # ansible.builtin.shell: | + # openssl req -new -x509 -newkey rsa:2048 -keyout "key.pem" \ + # -outform DER -out "cert.der" -nodes -days 36500 \ + # -subj "/CN=CachyOS Secure Boot/" && \ + # openssl pkcs12 -export -out key.p12 -inkey key.pem -in cert.der + # when: has_x86_64_v3 | bool + # changed_when: false + # args: + # executable: /bin/bash + # creates: + # - key.pem + # - cert.der + # - key.p12 + + # - name: Inform user to enroll MOK key + # ansible.builtin.debug: + # msg: | + # Please enroll the MOK key for kernel module signing on next reboot. + # Run: + # sudo certutil -A -i cert.der -n "CachyOS Secure Boot" -d /etc/pki/pesign/ -t "Pu,Pu,Pu" && \ + # sudo pk12util -i key.p12 -d /etc/pki/pesign + # sudo mokutil --import cert.der' if not prompted automatically. + # when: has_x86_64_v3 | bool + + - name: Create /etc/kernel/postinst.d directory + become: true + ansible.builtin.file: + path: /etc/kernel/postinst.d + state: directory + owner: root + group: root + mode: "0755" + + - name: Enable Automatically signing kernel updates + become: true + ansible.builtin.copy: + dest: /etc/kernel/postinst.d/00-signing + owner: root + group: root + mode: "0755" + content: | + #!/bin/sh + set -e + KERNEL_IMAGE="$2" + MOK_KEY_NICKNAME="CachyOS Secure Boot" + if [ "$#" -ne "2" ] ; then + echo "Wrong count of command line arguments. This is not meant to be called directly." >&2 + exit 1 + fi + if [ ! -x "$(command -v pesign)" ] ; then + echo "pesign not executable. Bailing." >&2 + exit 1 + fi + if [ ! -w "$KERNEL_IMAGE" ] ; then + echo "Kernel image $KERNEL_IMAGE is not writable." >&2 + exit 1 + fi + echo "Signing $KERNEL_IMAGE..." + pesign --certificate "$MOK_KEY_NICKNAME" --in "$KERNEL_IMAGE" --sign --out "$KERNEL_IMAGE.signed" + mv "$KERNEL_IMAGE.signed" "$KERNEL_IMAGE" + + - name: Install CachyOS LTS kernel for x86_64_v2-only CPUs + become: true + ansible.builtin.dnf: + name: + - kernel-cachyos-lts + - kernel-cachyos-lts-devel-matched + state: present + when: (not has_x86_64_v3 | bool) and (has_x86_64_v2 | bool) - name: Ensure core gaming and streaming packages are installed become: true @@ -66,6 +218,8 @@ - waypipe - drm-utils - ethtool + - heroic-games-launcher-bin + - libva-nvidia-driver state: present - name: Ensure user namespaces are enabled @@ -92,6 +246,35 @@ enabled: true state: started + - name: Create firmware directory for EDID files + become: true + ansible.builtin.file: + path: /lib/firmware/edid + state: directory + owner: root + group: root + mode: "0755" + + - name: Copy custom EDID file + become: true + ansible.builtin.copy: + dest: "/lib/firmware/edid/aoc28e850.bin" + owner: root + group: root + mode: "0644" + content: "{{ lookup('file', 'game_station/firmware/aoc28e850.bin') | b64decode }}" + + - name: Ensure EDID file is available in initramfs + become: true + ansible.builtin.copy: + dest: /etc/dracut.conf.d/90-edid.conf + owner: root + group: root + mode: "0644" + content: | + install_items+=" /lib/firmware/edid/aoc28e850.bin " + notify: Run dracut + - name: Ensure NVIDIA modules are loaded at boot become: true ansible.builtin.copy: @@ -313,6 +496,26 @@ daemon_reload: true scope: user + - name: Install AppImages + become: true + ansible.builtin.get_url: + url: "{{ item.url }}" + dest: "/home/{{ user_name }}/.local/bin/{{ item.executable }}" + mode: "0755" + owner: "{{ user_name }}" + group: "{{ user_name }}" + loop: "{{ appimages }}" + + - name: Create symlink for AppImages + become: true + ansible.builtin.file: + src: "/home/{{ user_name }}/.local/bin/{{ item.executable }}" + dest: "/home/{{ user_name }}/.local/bin/{{ item.link }}" + state: link + owner: "{{ user_name }}" + group: "{{ user_name }}" + loop: "{{ appimages }}" + - name: Download steamtools become: true ansible.builtin.get_url: @@ -397,6 +600,6 @@ changed_when: false - name: Run dracut - ansible.builtin.command: dracut --force + ansible.builtin.command: dracut --regenerate-all --force become: true changed_when: false