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
| Variable | Values | Description |
|---|
GPU_RENDERING_MODE | xorg, headless-egl | Rendering mode (auto-detected) |
DISPLAY | :99, empty | X display (empty for headless EGL) |
DUEL_CAPTURE_USE_XVFB | true, false | Use Xvfb (deprecated, always false) |
VK_ICD_FILENAMES | /usr/share/vulkan/icd.d/nvidia_icd.json | Force NVIDIA Vulkan ICD |
Chrome Capture Configuration
| Variable | Values | Description |
|---|
STREAM_CAPTURE_HEADLESS | false, new, true | Headless mode |
STREAM_CAPTURE_USE_EGL | true, false | Use EGL directly |
STREAM_CAPTURE_CHANNEL | chrome-dev | Browser channel |
STREAM_CAPTURE_ANGLE | vulkan, gl | ANGLE backend |
STREAM_CAPTURE_DISABLE_WEBGPU | true, false | Disable 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:
- NVIDIA driver not installed
- Vulkan ICD misconfigured
- 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:
-
Vulkan ICD not working:
# Force NVIDIA ICD
export VK_ICD_FILENAMES=/usr/share/vulkan/icd.d/nvidia_icd.json
vulkaninfo --summary
-
Missing Chrome flags:
# Required flags for WebGPU
--enable-unsafe-webgpu
--enable-features=Vulkan,WebGPU
--ignore-gpu-blocklist
-
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
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
| GPU | Mode | Status | Notes |
|---|
| RTX 3060 Ti | Xorg | ✅ Working | Preferred configuration |
| RTX 4090 | Xorg | ✅ Working | Excellent performance |
| RTX 4090 | Headless EGL | ✅ Working | Vast.ai containers |
| RTX 3060 Ti | Headless EGL | ✅ Working | Vast.ai containers |
| Any GPU | Xvfb | ❌ Not Supported | Software rendering too slow |
| Any GPU | SwiftShader | ❌ Not Supported | CPU Vulkan too slow |
| Any GPU | Lavapipe | ❌ Not Supported | CPU 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)