|
@@ -0,0 +1,173 @@
|
|
|
|
|
+#!/bin/bash
|
|
|
|
|
+set -Eeuo pipefail
|
|
|
|
|
+
|
|
|
|
|
+export DISPLAY="${DISPLAY:-:20}"
|
|
|
|
|
+export DISPLAY_SIZEW="${DISPLAY_SIZEW:-1920}"
|
|
|
|
|
+export DISPLAY_SIZEH="${DISPLAY_SIZEH:-1080}"
|
|
|
|
|
+export DISPLAY_REFRESH="${DISPLAY_REFRESH:-120}"
|
|
|
|
|
+export DISPLAY_DPI="${DISPLAY_DPI:-96}"
|
|
|
|
|
+export DISPLAY_CDEPTH="${DISPLAY_CDEPTH:-24}"
|
|
|
|
|
+export VIDEO_PORT="${VIDEO_PORT:-HDMI-0}"
|
|
|
|
|
+
|
|
|
|
|
+export XDG_RUNTIME_DIR="${XDG_RUNTIME_DIR:-/tmp/runtime-ubuntu}"
|
|
|
|
|
+export PIPEWIRE_RUNTIME_DIR="${PIPEWIRE_RUNTIME_DIR:-${XDG_RUNTIME_DIR}}"
|
|
|
|
|
+export PULSE_RUNTIME_PATH="${PULSE_RUNTIME_PATH:-${XDG_RUNTIME_DIR}/pulse}"
|
|
|
|
|
+export PULSE_SERVER="${PULSE_SERVER:-unix:${PULSE_RUNTIME_PATH}/native}"
|
|
|
|
|
+
|
|
|
|
|
+XORG_PID=""
|
|
|
|
|
+XFCE_PID=""
|
|
|
|
|
+
|
|
|
|
|
+cleanup() {
|
|
|
|
|
+ echo "[desktop] Stopping XFCE/Xorg..."
|
|
|
|
|
+
|
|
|
|
|
+ if [[ -n "${XFCE_PID}" ]] && kill -0 "${XFCE_PID}" 2>/dev/null; then
|
|
|
|
|
+ kill -TERM "${XFCE_PID}" 2>/dev/null || true
|
|
|
|
|
+ fi
|
|
|
|
|
+
|
|
|
|
|
+ if [[ -n "${XORG_PID}" ]] && kill -0 "${XORG_PID}" 2>/dev/null; then
|
|
|
|
|
+ kill -TERM "${XORG_PID}" 2>/dev/null || true
|
|
|
|
|
+ fi
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+trap cleanup EXIT HUP INT QUIT TERM
|
|
|
|
|
+
|
|
|
|
|
+echo "[desktop] Preparing X11 runtime..."
|
|
|
|
|
+
|
|
|
|
|
+sudo install -d -m 1777 /tmp/.X11-unix /tmp/.ICE-unix
|
|
|
|
|
+sudo rm -f "/tmp/.X${DISPLAY#:}-lock"
|
|
|
|
|
+
|
|
|
|
|
+# Do not wipe the whole user cache: Steam may use it.
|
|
|
|
|
+rm -rf "${HOME}/.cache/sessions" 2>/dev/null || true
|
|
|
|
|
+
|
|
|
|
|
+if ! command -v nvidia-smi >/dev/null 2>&1; then
|
|
|
|
|
+ echo "[desktop] ERROR: nvidia-smi is not available." >&2
|
|
|
|
|
+ exit 1
|
|
|
|
|
+fi
|
|
|
|
|
+
|
|
|
|
|
+if ! command -v nvidia-xconfig >/dev/null 2>&1; then
|
|
|
|
|
+ echo "[desktop] ERROR: nvidia-xconfig is not available." >&2
|
|
|
|
|
+ exit 1
|
|
|
|
|
+fi
|
|
|
|
|
+
|
|
|
|
|
+GPU_SELECT="$(
|
|
|
|
|
+ nvidia-smi --query-gpu=uuid --format=csv,noheader | head -n 1 | tr -d '[:space:]'
|
|
|
|
|
+)"
|
|
|
|
|
+
|
|
|
|
|
+if [[ -z "${GPU_SELECT}" ]]; then
|
|
|
|
|
+ echo "[desktop] ERROR: no visible NVIDIA GPU detected." >&2
|
|
|
|
|
+ exit 1
|
|
|
|
|
+fi
|
|
|
|
|
+
|
|
|
|
|
+HEX_ID="$(
|
|
|
|
|
+ nvidia-smi --id="${GPU_SELECT}" --query-gpu=pci.bus_id --format=csv,noheader | head -n 1 | tr -d '[:space:]'
|
|
|
|
|
+)"
|
|
|
|
|
+
|
|
|
|
|
+if [[ -z "${HEX_ID}" ]]; then
|
|
|
|
|
+ echo "[desktop] ERROR: unable to determine NVIDIA PCI bus ID." >&2
|
|
|
|
|
+ exit 1
|
|
|
|
|
+fi
|
|
|
|
|
+
|
|
|
|
|
+IFS=':.' read -r DOMAIN BUS DEVICE FUNCTION <<<"${HEX_ID}"
|
|
|
|
|
+
|
|
|
|
|
+BUS_ID="PCI:$((16#${BUS}))@$((16#${DOMAIN})):$((16#${DEVICE})):$((16#${FUNCTION}))"
|
|
|
|
|
+
|
|
|
|
|
+echo "[desktop] GPU UUID : ${GPU_SELECT}"
|
|
|
|
|
+echo "[desktop] GPU PCI : ${HEX_ID} -> ${BUS_ID}"
|
|
|
|
|
+
|
|
|
|
|
+MODELINE="$(
|
|
|
|
|
+ cvt -r "${DISPLAY_SIZEW}" "${DISPLAY_SIZEH}" "${DISPLAY_REFRESH}" | sed -n '2p'
|
|
|
|
|
+)"
|
|
|
|
|
+
|
|
|
|
|
+if [[ -z "${MODELINE}" ]]; then
|
|
|
|
|
+ echo "[desktop] ERROR: cvt failed to generate a modeline." >&2
|
|
|
|
|
+ exit 1
|
|
|
|
|
+fi
|
|
|
|
|
+
|
|
|
|
|
+MODE_NAME="$(
|
|
|
|
|
+ awk '{print $2}' <<<"${MODELINE}" | tr -d '"'
|
|
|
|
|
+)"
|
|
|
|
|
+
|
|
|
|
|
+if [[ "${VIDEO_PORT,,}" == "none" ]]; then
|
|
|
|
|
+ CONNECTED_MONITOR=(--use-display-device=None)
|
|
|
|
|
+else
|
|
|
|
|
+ CONNECTED_MONITOR=(--connected-monitor="${VIDEO_PORT}")
|
|
|
|
|
+fi
|
|
|
|
|
+
|
|
|
|
|
+echo "[desktop] Generating /etc/X11/xorg.conf for ${DISPLAY_SIZEW}x${DISPLAY_SIZEH}@${DISPLAY_REFRESH}..."
|
|
|
|
|
+
|
|
|
|
|
+sudo rm -f /etc/X11/xorg.conf
|
|
|
|
|
+
|
|
|
|
|
+sudo nvidia-xconfig --virtual="${DISPLAY_SIZEW}x${DISPLAY_SIZEH}" --depth="${DISPLAY_CDEPTH}" --mode="${MODE_NAME}" --allow-empty-initial-configuration --no-probe-all-gpus --busid="${BUS_ID}" --include-implicit-metamodes --mode-debug --no-sli --no-base-mosaic --only-one-x-screen "${CONNECTED_MONITOR[@]}"
|
|
|
|
|
+
|
|
|
|
|
+sudo sed -i '/Driver[[:space:]]*"nvidia"/a\ Option "ModeValidation" "NoMaxPClkCheck,NoEdidMaxPClkCheck,NoMaxSizeCheck,NoHorizSyncCheck,NoVertRefreshCheck,NoVirtualSizeCheck,NoExtendedGpuCapabilitiesCheck,NoTotalSizeCheck,NoDualLinkDVICheck,NoDisplayPortBandwidthCheck,AllowNon3DVisionModes,AllowNonHDMI3DModes,AllowNonEdidModes,NoEdidHDMI2Check,AllowDpInterlaced"' /etc/X11/xorg.conf
|
|
|
|
|
+
|
|
|
|
|
+sudo sed -i '/Driver[[:space:]]*"nvidia"/a\ Option "AllowExternalGpus" "True"' /etc/X11/xorg.conf
|
|
|
|
|
+
|
|
|
|
|
+sudo sed -i '/Section[[:space:]]*"Monitor"/a\ '"${MODELINE}" /etc/X11/xorg.conf
|
|
|
|
|
+
|
|
|
|
|
+sudo sed -i '/"DPMS"/d' /etc/X11/xorg.conf
|
|
|
|
|
+
|
|
|
|
|
+sudo sed -i '/Section[[:space:]]*"Monitor"/a\ Option "DPMS" "False"' /etc/X11/xorg.conf
|
|
|
|
|
+
|
|
|
|
|
+cat <<'EOF' | sudo tee -a /etc/X11/xorg.conf >/dev/null
|
|
|
|
|
+
|
|
|
|
|
+Section "ServerFlags"
|
|
|
|
|
+ Option "DontVTSwitch" "True"
|
|
|
|
|
+ Option "DontZap" "True"
|
|
|
|
|
+ Option "AllowMouseOpenFail" "True"
|
|
|
|
|
+ Option "AutoAddGPU" "False"
|
|
|
|
|
+EndSection
|
|
|
|
|
+EOF
|
|
|
|
|
+
|
|
|
|
|
+# Xorg is started with -sharevts exactly like the previously validated stack.
|
|
|
|
|
+sudo ln -snf /dev/ptmx /dev/tty7
|
|
|
|
|
+
|
|
|
|
|
+echo "[desktop] Starting Xorg on ${DISPLAY}..."
|
|
|
|
|
+
|
|
|
|
|
+# Important:
|
|
|
|
|
+# Do not use udevadm trigger here. Sunshine input hotplug is handled by the
|
|
|
|
|
+# controlled Xorg restart in sunshine-entrypoint.sh.
|
|
|
|
|
+/usr/lib/xorg/Xorg "${DISPLAY}" vt7 -noreset -novtswitch -sharevts -nolisten tcp -ac -dpi "${DISPLAY_DPI}" +extension COMPOSITE +extension DAMAGE +extension GLX +extension RANDR +extension RENDER +extension MIT-SHM +extension XFIXES +extension XTEST &
|
|
|
|
|
+
|
|
|
|
|
+XORG_PID=$!
|
|
|
|
|
+
|
|
|
|
|
+echo "[desktop] Waiting for X socket..."
|
|
|
|
|
+
|
|
|
|
|
+for _ in $(seq 1 120); do
|
|
|
|
|
+ if [[ -S "/tmp/.X11-unix/X${DISPLAY#:}" ]]; then
|
|
|
|
|
+ break
|
|
|
|
|
+ fi
|
|
|
|
|
+
|
|
|
|
|
+ if ! kill -0 "${XORG_PID}" 2>/dev/null; then
|
|
|
|
|
+ echo "[desktop] ERROR: Xorg exited before creating its socket." >&2
|
|
|
|
|
+ wait "${XORG_PID}" || true
|
|
|
|
|
+ exit 1
|
|
|
|
|
+ fi
|
|
|
|
|
+
|
|
|
|
|
+ sleep 0.5
|
|
|
|
|
+done
|
|
|
|
|
+
|
|
|
|
|
+if [[ ! -S "/tmp/.X11-unix/X${DISPLAY#:}" ]]; then
|
|
|
|
|
+ echo "[desktop] ERROR: timed out waiting for Xorg." >&2
|
|
|
|
|
+ exit 1
|
|
|
|
|
+fi
|
|
|
|
|
+
|
|
|
|
|
+echo "[desktop] Xorg is ready."
|
|
|
|
|
+
|
|
|
|
|
+xset -display "${DISPLAY}" -dpms 2>/dev/null || true
|
|
|
|
|
+xset -display "${DISPLAY}" s off 2>/dev/null || true
|
|
|
|
|
+xset -display "${DISPLAY}" s noblank 2>/dev/null || true
|
|
|
|
|
+
|
|
|
|
|
+export XDG_SESSION_ID="${DISPLAY#:}"
|
|
|
|
|
+export DESKTOP_SESSION=xfce
|
|
|
|
|
+export XDG_SESSION_DESKTOP=xfce
|
|
|
|
|
+export XDG_CURRENT_DESKTOP=XFCE
|
|
|
|
|
+export XDG_SESSION_TYPE=x11
|
|
|
|
|
+
|
|
|
|
|
+echo "[desktop] Starting XFCE..."
|
|
|
|
|
+
|
|
|
|
|
+xfce4-session &
|
|
|
|
|
+XFCE_PID=$!
|
|
|
|
|
+
|
|
|
|
|
+# Keep the Supervisor program alive for the lifetime of the desktop session.
|
|
|
|
|
+wait "${XFCE_PID}"
|