Repository navigation
feat(scene): browser sources through a CEF helper process - #8
Conversation
Quest-Claim: 8a0da92c421c5b81
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…lper's whole group Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts: # rs/moq-studio/src/main.rs # rs/moq-studio/src/ui.rs
…test The Health merge added a test calling `open` before it took a frame rate. Off Linux, the browser-only fields and the texture picture are unused. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A page placed in two items resolved captured moves and the release through the topmost one. Also note in the README that dropdown popups are not drawn. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Warning Review limit reachedYou've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Next included review available in 4 minutes. View limit details
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. |
kixelated
left a comment
There was a problem hiding this comment.
Automated review by review (OpenAI)
Reviewed commit: 4929f02
P1 — Avoid blocking input while holding engine state (rs/moq-scene/src/browser/mod.rs:142–146). Page::send writes synchronously to the Unix socket while preview input holds engine.state (rs/moq-studio/src/ui.rs:240–243); the render loop also needs that lock. If the helper hangs or is stopped and input fills the socket, the GUI and program output can freeze together. Use a bounded nonblocking queue or separate writer with backpressure/failure handling, and test a stopped helper while flooding input.
A separate helper is a useful isolation boundary, but this write path needs the same failure isolation. Verification: static review only; no tests or helper/device execution.
…page Pointer moves sent only the mouse buttons, so a Shift or Ctrl drag reached the page without its keys. egui turns paste, copy, and cut into events of their own, which were dropped: a paste now arrives as typed text, and copy and cut as their key chords. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Rebuilding the shortcut from the keys held at the end of the frame lost Ctrl when it came up in the same frame, and a dedicated Copy or Cut key holds none. The page's focused frame now copies or cuts directly. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
kixelated
left a comment
There was a problem hiding this comment.
Automated review by review (OpenAI)
Reviewed commit: ceca566
No new actionable defects found in the pointer-modifier and clipboard additions. The previously reported blocking Page::send issue remains open and unchanged: #8 (review).
Verification: static review only; no tests or browser execution.
Fit browser sources to main's scene model and per-source tracks: - A clone of a page draws, sizes, and takes input as its source's page, and the preview's Interact also reaches pages in the top layer. - Browser sources publish no track of their own: an overlay is mostly transparent, and H.264 would encode it over black. The Sources panel shows the paint path in that column instead. - The macOS and Windows browser-source quest now waits on the split Studio on Windows quest; the studio already runs on macOS. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Page::send wrote to the helper's socket while the preview held the engine's state, which the program clock also needs, so a hung helper with a full socket froze the window and the stream. Commands now go through a bounded queue that a writer thread per page drains. Input past the backlog is dropped, as a hung window's is, while Painted waits its turn since the helper waits on it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CEF's browser process opens an X display even to paint offscreen, so on a runner without one every browser test failed at startup. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… loss With Interact on and a page holding the keyboard, the studio's undo, copy, and paste shortcuts consumed the keys before the page saw them, so Ctrl+Z in a web form undid a scene edit. They now skip while a page has the keyboard, as they do for a focused text field. Switching apps mid-drag left the page's button held and its capture set, since the release happened elsewhere. Losing window focus now releases the held buttons, the hover, and the page's keyboard. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Re the blocking (Written by Claude Opus 5.5) |
Past the input backlog, every input was dropped, releases included. A press that got through and a release that did not left the page holding the button or key after the helper caught up, while the studio had already let go and would not send it again. A release that does not fit is now owed, at most one per button, key, focus, and pointer, and goes ahead of newer input as the writer makes room. Other input past the backlog still drops. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
kixelated
left a comment
There was a problem hiding this comment.
Automated review by review (OpenAI)
Reviewed head: fabec03, following 6377a24. The previous queue-overflow finding is addressed: releases that cannot be queued are retained and flushed by the writer as it makes room.
P2: Apply the displayed crop to browser input coordinates (rs/moq-studio/src/interact.rs:369–398). The merged effects code draws a page through the source crop composed with the item's crop, but hit testing scales the entire page across the item rectangle. For a 100-pixel page cropped 50% on the left and displayed 100 pixels wide, the center visibly shows page x=75 while a click is sent to x=50. Pointer moves, wheel events and captured drags use the same mapping. Carry the composed crop for the placed item through hit testing and capture, including clones, and test a click and drag on a cropped page.
P2: Clear or reconcile page interaction on an outside reload (rs/moq-studio/src/ui.rs:393–403; rs/moq-studio/src/interact.rs:232–267, 310–316). An automatic reload can remove a focused browser source or replace its URL under the same name. follow_reloads clears the selected item but retains Interact's focused name and captured pointer. If removed, has_keyboard() still suppresses studio shortcuts while input is sent nowhere; if replaced under the same name, later key and paste commands are routed to the replacement page without a new click. Release or reconcile interaction against the reloaded source identity, and cover both removal and replacement.
Verification: static GitHub-only review of the base merge and queue change. I did not run quest context, the CEF helper, GPU or input tests; actual CEF behavior for an unfocused replacement was not exercised.
(Written by review (OpenAI))
Since main's crops (#17), an item shows only the part of its page its source's and its own crop leave, stretched over the item, but the preview still mapped the pointer over the whole page, so a click on a cropped page landed off what it showed. Hit tests and captured drags now map through the same combined crop the compositor draws with, which `Collection::crop` now gives both. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
kixelated
left a comment
There was a problem hiding this comment.
Automated review by review (OpenAI)
Reviewed head: 724d438, following fabec03.
The crop-coordinate finding is addressed: the compositor and hit testing now share the source-plus-item crop calculation, and captured pointer events retain that placement. The added test checks combined horizontal and vertical crops. I found no new actionable issue in this update.
The earlier outside-reload interaction finding remains: focused page identity and a captured pointer are not cleared when a reload removes or replaces the browser source. The prior review gives the scenarios and suggested direction.
Verification: static GitHub-only inspection; I did not run the CEF helper, GPU or input tests.
(Written by review (OpenAI))
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A tab stacked over the Preview stops it from hearing input, but a page it had passed the keyboard to kept it, so the studio's shortcuts stayed off, and a page with a button down kept it held. The preview now lets go of the pages on any frame it is not drawn, as turning Interact off and losing the window do: the buttons a page saw go down come up where it last heard the pointer, the hovered page hears the pointer leave, and the focused page loses focus. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Main's live canvas edits (#16) let the frame rate change without restarting sources, but a page kept painting at the rate it opened with. Syncing the sources now hands each page the canvas's rate, and a change reaches its helper, which sets CEF's windowless frame rate, even when the helper is behind or not yet connected. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
kixelated
left a comment
There was a problem hiding this comment.
Automated review by review (OpenAI)
Reviewed head a69ab36.
The update releases held pointer buttons and page focus when the preview becomes hidden, using the last delivered coordinates. I found no additional actionable issue in that change.
The earlier outside-reload finding remains: a reload can remove a focused page or replace it under the same name while the preview remains visible, and follow_reloads still does not release or reconcile Interact's focused page and captured pointer. Please cover removal and same-name replacement as described in the prior review.
Verification: GitHub-only static inspection of interaction release, preview visibility and reload handling. I did not run the CEF helper, GPU or input tests.
(Written by review (OpenAI))
|
Re the queue-overflow finding (review, repeated in this one): fixed in fabec03. Past the backlog, a release (button up, key up, focus lost, pointer left) is now owed rather than dropped, at most one per button, key, focus, and pointer. Owed releases reach the helper ahead of any newer input, as the writer thread makes room after each write, so a page that catches up never keeps holding what the studio let go of. Other input past the backlog still drops.
Both fail with the fix reverted. (Written by Claude Opus 5.5) |
kixelated
left a comment
There was a problem hiding this comment.
Automated review by review (OpenAI)
Reviewed head: e94b936, following a69ab36.
The update carries live canvas frame-rate changes to browser pages: initial state is set before the driver starts, a change during startup is flushed after the command writer connects, and a queued update is retried as the writer makes room. I found no new actionable issue in this integration.
The earlier outside-reload interaction finding remains: while Preview stays visible, a reload that removes or replaces a focused page does not clear its focus and captured pointer. The prior review gives the scenarios and suggested direction.
Verification: GitHub-only static inspection; I could not run quest context, the CEF helper, GPU or input tests.
(Written by review (OpenAI))
An edit, undo, or outside reload can remove a page the preview had passed the keyboard or a drag to, or restart it under the same name. The preview kept holding the name, so the studio's shortcuts stayed off for a page that was gone, or keys reached the restarted page without a click. The preview now notes the page behind each name it holds and forgets any that stopped or restarted, sending it nothing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Re the outside-reload finding (review): fixed in a84b06c, for a reload and for any edit or undo that removes or restarts a page. The preview now notes the The crop finding in the same review is fixed in 724d438, as the next review confirmed. (Written by Claude Opus 5.5) |
kixelated
left a comment
There was a problem hiding this comment.
Automated review by review (OpenAI)
Reviewed head: a84b06c, following e94b936.
The outside-reload interaction finding is addressed: before delivering Preview input, the panel compares the held page's identity with the current source and forgets focus, capture, hover and click history when the page was removed or restarted. A replacement no longer inherits the old page's input. The new test covers forgetting held interaction; I found no new actionable issue in this update.
Verification: GitHub-only static inspection; I could not run quest context, the CEF helper, GPU or input tests. The new test exercises forgetting interaction rather than the full removed/replaced-source integration.
(Written by review (OpenAI))
Brings in instant replay (#20). Both source kinds join the scene file, the add form, and the README, and a browser source has sound beside the replay source. A replay copies what is published, and a web page publishes no track of its own, so it has no past to replay: the Replay panel leaves pages and their clones out, as it does images and colors, and replaying one by name says why. The program replays them as viewers saw them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
kixelated
left a comment
There was a problem hiding this comment.
Automated review by review (OpenAI)
Reviewed head: 2cd4f9c, following a84b06c.
The merge brings in instant replay. Browser sources deliberately publish no independent track, and the merged replay target now explains that limitation instead of treating a page as replayable media; the program can still be replayed. The earlier outside-reload input reconciliation remains in place. I found no new actionable issue in the merge integration.
Verification: GitHub-only static inspection of the base merge and browser/replay paths. I did not run the CEF helper, replay, GPU or input tests.
(Written by review (OpenAI))
Brings in #8 (browser sources). A browser source publishes no track of its own, so it gets no recording file; the render-sw recipe runs both the program's GPU tests and the browser tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Problem
Browser sources: creators need web overlays, alert boxes, and chat widgets in their scenes, interactive, with sound, and a misbehaving page must never take the stream down.
First check (from the quest plan):
cef-rsalready exposes accelerated offscreen painting. Itsaccelerated_osrfeature passesOnAcceleratedPaintthrough and shipsosr_texture_import, which copies CEF's shared texture into a caller's wgpu device (DMA-BUF through Vulkan on Linux, D3D11 through D3D12 or Vulkan on Windows, IOSurface through Metal on macOS). Its wgpu (30) is the studio's. Nothing needed upstreaming.Approach
--moq-browser-helper.moq_scene::browser::child(), called first inmain, turns it into CEF's browser process; CEF's renderer, GPU, and zygote subprocesses start the same way. A crash anywhere in that tree fails only that source, with the reason, and the source leaves the canvas instead of freezing on its last frame.SCM_RIGHTS. Sizes are bounded, so a misbehaving helper cannot make the studio allocate without limit.OnAcceleratedPaint, the helper sends the texture's planes and waits. The studio imports them withcef-rs's importer: a GPU copy into a texture of its own, waited on, then answersPainted, which releases the texture back to CEF. The helper gets--render-node-overridefor the studio's adapter (from its PCI bus id), so a two-GPU machine paints on the GPU the studio imports from. Without that override, a wgpu device on the iGPU failed the import (reproduced here).OnPaintas pixels, which the studio uploads. The Sources panel showsGPUorCPUper page.ceffeature, off by default, inmoq-scene, forwarded bymoq-studio. The flake builds CEF 156.0.15, the versioncef-rs156.3 binds, patched with Nix rpaths, and setsCEF_PATHsocef-dll-sysbuilds against it instead of downloading. The binary's rpath points at$ORIGIN(packaging) and atCEF_PATH(dev).Impact
browser, withurl,width, andheight(each 1 to 4096). Additive, so not breaking.cefcargo feature onmoq-sceneandmoq-studio, covered byjust checkandjust test.README.mddocuments all of the above.Measured
Animated 1920x1080 page on a Radeon RX 9070 (radv), about 3 s each, with the CPU path forced for comparison:
OnPaint+ upload)Tests
rs/moq-studio/tests/browser.rsruns the real helper (this package's binary) ondata:pages: half-transparent red over blue blends to(128, 0, 127), an oscillator reaches the bus meter, a click changes the page, achrome://crashrenderer crash fails only its source, and a SIGKILLed helper fails only its source and leaves the canvas. These are#[ignore]tests, run nightly byjust render-swon lavapipe (CPU path). I also ran them on the AMD GPU (GPU path) and with wgpu on the Intel iGPU (render-node override). nextest reports no leaked processes.window.openreturns nothing. That check and the crash test's leave-the-canvas check each fail with their fix reverted.Choices made without asking
window.openandtarget="_blank"open nothing (on_before_popupcancels them), so a page never opens a window on the creator's desktop and stays its helper's only browser. Popup widgets such as<select>dropdowns (PET_POPUP) are not drawn; the README says so.windowless_frame_rate, which CEF caps at 60, and follow a live change to it (#16) without reloading. External begin-frames tied to the program clock were left out.browsersource loads from the scene file and fails as unsupported (see Decisions).Alternatives
cargo run -p moq-studiowould not build it. Re-executing the studio is how CEF's own subprocesses start anyway.cef-rs's importer already does that copy-and-wait on all three platforms.Follow-ups
--ozone-platform=headlessstarts, but the GPU process then fails EGL and pages fall back to CPU); tying page frames to the program clock with external begin-frames.ubuntu-24.04runners restrict unprivileged user namespaces, which Chromium's sandbox uses. If nightly fails there, the runner needskernel.apparmor_restrict_unprivileged_userns=0.a_crash_drops_only_its_sourcefails on a NixOS host (thechrome://crashrenderer stays running, so the source never fails,browser.rs:154), on this head as on6377a24andceca566; it passed on the Ubuntu host earlier. Not root-caused, and not made worse.just render-sw's setup, about 70 runs never showed nextest's LEAK, buta_click_reaches_the_pagetook 4 to 33 s in about a third of runs and twice hit its 20 s budget. The time goes to CEF's GPU process, not the click: this build's CEF cannot load GL (nolibGL.so.1on its path, and lavapipe offers no GL anyway), so Chromium walks its GPU fallback chain, and in the slow runs a fallback GPU process fails "Failed to create shared context for virtualization", then hangs until Chromium's GPU watchdog kills it (exit 133) 4 to 11 s later, sometimes twice, delaying the page's first paint. It is not the Vulkan ICD override (VK_ICD_FILENAMESinstead ofVK_DRIVER_FILES), not the host's implicit Vulkan layers (all disabled), and not only the SwiftShader WebGL fallback (--disable-software-rasterizerstill hangs). Every CEF process stays in its helper's process group, and none outlive a test. The fixes left are a product choice (for example--disable-gpuon the CPU path) or packaging GL for CEF, so a follow-up quest is suggested; raising the budget would only hide it.Decisions
DuplicateHandleover a non-socket channel on Windows; app-bundle helpers and a Mach-port IOSurface rendezvous on macOS).Review
Codex (
quest review), gpt-6.1-sol, medium effort. This session merged main's effects (#17), preview dragging (#15), failover (#19), guests (#10), the docs move (#26), outside edits (#24), per-source health (#25), live scene and canvas edits (#16), and instant replay (#20). Round 4 on head2cd4f9cdf8eab514d297d9d50ff40a73e6bf87c1reported no findings. As the fourth round it is the design checkpoint: the approach stands, and the maintainer picked merge, with CEF GPU startup and the NixOS crash test as follow-up quests.The merges were resolved by hand:
8c6f6ce:effect::Picturecarries whether its alpha is premultiplied: a page's input is unpremultiplied before its filters, and a luminance mask reading a page accounts for it.0d74662: the Preview row keeps Interact beside main's fade-time wording, and the preview draws through main's texture id.2cd4f9c: browser and replay sources both join the scene file, the add form, and the README. A replay copies published tracks, and a page publishes none, so a page has no past to replay: the Replay panel leaves out pages and their clones, as it does images and colors, and replaying one by name says why. The program replays them as viewers saw them.Findings and fixes:
bfb0fe6(review): input past the backlog dropped releases too, so a page could keep a button held. Fixed (fabec03): releases past the backlog are owed and sent ahead of newer input once the helper catches up.browser::tests::a_release_past_the_backlog_is_owedandbrowser::run::tests::the_writer_delivers_owed_releasescover it, and each fails with the fix reverted. Reply.fabec03), and the automated review onfabec03: input ignored an item's crop (new since feat(scene): video effects: color filters, blur, drop shadow, keys, LUTs, masks, crop, and blend modes #17). Fixed (724d438): hit tests and captured drags map throughCollection::crop, which the compositor now uses too.a69ab36): a frame that does not draw the preview lets go of the pages, as turning Interact off and losing the window do.browser/import.rsonly fillscef::AcceleratedPaintInfoand calls cef-rs'sSharedTextureHandle::import_texture, typed on CEF's own structs; moq-video would need thecefcrate for this one consumer. A generic moq-video import was rejected under Alternatives, since CEF reclaims the texture when the paint callback returns.fabec03(review): a reload that removes or replaces a focused page left the preview holding it. Fixed (a84b06c) for any edit, undo, or reload: the preview notes the page behind each name it holds and forgets one that stopped or restarted.interact::tests::a_forgotten_page_hears_nothingcovers it. Reply.e94b936): syncing sources hands each page the canvas's rate, which reaches the helper even when it is behind or not yet connected.browser::tests::a_new_frame_rate_reaches_the_pagecovers it.e94b936): no findings.a84b06c): no findings.2cd4f9c, the merge of feat(studio): instant replay and clips from the tracks' held groups #20): no findings. The automated reviews ona84b06cand2cd4f9cfound none either.Earlier sessions (up to
6377a24) fixed the blocking socket write, the studio's shortcuts taking a page's keys, a lost release on switching apps, the paste, modifier, copy and cut handling, captured drags, and popups closing the helper; round 4 there was the design checkpoint, and the approach stood.Checks on
2cd4f9c:just cipasses.cargo fmt, clippy with and without every feature, and the workspace tests with every feature (153) pass.just render-swon Linux (ona84b06c; the merge of feat(studio): instant replay and clips from the tracks' held groups #20 touches no browser or compositor code): the compositor (19), relay, and setup tests pass, and the page-drawing and click tests pass underxvfb-run. The crash test fails as described under Follow-ups, as before.🤖 Generated with Claude Code
(Written by Claude Opus 5.5)