Skip to main content

Overview

Hyperscape streaming requires hardware GPU rendering for WebGPU support. The game uses Three.js Shading Language (TSL) which compiles to WGSL and requires WebGPU—software rendering is not supported.
Software rendering (Xvfb, SwiftShader, Lavapipe) is NOT supported. WebGPU requires hardware GPU acceleration.

GPU Rendering Modes

The deployment system supports two GPU rendering modes, automatically detected based on container capabilities:

1. Xorg Mode (Preferred)

Requirements:
  • DRM/DRI device access (/dev/dri/card0 or similar)
  • NVIDIA GPU with working drivers
  • X server support
Advantages:
  • Full hardware GPU acceleration
  • Best performance
  • Lowest latency
  • Supports all WebGPU features
Configuration:
export DISPLAY=:99
export DUEL_CAPTURE_USE_XVFB=false
export GPU_RENDERING_MODE=xorg
export VK_ICD_FILENAMES=/usr/share/vulkan/icd.d/nvidia_icd.json
Xorg Setup: The deployment script automatically configures Xorg for headless GPU rendering:
# Auto-detect GPU BusID
GPU_BUS_ID=$(nvidia-smi --query-gpu=pci.bus_id --format=csv,noheader | head -1)

# Generate Xorg config
cat > /etc/X11/xorg-nvidia-headless.conf << EOF
Section "ServerLayout"
    Identifier     "Layout0"
    Screen      0  "Screen0"
EndSection

Section "Device"
    Identifier     "Device0"
    Driver         "nvidia"
    BusID          "PCI:1:0:0"
    Option         "AllowEmptyInitialConfiguration" "True"
    Option         "UseDisplayDevice" "None"
EndSection

Section "Screen"
    Identifier     "Screen0"
    Device         "Device0"
    DefaultDepth    24
    SubSection     "Display"
        Depth       24
        Virtual    1920 1080
    EndSubSection
EndSection
EOF

# Start Xorg
Xorg :99 -config /etc/X11/xorg-nvidia-headless.conf -noreset &
Verification:
# Check Xorg is running
xdpyinfo -display :99

# Check GPU rendering
DISPLAY=:99 glxinfo | grep "OpenGL renderer"
# Should show: NVIDIA GeForce RTX ...

2. Headless EGL Mode (Fallback)

Requirements:
  • NVIDIA GPU with EGL support
  • No DRM/DRI device access required
  • Chrome’s new headless mode
Advantages:
  • Works in containers without DRM/DRI access
  • No X server required
  • Ideal for Vast.ai containers
  • Still uses hardware GPU via NVIDIA EGL
Configuration:
export DISPLAY=
export STREAM_CAPTURE_HEADLESS=new
export STREAM_CAPTURE_USE_EGL=true
export GPU_RENDERING_MODE=headless-egl
export VK_ICD_FILENAMES=/usr/share/vulkan/icd.d/nvidia_icd.json
Chrome Flags:
--headless=new                    # Chrome's new headless mode
--use-gl=egl                      # Use EGL directly
--ozone-platform=headless         # Headless Ozone platform
--enable-features=VaapiVideoDecoder,VaapiVideoEncoder  # GPU video encoding
Verification:
# Check EGL library exists
ls -la /usr/lib/x86_64-linux-gnu/libEGL_nvidia.so.0

# Test Chrome with EGL
google-chrome-unstable --headless=new --use-gl=egl --enable-unsafe-webgpu \
  --screenshot=test.png https://get.webgl.org/webgpu/

Automatic GPU Detection

The scripts/deploy-vast.sh script automatically detects and configures the best GPU rendering mode:
# 1. Check for DRI devices
if [ -d "/dev/dri" ] && [ -e "/dev/dri/card0" ]; then
    # DRI available → Use Xorg mode
    export GPU_RENDERING_MODE=xorg
    export DISPLAY=:99
    export DUEL_CAPTURE_USE_XVFB=false
    # Start Xorg with NVIDIA config
else
    # No DRI → Use headless EGL mode
    export GPU_RENDERING_MODE=headless-egl
    export DISPLAY=
    export STREAM_CAPTURE_HEADLESS=new
    export STREAM_CAPTURE_USE_EGL=true
fi

# 2. Force NVIDIA-only Vulkan ICD (avoid Mesa conflicts)
export VK_ICD_FILENAMES=/usr/share/vulkan/icd.d/nvidia_icd.json

Environment Variables

GPU Rendering Configuration

VariableValuesDescription
GPU_RENDERING_MODExorg, headless-eglRendering mode (auto-detected)
DISPLAY:99, emptyX display (empty for headless EGL)
DUEL_CAPTURE_USE_XVFBtrue, falseUse Xvfb (deprecated, always false)
VK_ICD_FILENAMES/usr/share/vulkan/icd.d/nvidia_icd.jsonForce NVIDIA Vulkan ICD

Chrome Capture Configuration

VariableValuesDescription
STREAM_CAPTURE_HEADLESSfalse, new, trueHeadless mode
STREAM_CAPTURE_USE_EGLtrue, falseUse EGL directly
STREAM_CAPTURE_CHANNELchrome-devBrowser channel
STREAM_CAPTURE_ANGLEvulkan, glANGLE backend
STREAM_CAPTURE_DISABLE_WEBGPUtrue, falseDisable WebGPU

System Requirements

NVIDIA Drivers

Required:
  • NVIDIA GPU (RTX 3060 Ti or better)
  • NVIDIA driver version 525+ (for Vulkan 1.3)
  • Vulkan ICD installed
Installation:
# Check driver version
nvidia-smi

# Install Vulkan tools
apt-get install -y \
    mesa-vulkan-drivers \
    vulkan-tools \
    libvulkan1

# Verify Vulkan
vulkaninfo --summary

Xorg Dependencies (Xorg Mode)

apt-get install -y \
    xserver-xorg-core \
    xserver-xorg-video-nvidia-XXX \
    x11-xserver-utils \
    mesa-utils \
    libglvnd0 \
    libgl1 \
    libglx0
Replace XXX with your NVIDIA driver version (e.g., 525, 535).

EGL Dependencies (Headless EGL Mode)

apt-get install -y \
    libegl1 \
    libgles2 \
    mesa-utils \
    libglvnd0

Chrome Dev Channel

WebGPU support requires Chrome Dev channel (google-chrome-unstable):
# Install Chrome Dev
wget -q -O - https://dl.google.com/linux/linux_signing_key.pub | apt-key add -
echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" > /etc/apt/sources.list.d/google-chrome.list
apt-get update
apt-get install -y google-chrome-unstable

# Verify installation
google-chrome-unstable --version
Playwright Configuration:
const browser = await chromium.launch({
  channel: 'chrome-dev',  // Maps to google-chrome-unstable
  headless: false,        // or 'new' for headless EGL
  args: [
    '--use-gl=egl',       // or '--use-gl=angle'
    '--use-angle=vulkan', // if using ANGLE
    '--enable-unsafe-webgpu',
  ]
});

Vulkan Configuration

Force NVIDIA ICD

Vast.ai containers may have conflicting Mesa Vulkan ICDs. Force NVIDIA-only:
export VK_ICD_FILENAMES=/usr/share/vulkan/icd.d/nvidia_icd.json
Why This Matters:
  • Mesa ICDs can conflict with NVIDIA drivers
  • Some Mesa ICDs are misconfigured (point to wrong libraries)
  • Forcing NVIDIA ICD ensures hardware Vulkan works correctly
Verification:
# Check which ICD is being used
vulkaninfo | grep "deviceName"
# Should show: NVIDIA GeForce RTX ...

# List available ICDs
ls /usr/share/vulkan/icd.d/
# Should include: nvidia_icd.json

Vulkan Troubleshooting

Problem: vulkaninfo fails with “Cannot create Vulkan instance” Causes:
  1. NVIDIA driver not installed
  2. Vulkan ICD misconfigured
  3. Missing Vulkan libraries
Solutions:
# 1. Check NVIDIA driver
nvidia-smi
# If fails: Install NVIDIA driver

# 2. Check Vulkan ICD
cat /usr/share/vulkan/icd.d/nvidia_icd.json
# Should point to valid library path

# 3. Check Vulkan libraries
ldconfig -p | grep vulkan
# Should show libvulkan.so.1

# 4. Force NVIDIA ICD
export VK_ICD_FILENAMES=/usr/share/vulkan/icd.d/nvidia_icd.json
vulkaninfo --summary

Deployment Integration

ecosystem.config.cjs

The PM2 configuration automatically uses GPU rendering settings:
module.exports = {
  apps: [{
    name: "hyperscape-duel",
    env: {
      // GPU Rendering (auto-detected by deploy script)
      GPU_RENDERING_MODE: process.env.GPU_RENDERING_MODE || "xorg",
      DISPLAY: process.env.DISPLAY || "",
      DUEL_CAPTURE_USE_XVFB: "false",
      VK_ICD_FILENAMES: "/usr/share/vulkan/icd.d/nvidia_icd.json",
      
      // Chrome Capture
      STREAM_CAPTURE_HEADLESS: process.env.STREAM_CAPTURE_HEADLESS || "false",
      STREAM_CAPTURE_USE_EGL: process.env.STREAM_CAPTURE_USE_EGL || "false",
      STREAM_CAPTURE_CHANNEL: "chrome-dev",
      STREAM_CAPTURE_ANGLE: "vulkan",
      STREAM_CAPTURE_DISABLE_WEBGPU: "false",
    }
  }]
};

deploy-vast.sh

The deployment script handles GPU detection and configuration:
#!/bin/bash
# GPU Rendering Setup

# 1. Verify NVIDIA GPU
if ! nvidia-smi &>/dev/null; then
    echo "FATAL: NVIDIA GPU not accessible"
    exit 1
fi

# 2. Check for DRI devices
if [ -d "/dev/dri" ] && [ -e "/dev/dri/card0" ]; then
    # Xorg mode
    export GPU_RENDERING_MODE=xorg
    export DISPLAY=:99
    export DUEL_CAPTURE_USE_XVFB=false
    
    # Start Xorg
    Xorg :99 -config /etc/X11/xorg-nvidia-headless.conf &
    sleep 5
    
    # Verify Xorg
    if xdpyinfo -display :99 >/dev/null 2>&1; then
        echo "✓ Xorg started successfully"
    else
        echo "Xorg failed, falling back to headless EGL"
        export GPU_RENDERING_MODE=headless-egl
        export DISPLAY=
        export STREAM_CAPTURE_HEADLESS=new
        export STREAM_CAPTURE_USE_EGL=true
    fi
else
    # Headless EGL mode
    export GPU_RENDERING_MODE=headless-egl
    export DISPLAY=
    export STREAM_CAPTURE_HEADLESS=new
    export STREAM_CAPTURE_USE_EGL=true
fi

# 3. Force NVIDIA Vulkan ICD
export VK_ICD_FILENAMES=/usr/share/vulkan/icd.d/nvidia_icd.json

# 4. Start PM2 with GPU environment
bunx pm2 start ecosystem.config.cjs

Troubleshooting

Black Screen in Stream

Symptom: Stream shows black screen instead of game Diagnosis:
# 1. Check GPU access
nvidia-smi

# 2. Check Vulkan
vulkaninfo --summary

# 3. Check display (Xorg mode)
xdpyinfo -display :99

# 4. Check Chrome GPU status
# Navigate to chrome://gpu in the capture browser
# Should show: "WebGPU: Hardware accelerated"
Solutions: If Xorg mode:
# Check Xorg logs
cat /var/log/Xorg.99.log | tail -50

# Restart Xorg
pkill Xorg
Xorg :99 -config /etc/X11/xorg-nvidia-headless.conf &
If headless EGL mode:
# Check EGL library
ls -la /usr/lib/x86_64-linux-gnu/libEGL_nvidia.so.0

# Test Chrome with EGL
google-chrome-unstable --headless=new --use-gl=egl \
  --enable-unsafe-webgpu --screenshot=test.png \
  https://get.webgl.org/webgpu/

WebGPU Not Available

Symptom: Chrome reports “WebGPU not supported” Diagnosis:
# Check Chrome GPU info
google-chrome-unstable --headless=new --use-gl=egl \
  --enable-unsafe-webgpu --enable-logging=stderr \
  --log-level=0 https://get.webgl.org/webgpu/ 2>&1 | grep -i webgpu
Common Causes:
  1. Vulkan ICD not working:
    # Force NVIDIA ICD
    export VK_ICD_FILENAMES=/usr/share/vulkan/icd.d/nvidia_icd.json
    vulkaninfo --summary
    
  2. Missing Chrome flags:
    # Required flags for WebGPU
    --enable-unsafe-webgpu
    --enable-features=Vulkan,WebGPU
    --ignore-gpu-blocklist
    
  3. Wrong GL backend:
    # For Xorg mode
    --use-gl=angle --use-angle=vulkan
    
    # For headless EGL mode
    --use-gl=egl --ozone-platform=headless
    

Vulkan Instance Creation Fails

Symptom: vulkaninfo fails with “Cannot create Vulkan instance” Causes:
  • Conflicting Mesa ICDs
  • Broken NVIDIA ICD configuration
  • Missing Vulkan libraries
Solutions:
# 1. Force NVIDIA-only ICD
export VK_ICD_FILENAMES=/usr/share/vulkan/icd.d/nvidia_icd.json

# 2. Check ICD configuration
cat /usr/share/vulkan/icd.d/nvidia_icd.json
# Should point to valid library path

# 3. Verify library exists
ls -la /usr/lib/x86_64-linux-gnu/libGLX_nvidia.so.0

# 4. Test Vulkan
vulkaninfo --summary

DRI Devices Not Available

Symptom: /dev/dri/ directory doesn’t exist or is empty Cause: Container doesn’t have DRM/DRI device access (common on Vast.ai) Solution: Use headless EGL mode instead of Xorg:
export GPU_RENDERING_MODE=headless-egl
export DISPLAY=
export STREAM_CAPTURE_HEADLESS=new
export STREAM_CAPTURE_USE_EGL=true
Why This Works:
  • EGL doesn’t require DRM/DRI devices
  • Chrome’s new headless mode supports EGL
  • NVIDIA EGL provides hardware GPU access
  • WebGPU works via Vulkan over EGL

Performance Optimization

GPU Memory

Monitor GPU memory usage:
# Watch GPU memory
watch -n 1 nvidia-smi

# Check Chrome GPU memory
# Navigate to chrome://gpu in capture browser
Optimization:
# Limit texture size
STREAM_CAPTURE_WIDTH=1280
STREAM_CAPTURE_HEIGHT=720

# Reduce quality if needed
STREAM_CDP_QUALITY=70  # Default: 80

CPU Usage

GPU rendering offloads work from CPU:
# Monitor CPU usage
htop

# Check FFmpeg CPU usage
ps aux | grep ffmpeg
Expected CPU usage:
  • Xorg mode: 50-80% (encoding only)
  • Headless EGL mode: 60-90% (encoding + EGL overhead)
  • Software rendering: 200-300% (NOT SUPPORTED)

Tested Configurations

GPUModeStatusNotes
RTX 3060 TiXorg✅ WorkingPreferred configuration
RTX 4090Xorg✅ WorkingExcellent performance
RTX 4090Headless EGL✅ WorkingVast.ai containers
RTX 3060 TiHeadless EGL✅ WorkingVast.ai containers
Any GPUXvfb❌ Not SupportedSoftware rendering too slow
Any GPUSwiftShader❌ Not SupportedCPU Vulkan too slow
Any GPULavapipe❌ Not SupportedCPU Vulkan too slow

Commit History

Recent GPU rendering improvements:
  • dd649da (Feb 27, 2026): Fix headless mode flag passing (args vs option)
  • e51a332 (Feb 27, 2026): Add headless EGL mode for containers without DRM
  • 30bdaf0 (Feb 27, 2026): Require NVIDIA Xorg, no software rendering fallback
  • 5fe4a18 (Feb 27, 2026): Add robust Xorg/Xvfb fallback handling
  • 263bfc5 (Feb 27, 2026): Use Xorg instead of Xvfb for NVIDIA GPU rendering
  • 89b78e3 (Feb 27, 2026): Use NVIDIA hardware Vulkan instead of SwiftShader
  • 54836200 (Feb 27, 2026): Enable SwiftShader for WebGPU (deprecated)
  • ba1cf0a (Feb 27, 2026): Use Lavapipe software Vulkan (deprecated)
  • ef8033c (Feb 27, 2026): Use SwiftShader and WebGL fallback (deprecated)