Skip to content

Instantly share code, notes, and snippets.

@adujardin
Last active February 13, 2026 13:35
Show Gist options
  • Select an option

  • Save adujardin/9154a619cbf5a5508e5fad336839702b to your computer and use it in GitHub Desktop.

Select an option

Save adujardin/9154a619cbf5a5508e5fad336839702b to your computer and use it in GitHub Desktop.
Screenless jetson with hw acceleration (including EGL, Argus, CUDA and remote nomachine screen)
#!/bin/bash
# =============================================================================
# Jetson Headless Virtual Display Setup (GPU-Accelerated)
# =============================================================================
#
# Creates a virtual 1920x1080@60Hz display on Jetson AGX Orin without a
# physical monitor. EGL, CUDA, and NVIDIA Argus all work. A real monitor
# can still be hot-plugged at any time. Works with NoMachine/VNC for remote
# desktop access.
#
# Platform: Jetson AGX Orin
# - JetPack 5.x (L4T R35.x, Ubuntu 20.04) — Xorg "nvidia" DDX driver
# - JetPack 6.x (L4T R36.x, Ubuntu 22.04) — Xorg "nvidia" DDX driver
#
# HOW IT WORKS:
# -------------
# Uses the nvidia DDX Xorg driver with ConnectedMonitor + CustomEDID options
# to fake a connected 1920x1080 display on the DP port. This provides:
# - Full NVIDIA EGL support (nvbufsurface, Argus camera can create EGLImages)
# - CUDA-EGL interop (cuGraphicsEGLRegisterImage works)
# - Hardware-accelerated X11/GLX rendering via NVIDIA GPU
# - Proper DRI2 for remote desktop protocols (NoMachine, VNC, etc.)
#
# JP6-SPECIFIC NOTES:
# -------------------
# nvidia-drm.modeset=1 is NOT compatible with nvidia DDX driver — it causes
# "Failed to acquire modesetting permission". We remove it from boot params.
# The nvidia DDX handles modesetting directly without nvidia-drm KMS.
#
# EGL/CUDA/Argus work fine WITHOUT nvidia-drm.modeset=1 when using nvidia DDX,
# because applications access NVIDIA EGL/CUDA directly via the ICD, not through
# the kernel DRM modesetting path.
#
# REAL MONITOR:
# -------------
# If you plug in a real DP monitor, it appears automatically in xrandr
# and is usable alongside (or instead of) the virtual framebuffer.
#
# USAGE:
# chmod +x setup-virtual-display-fixed.sh
# sudo ./setup-virtual-display-fixed.sh
# sudo reboot
#
# VERIFY:
# DISPLAY=:0 xrandr # 1920x1080 screen
# DISPLAY=:0 eglinfo 2>&1 | head -15 # EGL vendor: NVIDIA
# python3 -c "import ctypes; c=ctypes.CDLL('libcuda.so.1'); print(c.cuInit(0))" # 0
# # Connect via NoMachine — should show full GNOME desktop
#
# TO REVERT:
# sudo cp /etc/X11/xorg.conf.bak.original /etc/X11/xorg.conf # or rm it
# sudo rm -f /etc/X11/edid-1080p.bin
# sudo rm -f /etc/udev/rules.d/99-jetson-drm-seat.rules
# sudo systemctl enable seatd 2>/dev/null # if you need seatd back
# # For JP6: add back nvidia-drm.modeset=1 to /boot/extlinux/extlinux.conf if needed
# sudo reboot
#
# =============================================================================
set -euo pipefail
if [[ $EUID -ne 0 ]]; then
echo "ERROR: Must run as root (sudo)."
exit 1
fi
# --- Detect JetPack / L4T version ---
detect_jetpack_version() {
local l4t_major=""
if [[ -f /etc/nv_tegra_release ]]; then
l4t_major=$(sed -n 's/^# R\([0-9]*\).*/\1/p' /etc/nv_tegra_release)
fi
if [[ -z "$l4t_major" ]] && command -v dpkg-query &>/dev/null; then
l4t_major=$(dpkg-query -W -f='${Version}' nvidia-l4t-core 2>/dev/null \
| sed -n 's/^\([0-9]*\)\..*/\1/p') || true
fi
if [[ -n "$l4t_major" && "$l4t_major" -ge 36 ]]; then
echo 6
elif [[ -n "$l4t_major" && "$l4t_major" -ge 35 ]]; then
echo 5
else
echo 0
fi
}
# --- Detect first available DP connector ---
detect_dp_connector_drm() {
# DRM naming (1-indexed): DP-1, DP-2, etc.
for card_dp in /sys/class/drm/card*-DP-*; do
if [[ -d "$card_dp" ]]; then
basename "$card_dp" | sed 's/card[0-9]*-//'
return
fi
done
echo "DP-1"
}
detect_dp_connector_xorg() {
# nvidia DDX uses 0-indexed: DP-0, DP-1, etc.
local drm_idx
drm_idx=$(detect_dp_connector_drm | sed 's/.*DP-//')
echo "DP-$((drm_idx - 1))"
}
JP_VERSION=$(detect_jetpack_version)
DP_DRM=$(detect_dp_connector_drm)
DP_XORG=$(detect_dp_connector_xorg)
echo "=== Jetson Virtual Display Setup ==="
if [[ "$JP_VERSION" -eq 6 ]]; then
echo "Detected: JetPack 6 (L4T R36.x)"
elif [[ "$JP_VERSION" -eq 5 ]]; then
echo "Detected: JetPack 5 (L4T R35.x)"
else
echo "WARNING: Could not detect JetPack version, defaulting to JP5 path"
JP_VERSION=5
fi
# =========================================================================
# COMMON PATH (JP5 + JP6): nvidia DDX driver with ConnectedMonitor + CustomEDID
# =========================================================================
echo "Using nvidia DDX driver with connector ${DP_XORG}"
STEP=0
TOTAL_JP5=3
TOTAL_JP6=5
# ------------------------------------------------------------------
# Step 1: Backup xorg.conf
# ------------------------------------------------------------------
STEP=$((STEP+1))
if [[ -f /etc/X11/xorg.conf && ! -f /etc/X11/xorg.conf.bak.original ]]; then
cp /etc/X11/xorg.conf /etc/X11/xorg.conf.bak.original
echo "[${STEP}] Backed up xorg.conf"
else
echo "[${STEP}] Backup: skipped (already exists or no file)"
fi
# ------------------------------------------------------------------
# Step 2: EDID binary
# ------------------------------------------------------------------
STEP=$((STEP+1))
base64 -d > /etc/X11/edid-1080p.bin << 'EDID_EOF'
AP///////wBZ5QEAAQAAAAEiAQOAAAB4Cu6Ro1RMmSYPUFQhCAABAQEBAQEBAQEBAQEBAQEBAjqA
GHE4LUBYLEUADyghAAAeAAAA/ABWaXJ0dWFsIDEwODBwAAAA/QAySx5REQAKICAgICAgAAAA/wAw
MDAwMDAwMDAwMDAxAJc=
EDID_EOF
chmod 644 /etc/X11/edid-1080p.bin
echo "[${STEP}] Installed EDID binary"
# ------------------------------------------------------------------
# Step 3: xorg.conf (nvidia DDX)
# ------------------------------------------------------------------
STEP=$((STEP+1))
cat > /etc/X11/xorg.conf << XORG_EOF
# Jetson JP${JP_VERSION} - nvidia DDX driver, virtual display
Section "DRI"
Mode 0666
EndSection
Section "Module"
Disable "dri"
SubSection "extmod"
Option "omit xfree86-dga"
EndSubSection
EndSection
Section "Device"
Identifier "Tegra0"
Driver "nvidia"
Option "AllowEmptyInitialConfiguration" "true"
Option "ConnectedMonitor" "${DP_XORG}"
Option "CustomEDID" "${DP_XORG}:/etc/X11/edid-1080p.bin"
Option "HardDPMS" "false"
EndSection
Section "Monitor"
Identifier "Virtual-1080p"
HorizSync 30-81
VertRefresh 50-75
ModeLine "1920x1080_60" 148.50 1920 2008 2052 2200 1080 1084 1089 1125 +HSync +VSync
Option "PreferredMode" "1920x1080_60"
EndSection
Section "Screen"
Identifier "Default Screen"
Device "Tegra0"
Monitor "Virtual-1080p"
DefaultDepth 24
SubSection "Display"
Depth 24
Modes "1920x1080_60"
EndSubSection
EndSection
XORG_EOF
echo "[${STEP}] Wrote xorg.conf (nvidia DDX)"
# ------------------------------------------------------------------
# JP6-SPECIFIC: Additional steps
# ------------------------------------------------------------------
if [[ "$JP_VERSION" -eq 6 ]]; then
# ------------------------------------------------------------------
# Step 4: Remove nvidia-drm.modeset=1 from boot params
# ------------------------------------------------------------------
STEP=$((STEP+1))
EXTLINUX_CONF="/boot/extlinux/extlinux.conf"
if [[ -f "$EXTLINUX_CONF" ]]; then
if grep -q "nvidia-drm.modeset=1" "$EXTLINUX_CONF"; then
cp "$EXTLINUX_CONF" "${EXTLINUX_CONF}.bak.$(date +%Y%m%d%H%M%S)"
sed -i 's| nvidia-drm\.modeset=1||g' "$EXTLINUX_CONF"
echo "[${STEP}] Removed nvidia-drm.modeset=1 from extlinux.conf"
else
echo "[${STEP}] nvidia-drm.modeset=1 not present (OK)"
fi
else
echo "[${STEP}] WARNING: ${EXTLINUX_CONF} not found"
fi
# ------------------------------------------------------------------
# Step 5: Disable seatd if present (optional, helps avoid conflicts)
# ------------------------------------------------------------------
STEP=$((STEP+1))
if systemctl is-enabled seatd &>/dev/null 2>&1; then
systemctl stop seatd 2>/dev/null || true
systemctl disable seatd 2>/dev/null || true
echo "[${STEP}] Disabled seatd (avoids DRM master conflicts)"
else
echo "[${STEP}] seatd not present or already disabled"
fi
fi
echo ""
echo "=== Done! ==="
echo ""
echo "A reboot is REQUIRED:"
echo " sudo reboot"
echo ""
echo "After reboot, verify:"
echo " DISPLAY=:0 xrandr # 1920x1080 screen"
echo " DISPLAY=:0 eglinfo 2>&1 | head -15 # EGL vendor: NVIDIA"
echo " python3 -c 'import ctypes; c=ctypes.CDLL(\"libcuda.so.1\"); print(c.cuInit(0))' # 0"
echo ""
if [[ "$JP_VERSION" -eq 6 ]]; then
echo "JP6 NOTES:"
echo " - nvidia DDX driver active (NOT modesetting)"
echo " - nvidia-drm.modeset=1 removed from boot (incompatible with nvidia DDX)"
echo " - EGL/CUDA/Argus work via nvidia DDX's own rendering path"
echo " - NoMachine/VNC will show full hardware-accelerated desktop"
echo ""
fi
echo "Connect via NoMachine or VNC to access the desktop remotely."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment