Skip to content

Instantly share code, notes, and snippets.

@MariusHerget
Created December 3, 2025 09:41
Show Gist options
  • Select an option

  • Save MariusHerget/5ef5e50ededf8622c8dea1b05b33d98b to your computer and use it in GitHub Desktop.

Select an option

Save MariusHerget/5ef5e50ededf8622c8dea1b05b33d98b to your computer and use it in GitHub Desktop.
COSMIC eGPU Synchronization Wrapper
#!/bin/bash
# ==============================================================================
# COSMIC eGPU Synchronization Wrapper
# Purpose: Delays session start until eGPU is ready and injects forced variables
# ==============================================================================
# CONFIGURATION
EGPU_SUBSTRING="RTX 2080"
EGPU_PCIE_ID="0000:0b:00.0"
MAX_WAIT=10 # Maximum seconds to wait for eGPU initialization
# LOGGING (viewable in journalctl -t cosmic-egpu)
log() {
echo "$1" | systemd-cat -t cosmic-egpu
}
log "Wrapper started. Checking for eGPU..."
# 1. WAIT LOOP: Wait for NVIDIA driver to see the eGPU
DETECTED=0
for i in $(seq 1 $MAX_WAIT); do
if nvidia-smi --query-gpu=name --format=csv,noheader | grep -q "$EGPU_SUBSTRING"; then
log "eGPU ($EGPU_SUBSTRING) detected and ready."
DETECTED=1
break
fi
log "Waiting for eGPU driver initialization... ($i/$MAX_WAIT)"
sleep 1
done
# 2. ENVIRONMENT INJECTION
if [ "$DETECTED" -eq 1 ]; then
log "Injecting eGPU environment variables for this session."
# A. Force WGPU (Rust Apps) to use the eGPU
export WGPU_ADAPTER_NAME="$EGPU_SUBSTRING"
export WGPU_POWER_PREF="high"
# B. Force Legacy/GL/Vulkan Apps (XWayland/Steam) to use eGPU
export DRI_PRIME=1 # For Linux PRIME offload
export __NV_PRIME_RENDER_OFFLOAD=1
export __NV_PRIME_RENDER_OFFLOAD_PROVIDER="$(nvidia-smi -L | grep "$EGPU_SUBSTRING" | cut -d':' -f1)"
export __GLX_VENDOR_LIBRARY_NAME=nvidia
export VK_ICD_FILENAMES=/usr/share/vulkan/icd.d/nvidia_icd.json
export __VK_LAYER_NV_optimus=NVIDIA_only
# C. Force Compositor (cosmic-comp) to run on eGPU
# Resolve the symlink to the actual render node
EGPU_NODE_SYMLINK="/dev/dri/by-path/pci-${EGPU_PCIE_ID}-render"
# Wait loop to ensure render node exists
for i in $(seq 1 $MAX_WAIT); do
if [ -e "$EGPU_NODE_SYMLINK" ]; then
EGPU_NODE=$(readlink -f "$EGPU_NODE_SYMLINK")
export COSMIC_RENDER_DEVICE="$EGPU_NODE"
log "Forcing compositor to run on: $EGPU_NODE"
break
fi
log "Waiting for eGPU render node... ($i/$MAX_WAIT)"
sleep 1
done
if [ -z "${COSMIC_RENDER_DEVICE:-}" ]; then
log "WARNING: Could not determine eGPU render node. Compositor may default to iGPU."
fi
# Import into systemd user environment so autostarted units see the eGPU
if command -v systemctl >/dev/null 2>&1; then
systemctl --user import-environment \
COSMIC_RENDER_DEVICE \
WGPU_ADAPTER_NAME \
WGPU_POWER_PREF \
__NV_PRIME_RENDER_OFFLOAD \
__NV_PRIME_RENDER_OFFLOAD_PROVIDER \
__GLX_VENDOR_LIBRARY_NAME \
VK_ICD_FILENAMES \
__VK_LAYER_NV_optimus \
DRI_PRIME
fi
else
log "No eGPU detected after $MAX_WAIT seconds. Proceeding with integrated graphics."
unset COSMIC_RENDER_DEVICE
unset WGPU_ADAPTER_NAME
unset WGPU_POWER_PREF
unset __NV_PRIME_RENDER_OFFLOAD
unset __NV_PRIME_RENDER_OFFLOAD_PROVIDER
unset __GLX_VENDOR_LIBRARY_NAME
unset VK_ICD_FILENAMES
unset __VK_LAYER_NV_optimus
unset DRI_PRIME
fi
# 3. HANDOFF TO COSMIC
log "Handing off control to standard start-cosmic..."
exec /usr/bin/start-cosmic
[Desktop Entry]
Name=COSMIC (eGPU)
Comment=This session logs you into the COSMIC desktop
Exec=/usr/local/bin/cosmic-egpu-start.sh
Type=Application
DesktopNames=COSMIC
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment