diff --git a/Cargo.lock b/Cargo.lock index e87b2ec4..a8d3c23e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4313,6 +4313,7 @@ dependencies = [ "url", "vello", "wuff", + "x11rb 0.13.2", ] [[package]] diff --git a/README.md b/README.md index 624c9c36..d9811cbb 100644 --- a/README.md +++ b/README.md @@ -100,7 +100,7 @@ Every panel is a tab you can drag, split, or stack. | Scenes | Pick the scene in preview, and add, rename (double-click), reorder, remove, or tick **Publish** on one (see [Published scenes](#published-scenes)). A scene on program, or still leaving it in a transition, cannot be removed, even by an undo, until program cuts away from it. | | History | See every edit, and undo or redo back to any of them. | | Items | Place, show, hide, and order what the preview scene or the top layer draws, back to front. The top layer is edited over a scene of the program's size. Select an item to filter or copy it. | -| Sources | Add a source by hand, see whether each and its own track are live and where it is shown, clone one, and remove one. Select a source to filter it. A camera or broadcast without a new picture, or a microphone or system audio without new sound, for a second reads as stalled. A browser source shows whether its page is copied on the GPU or, as a fallback, uploaded from memory (CPU), in place of a track, and **Reload** restarts its page. A media file reads as ended once it plays to its end without looping, **Play** plays it from its start, **Stop** stops it at once, blank and silent, until played again, and **Reload** reads the file again. | +| Sources | Add a source by hand, see whether each and its own track are live and where it is shown, clone one, and remove one. Select a source to filter it. A camera or broadcast without a new picture, or a microphone or system audio without new sound, for a second reads as stalled. A browser source shows whether its page is copied on the GPU or, as a fallback, uploaded from memory (CPU, saying why on hover), in place of a track, and **Reload** restarts its page. A media file reads as ended once it plays to its end without looping, **Play** plays it from its start, **Stop** stops it at once, blank and silent, until played again, and **Reload** reads the file again. | | Devices | List this machine's cameras, displays, windows, and audio inputs, and add one as a source. | | Guests | Invite a guest, show their join link as a QR code, see who joined, and take a guest out of every scene. | | Filters | Remove the selected source's background, crop the selected source or item, add, order, and set its filters, set an item's blend mode, and copy or paste filters. | @@ -890,7 +890,8 @@ driver that imports them, and NV12 capture and VideoToolbox decode surfaces on macOS. A browser source's page is copied on the GPU from the shared texture CEF paints, given the same Vulkan DMA-BUF import and a display to paint through: the Wayland one when `$WAYLAND_DISPLAY` is set, needing no XWayland, or else -the X one in `$DISPLAY`. Every other source, every source on Windows or on a +the X one in `$DISPLAY`, when the X server runs on the studio's GPU, since +CEF paints on the X server's there. Every other source, every source on Windows or on a GPU that cannot import, and every still image delivers its frames from the CPU, which the compositor uploads. A browser source takes that path with no display at all too, and there renders its page in software, WebGL included, so @@ -986,8 +987,9 @@ congested or losing packets, the relay is far away, the encoder is behind or stuck, a source stalled (a camera or broadcast the program draws, or a microphone or system audio the mix on program plays: unmuted and not left out of it), a source the program shows or plays failed or, as a media file -that does not loop, played to its end, or viewers are late, stalling, or cannot -decode a track. A relay lost while the other serves is +that does not loop, played to its end, a browser source the program shows is +uploaded from memory rather than copied on the GPU, or viewers are late, +stalling, or cannot decode a track. A relay lost while the other serves is degraded, since viewers have nothing left to fall back to; with none serving it is unhealthy. A problem with a published scene's broadcast names the scene. Below that it shows: diff --git a/quest/m0/README.md b/quest/m0/README.md index c4f42cf0..79eed49d 100644 --- a/quest/m0/README.md +++ b/quest/m0/README.md @@ -100,7 +100,6 @@ repository. - [Web studio](/quest/m0/web.md) - the full studio in wasm on WebGPU and WebCodecs, served from this repository - [Virtual camera](/quest/m0/vcam/README.md) - the program or a published scene exposed as a system camera on Linux, Windows, and macOS - [Browser sources on the GPU under Mesa](/quest/m0/cef-headless.md) - shared-texture pages paint on Intel and AMD under Wayland, and a page that cannot paint fails loudly -- [Browser sources on the GPU under X11 on NVIDIA](/quest/m0/cef-x11-nvidia.md) - the X11 GPU path paints on NVIDIA, or falls back to the CPU path loudly - [A browser helper exits with the studio](/quest/m0/browser-helper-exit.md) - no orphaned CEF helper after a crash, kill, or timed-out test - [Nightly and the browser suite pass](/quest/m0/nightly-green.md) - render-sw, cookies, and the X11 clipboard test fixed at their causes - [GPU tests exit cleanly on NVIDIA](/quest/m0/gpu-tests-exit.md) - compositor tests no longer crash on exit on NVIDIA diff --git a/quest/m0/cef-x11-nvidia.md b/quest/m0/cef-x11-nvidia.md deleted file mode 100644 index 8a89ed5a..00000000 --- a/quest/m0/cef-x11-nvidia.md +++ /dev/null @@ -1,31 +0,0 @@ -# [S] Browser sources on the GPU under X11 on NVIDIA - -## Goal - -On an NVIDIA GPU in an X11 or XWayland session, browser sources paint on -the GPU path. If the studio cannot give CEF a GBM device, it detects that at -startup and takes the CPU path with a note in Health, rather than leaving -pages stuck in Starting. - -## Plan - -From [moq-dev/studio#59](https://github.com/moq-dev/studio/pull/59), picked -2026-11-05 (maintainer, /quest-plan), m0 by the rule that fixes join m0. - -- On nixos (RTX 3070 Ti, NVIDIA 580), the GPU path under X11 never paints: - CEF's GPU process logs "Can't create buffer -- gbm device is missing". - Wayland sessions avoid it since #59, but X11-only sessions still hit it. -- Since [moq-dev/studio#73](https://github.com/moq-dev/studio/pull/73) the X11 - path passes `--use-angle=gl-egl`, which made it paint on Mesa; rerun nixos - with it first. On nixos2 under GNOME's XWayland, with the studio on the RTX - 2070, CEF still allocated on the Intel GPU that runs the X server (Intel - X-tiled modifier) despite `--render-node-override`. -- First find why. Likely suspects: the NVIDIA GBM backend - (`nvidia-drm_gbm.so`) is not on CEF's search path (`GBM_BACKENDS_PATH`), or - `nvidia-drm` modeset is off. Fix it if the studio can, for example by - passing the backend path to the helper or packaging it. -- Otherwise fail loud: probe for a GBM device when the helper starts, and if - there is none, take the CPU path and say why in Health and the Sources panel. - Fail on an observed probe result, never on a timeout. -- Verify on nixos under X11 (XWayland) and record how in the PR; no CI job - has a GPU. diff --git a/rs/moq-scene/Cargo.toml b/rs/moq-scene/Cargo.toml index 88f941dd..ffcd7a40 100644 --- a/rs/moq-scene/Cargo.toml +++ b/rs/moq-scene/Cargo.toml @@ -88,9 +88,12 @@ wuff = "0.2" # `accelerated_osr` copies the page's shared texture into the studio's device. cef = { version = "156.3", default-features = false, features = ["accelerated_osr"], optional = true } postcard = { version = "1", default-features = false, features = ["use-std"] } -rustix = { version = "1", features = ["net", "process", "stdio"] } +rustix = { version = "1", features = ["fs", "net", "process", "stdio"] } # The helper's CEF profile, removed once the helper has exited. tempfile = { workspace = true } +# Which GPU the X server runs on, which CEF paints on under X11. Pure Rust, and +# 0.13 as the studio's hotkeys use. +x11rb = { version = "0.13", features = ["dri3"] } [dev-dependencies] # An encoder on every machine, for the source track and replay tests. diff --git a/rs/moq-scene/src/browser/host.rs b/rs/moq-scene/src/browser/host.rs index 378812f9..e5e3991c 100644 --- a/rs/moq-scene/src/browser/host.rs +++ b/rs/moq-scene/src/browser/host.rs @@ -496,8 +496,9 @@ wrap_app! { Display::X11 => "x11", }; command_line.append_switch_with_value(Some(&"ozone-platform".into()), Some(&platform.into())); - // On X11, ANGLE otherwise draws through GLX, which on Mesa - // leaves shared textures blank. Wayland is always EGL. + // On X11, ANGLE otherwise draws through GLX, which leaves + // shared textures blank on Mesa, and on NVIDIA finds no GBM + // device to allocate them. Wayland is always EGL. if *display == Display::X11 { command_line.append_switch_with_value(Some(&"use-angle".into()), Some(&"gl-egl".into())); } diff --git a/rs/moq-scene/src/browser/mod.rs b/rs/moq-scene/src/browser/mod.rs index c16dbcfb..d5aefb07 100644 --- a/rs/moq-scene/src/browser/mod.rs +++ b/rs/moq-scene/src/browser/mod.rs @@ -12,7 +12,7 @@ //! become one; CEF's own subprocesses start the same way. The helper paints //! into a shared GPU texture the studio copies on its device, or into memory //! the studio uploads when either side cannot share textures or there is no -//! display to paint them through ([`Paint`] says which). Its popups, such as a +//! display to paint them through ([`Paint`] says which, and why). Its popups, such as a //! `