NVIDIA Support Issue: CloudXR.js 6.1.0 — Black Screen in Immersive VR Mode on Quest 3

## Summary

CloudXR.js 6.1.0 renders decoded video frames correctly in WebXR inline/2D mode but displays a black screen in immersive VR mode (`immersive-vr`) on Meta Quest 3. The streaming connection is stable, frames are sent and received, but the video content is not rendered to the XRWebGLLayer framebuffer.

## Environment

**Client:**

- Device: Meta Quest 3 (latest OS, auto-updated May 2026)

- Browser: Meta Quest Browser (Chromium-based)

- CloudXR.js: 6.1.0 (from NGC)

- Samples tested: Simple WebGL sample AND React Three Fiber sample — both exhibit the same issue

**Server:**

- Instance: AWS EC2 g6e.xlarge (NVIDIA L40S, 48 GB)

- OS: Windows Server 2022

- Driver: NVIDIA GRID 596.36 (WDDM mode)

- CloudXR Runtime: 6.0.5

- Device profile: `quest3`

- Application: CloudXR LÖVR sample (from GitHub - NVIDIA/cloudxr-lovr-sample: Stream your LÖVR VR applications wirelessly to supported headsets using NVIDIA CloudXR technology. This sample integrates CloudXR Runtime into LÖVR, enabling untethered VR experiences without physical cables. · GitHub )

**Network:**

- Signaling: WSS via nginx reverse proxy (port 48322 → localhost:49100)

- Media: Direct UDP via `mediaAddress` (ICE disabled per docs)

- Web client hosted on HTTPS (AWS CloudFront)

## Symptoms

### What works (inline/2D mode):

- Connecting via HTTP directly to port 49100 (no immersive session)

- Video frames decode and render correctly to the HTML canvas

- LÖVR scene content visible: controller models, cubes with XYZ axes, hand tracking data

- Connection stable for extended periods

### What fails (immersive VR mode):

- App enters `immersive-vr` session successfully (WebXR permission granted)

- Connection to server establishes (signaling + media)

- Server confirms frames are being sent (logs show 80+ frames delivered)

- Quest displays **completely black** in the headset

- In React sample: the opaque data channel UI panel (Action 1/Action 2 buttons) renders correctly as a floating 2D panel in VR space — proving the XR session is active and local rendering works

- Connection remains stable (no timeout, no crash) — data is flowing bidirectionally

- Issue persists regardless of codec (H.264, H.265, AV1), resolution settings, or foveation configuration

## Key Observation

The **same server, same connection, same frames** render correctly in inline mode but not in immersive mode. The only difference is the rendering target:

- Inline: frames rendered to HTML `` element ✅

- Immersive: frames should render to `XRWebGLLayer` framebuffer ❌

This points to a client-side issue in how CloudXR.js renders decoded frames to the XR compositor’s framebuffer in immersive mode.

## Reproduction Steps

1. Set up CloudXR Runtime 6.0.5 on a GPU server with the LÖVR sample running in `–webrtc` mode

2. Host either the Simple WebGL or React Three Fiber sample on HTTPS

3. On Quest 3, navigate to the sample and configure connection settings

4. Connect — observe “stream started” / stable connection

5. App enters immersive VR — observe black screen (no rendered content)

6. For comparison: connect via HTTP in non-immersive mode — observe rendered content (cubes, controllers)

## What We’ve Ruled Out

- **Server encoding:** NVENC is working (confirmed via logs: “Server sent the first video frame to client”, 80+ frames delivered)

- **Network delivery:** Frames arrive at the client (connection stable, no timeouts)

- **Client decoding:** Frames decode correctly (visible in 2D inline mode)

- **Codec compatibility:** Tested H.264, H.265, AV1 — all show same black screen

- **Resolution:** Tested various resolutions (1024x1024 through 4096x4032) — same result

- **WebXR session:** XR session is active (React sample’s local UI renders in VR space)

- **Quest OS version:** Latest (auto-updated)

- **Both samples:** Simple WebGL and React Three Fiber samples both exhibit identical behavior

## Questions for NVIDIA

1. Is there a known issue with CloudXR.js 6.1.0 rendering to XRWebGLLayer on Quest 3?

2. Are there specific WebGL context creation flags or XRWebGLLayer configuration required for CloudXR frame rendering in immersive mode?

3. Is there a working reference deployment of CloudXR.js 6.1.0 streaming to Quest 3 in immersive VR mode that we can compare against?

4. Does the `session.render(timestamp, frame, xrWebGLLayer)` call have specific requirements for the WebGL state or framebuffer binding that the samples might not be satisfying?

## Browser Console Errors (via chrome://inspect remote debugging)

The following errors appear in the Quest 3 browser console when entering immersive VR mode:

```

⚠ “No WebGL binding found”

c @ bundle.js:2

await in c

dispatchEvent @ bundle.js:2

Nt.setSession @ bundle.js:2

await in Nt.setSession

He @ bundle.js:2

Ve @ bundle.js:2

Qe @ bundle.js:2

await in Qe

enterVR @ bundle.js:2

Running on HTTPS protocol - using secure WebSocket (WSS)

No proxy URL - using direct WSS connection

Using user-provided server IP: 18.191.19.82

Using user-provided port: 48322

⚠ [WebGLStateApply] Cannot bind UNIFORM_BUFFER at index 0: buffer has been deleted. Skipping.

CloudXR session connect initiated

❌ WebGL context is already wrapped with state tracking. Returning existing BoundWebGLState.

⚠ WebGL context is already wrapped with state tracking. Returning existing BoundWebGLState.

⚠ WebGL context is already wrapped with state tracking. Returning existing BoundWebGLState.

(repeated 14+ times)

Requested frame rate 90 is supported; requested it.

❌ InvalidStateError: OfferSession promise was cancelled because it was called more than once.

```

### Analysis of Console Errors

1. **“No WebGL binding found”** — This appears to be the root cause. When entering immersive VR, CloudXR.js cannot find the WebGL shader/program binding needed to render decoded video frames to the XR layer’s framebuffer.

2. **“Cannot bind UNIFORM_BUFFER at index 0: buffer has been deleted”** — Indicates WebGL state corruption during the transition to immersive mode.

3. **“WebGL context is already wrapped with state tracking”** — CloudXR.js’s internal `BoundWebGLState` tracker is conflicting with the WebGL context. This occurs in both the Simple WebGL sample and the React Three Fiber sample, suggesting it’s internal to CloudXR.js rather than sample-specific.

4. **“OfferSession promise was cancelled because it was called more than once”** — Suggests a race condition in the WebRTC session establishment during XR mode entry.

### Hypothesis

CloudXR.js 6.1.0’s WebGL state management (`BoundWebGLState`) appears to lose track of the WebGL context when the browser transitions to an immersive XR session. The XR session may create or reconfigure the WebGL context in a way that invalidates CloudXR’s internal state tracking, causing the “No WebGL binding found” error and preventing frame rendering to the XRWebGLLayer.

[Issue still persists]

Update — May 19, 2026: Reproduced on fresh deployment + confirmed rendering works on desktop (IWER)

We’ve done additional testing that further isolates this issue:

  1. Reproduced on a completely new deployment:

Fresh EC2 g6e.xlarge in us-west-2 (different region/instance from original report), Windows Server 2022, GRID driver 596.36, CloudXR Runtime 6.0.5, LÖVR sample with --webrtc, CloudXR.js 6.1.0 Simple WebGL sample built fresh from GitHub and hosted on CloudFront. Media configured via mediaAddress mode per NAT Configuration docs.

Full pipeline confirmed working: signaling connects (WSS via nginx proxy), media path establishes, “CloudXR stream started” / “Streaming started!” in client console, stream stops cleanly on user exit (no error code). Server logs show no errors during streaming.

On Quest 3: black screen in immersive mode. New browser diagnostic from chrome://inspect:

Note: The XRSession has completed multiple animation frames without drawing anything to the baseLayer’s framebuffer, resulting in no visible output.
Tested with H.264, AV1, multiple resolutions and bitrates — same result in all cases.

  1. Same deployment renders correctly on desktop Chrome with IWER:

Using the exact same server, same CloudFront-hosted client, same connection settings — opened the sample in Chrome on a laptop. IWER (Immersive Web Emulation Runtime) loaded automatically and emulated a Quest 3 session. The LÖVR scene rendered correctly: 3D cubes with colored axes visible, interactive (rotation/manipulation via IWER controls), streaming stable.

Conclusion: CloudXR.js’s rendering code works correctly when the XRWebGLLayer is provided by IWER (desktop emulation). The same code fails when running on the actual Quest 3 browser’s native XRWebGLLayer implementation. This points to a compatibility issue between CloudXR.js’s framebuffer rendering and the Meta Quest Browser’s real WebXR/WebGL implementation — not a fundamental bug in CloudXR.js’s render path.

Quest 3 details: Meta Quest Browser version 146.1.0.27.53 (Chromium 146), latest Quest OS (auto-updated May 2026).