Commit Graph
36 Commits
Author SHA1 Message Date
ZacharyZhang-NY 90c029eddb Move Servo IPC off UI thread
Root cause of the post-tab lag: the GPUI 16 ms timer was calling
`WebSurfaceRuntime::ensure_tab` and `tick` on the UI thread, and each
call did a synchronous `serde_json` write plus `read_line` against the
Servo sidecar over stdin/stdout. With even one visible tab, every
frame stalled on cross-process IPC.

Introduce `web_surface_worker.rs` — a per-profile worker thread that
owns the `ServoLiveClient`, drains a coalescing request queue
(latest Ensure/Poll per tab wins, no unbounded growth), and ships
results back through a `std::sync::mpsc` channel. `WebSurfaceRuntime`
now submits work non-blockingly and drains responses in `tick`; the
UI thread never blocks on the sidecar.

Adjacent in-flight cleanup riding along: hardware IOSurface
rendering-context completion (sidecar `live_protocol`,
`hardware_rendering_context`, GPUI BGRA surface shader), CSS viewport
size + device pixel ratio plumbing into `ServoLiveFrame`, and the
Send opt-ins for `CVPixelBuffer`-bearing types so frames can cross
the thread boundary.
2026-05-15 16:41:40 -04:00
ZacharyZhang-NY f4c650c4d8 Fix Servo IOSurface orientation and resize identity 2026-05-13 10:21:50 -04:00
ZacharyZhang-NY a743435ea1 Transfer Servo IOSurface ports over Mach 2026-05-13 04:05:07 -04:00
ZacharyZhang-NY ac84a80d9e Close Servo live sessions for removed tabs 2026-05-13 02:41:54 -04:00
ZacharyZhang-NY 74731d4faa Keep loading until live content arrives 2026-05-13 02:18:48 -04:00
ZacharyZhang-NY 6ce5df83a8 Skip hardware live readback 2026-05-13 01:41:58 -04:00
ZacharyZhang-NY 8cd5e969dc Guard hardware surface selectors 2026-05-13 00:43:13 -04:00
ZacharyZhang-NY 8308eae6d2 Split sidecar args tests 2026-05-13 00:34:03 -04:00
ZacharyZhang-NY 316bf6f9a4 Split Servo live rendering modules 2026-05-12 23:38:13 -04:00
ZacharyZhang-NY 0db1caad69 Route web surface scrolls to Servo hit point 2026-05-12 23:29:40 -04:00
ZacharyZhang-NY b70fa71a9f T13: push display scale factor into Servo's hidpi so Retina pages lay out at logical CSS dimensions 2026-05-11 00:46:32 -04:00
ZacharyZhang-NY 60a3b9b050 T12: disarm visible-content gate on software path after first real frame 2026-05-11 00:35:11 -04:00
ZacharyZhang-NY d570b84c9c T10.7: bypass visible-content gate on hardware path (196ms → 6ms per frame) 2026-05-11 00:05:04 -04:00
ZacharyZhang-NY 6e2bd20a9b T10.6: drop RGBA payload from the wire when the hardware path publishes a surface 2026-05-10 23:52:12 -04:00
ZacharyZhang-NY 07b9c9da01 T10.3: publish IOSurfaceHandle once per surface, current_surface_id per frame 2026-05-10 23:17:05 -04:00
ZacharyZhang-NY 320da3ddb5 Make frame_perf total a real end-to-end timing and right-size buckets 2026-05-10 22:38:12 -04:00
ZacharyZhang-NY f7027e6ea5 Profile frame stages via sidecar histogram → ely::servo::perf 2026-05-10 22:30:57 -04:00
ZacharyZhang-NY 18fd20b577 Plumb the rendering context kind from ely_app env var to the sidecar
T10.1: with the vendored `HardwareOffscreenContext` (048c5df) and the
host-level kind dispatch (a7d3e89) in place, the sidecar binary
still ignored the rendering context kind — every spawn was wired to
the software path regardless of how the host process was built. This
commit threads the choice end-to-end:

  * `ely_servo_sidecar` learns a `--rendering-context [software|
    hardware]` flag on its `live` subcommand. `LiveArgs` carries
    the parsed `RenderingContextKind` (defaulting to `Software` so
    existing invocations stay bit-identical) and `live.rs::run_live`
    routes it through to `SoftwareServoHost::new_with_config_dir_and_kind`.
    Unknown values produce a typed
    `SidecarArgsError::InvalidRenderingContext`; a missing value
    after the flag produces the existing `MissingArgumentValue`.

  * `ely_app` reads `ELY_SERVO_RENDERING_CONTEXT` (with values
    `software` / `hardware`, case-insensitive) and, if set, appends
    `--rendering-context VALUE` to the sidecar command line.
    Unset or unrecognised values fall through to the sidecar's own
    software default — a stale env var or a typo never breaks the
    browser startup. The sidecar arg parser is the source of truth
    for legality of explicit values; the env helper only gates
    which values reach it.

  * Five new unit tests in `args::tests` pin the new parse paths:
    default-is-software, explicit-software, explicit-hardware,
    bogus-value-rejected, missing-value-rejected. Run via
    `cargo test -p ely_servo_host --features servo-engine --bin
    ely_servo_sidecar` and now hit alongside the five existing
    snapshot tests for 10 passes.

End-to-end perf expectation: with the sidecar binary built using
`--features servo-engine,hardware-render` and the env var set to
`hardware`, every spawned sidecar webview rasterises through the
real GPU adapter (via the vendored
`HardwareOffscreenContext`/surfman/CGL chain on macOS). The host
still reads back RGBA into a `Vec<u8>` for the existing pipe
protocol; the IOSurface zero-copy bridge that deletes that
read-back is T10.2–T10.5 in docs/t10-iosurface-plan.md and lands
in subsequent commits.

cargo test --bin ely_app: 120 passed, 0 failed, 2 ignored.
cargo test -p ely_servo_host --features servo-engine --bin ely_servo_sidecar: 10 passed.
cargo test -p ely_servo_host --features servo-engine --test sidecar: 9 passed.
cargo test -p ely_servo_host --features servo-engine,hardware-render --test hardware_rendering_context: 1 passed.
2026-05-10 21:27:12 -04:00
ZacharyZhang-NY e02c0fd502 Drop the per-frame to_vec() clone in the sidecar pixel writer
`LiveOutcome::frame` was carrying the rendered bytes as a fresh
`Vec<u8>` cloned out of `RenderedFrame::rgba_bytes()`. At 60 fps
on a 1080p canvas that was an extra 8 MB allocation + memcpy per
frame on top of the clone `host.last_rendered_frame()` already
paid for. `LiveOutcome` now carries the owned `RenderedFrame`
directly, and `write_outcome` writes its `rgba_bytes()` slice
straight to stdout — same single-clone cost as the host already
incurred, no second allocation.

Small Karpathy-style follow-up from the T8 review ("the host
still copies its rendered buffer to a transient Vec<u8> before
write_all; expose &[u8] straight to write_all once the profile
shows that allocation in the top five"). Profile data is still
deferred (T9 was marked vibe-benchmarking until T10 lands a real
spec), but removing the cheap clone is structurally cleaner and
makes the dispatch path one allocation lighter regardless.

cargo test --bin ely_app: 118 passed, 0 failed, 1 ignored.
cargo test -p ely_servo_host --features servo-engine --test sidecar: 9 passed.
2026-05-10 19:54:14 -04:00
ZacharyZhang-NY a80d0393e9 Drop the file system from the live frame pixel pipe
Every live frame was round-tripping through the local file system:
the sidecar called `fs::write(rgba_out, frame.rgba_bytes())` in
`poll_frame`, the JSON response carried `rgba_path`, and the main
process turned around and called `fs::read(rgba_path)` to lift the
bytes back into a `Vec<u8>`. At 1080p that is 8 MB of syscall +
memcpy + page cache traffic per frame; at 60 fps it dwarfs every
other cost in the pipeline and shows up as scroll/zoom jank the user
can feel before any other bottleneck.

Replace it with a same-pipe binary protocol. The sidecar writes the
JSON `LiveResponse` line as before, then writes the raw RGBA frame
bytes on the same stdout immediately after the trailing `\n`. The
client `read_line`s the JSON, parses `rgba_byte_count` from the
header, and `read_exact`s exactly that many bytes from the same
`BufReader<ChildStdout>` (the buffered reader drains its own buffer
before pulling from the child). No tmpfs directory, no
`fs::remove_dir_all` on drop, no `rgba_path` field, no per-frame
filename plumbing.

Boundary defence on the client side: the header's `rgba_byte_count`
is cross-checked against `width * height * 4` before any allocation
or `read_exact`. A buggy or compromised sidecar can no longer ask
the GPUI process to allocate an arbitrarily large buffer or park on
`read_exact` for a payload that will never arrive.

The sidecar process boundary stays exactly where it was; only the
pixel transport between the two processes changes. The `one-shot`
sidecar binary path (used by `tests/sidecar.rs` and PRD smoke tests)
still writes to its CLI-supplied `--rgba-out` path — those tests
were untouched and continue to pass 9/9.

cargo test --bin ely_app: 112 passed.
cargo test -p ely_servo_host --features servo-engine --test sidecar: 9 passed.

Follow-ups deferred to the profile step (T9):
  * the host still copies its rendered buffer to a transient
    `Vec<u8>` via `frame.rgba_bytes().to_vec()` before write_all;
    expose `&[u8]` straight to `write_all` once the profile shows
    that allocation in the top five.
  * `poll_frame` calls `snapshot` twice per iteration; harmless
    under the software renderer but worth folding into a single
    snapshot once we have numbers.
  * raw memcpy bandwidth is still ~480 MB/s at 60 fps 1080p; the
    GPU-side fix (T10: OffscreenRenderingContext + IOSurface
    zero-copy) is the next material change.
2026-05-10 19:04:34 -04:00
ZacharyZhang-NY eb58ce75da Plug three holes in Servo input forwarding
1. Scroll no longer wipes keyboard focus. Servo holds DOM focus across
   wheel events; the shell was clearing keyboard_focus and typed_texts
   on every scroll, so a focused input went deaf the moment the user
   scrolled. Scroll still drops the buffered click point because that
   coordinate is captured against the pre-scroll viewport.

2. Mouse-down hands focus to the shell's root focus handle (in
   addition to mouse-up's existing click forwarding). The user can now
   start typing the moment they press the page, instead of having to
   first complete a click round-trip to escape the omnibar's focus.

3. Sidecar hover() honors the requesting webview_id instead of
   defaulting to the first webview in the map, so multi-tab sidecars
   no longer pipe every hover into tab #1.
2026-05-10 00:51:37 -04:00
ZacharyZhang-NY 4d82023a68 Servo sidecar: extend post-input frame wait to 250 ms
The live-mode `poll_frame` budgeted 60 ms for Servo to paint after
each `Ensure` request. That value was set when the only thing being
applied was navigation, where the GPUI tick timer (16 ms cadence) would
backfill missed frames quickly. Once we started forwarding clicks and
typing through the same `Ensure`, 60 ms was tighter than the
software renderer needs to handle MouseDown + MouseUp + layout +
paint on a real page like google.com — so the response carried the
pre-click frame and the user saw no visible reaction.

Bump the budget to 250 ms. That covers the click → focus-ring paint
cycle on the software backend without making nav slower (`apply_layout`
exits early on stable size, so unchanged ensures still return on the
first poll).
2026-05-10 00:21:33 -04:00
ZacharyZhang-NY 3caf207129 update 2026-05-09 16:27:40 -04:00
ZacharyZhang-NY 4c6d9c757a Add mouse hover tracking across the Servo input pipeline
Without continuous MouseMove events, Servo never updates hover state:
no cursor changes over links, no :hover CSS effects, no mouseenter
JavaScript events. The web page appears completely non-interactive.

Track mouse position from GPUI on_mouse_move through the full IPC
pipeline to Servo. Hover position is included with each ensure
request so Servo updates hover state at frame rate (~60fps).
2026-05-09 16:21:43 -04:00
ZacharyZhang-NY 1faa7423c1 Add Servo page zoom support 2026-05-09 12:32:44 -04:00
ZacharyZhang-NY 79d9646ab8 Pass site permission grants to sidecar snapshots 2026-05-09 00:01:14 -04:00
ZacharyZhang-NY 8334fcbd6e Wire sidecar profile data isolation 2026-05-08 22:10:10 -04:00
ZacharyZhang-NY a5907efeb0 Verify PRD sites through app sidecar 2026-05-08 19:43:54 -04:00
ZacharyZhang-NY 74c1e9ad4b Add PRD reference site smoke coverage 2026-05-08 15:48:09 -04:00
ZacharyZhang-NY 0ea43e8b81 Bridge Servo mouse drag input 2026-05-08 15:15:38 -04:00
ZacharyZhang-NY 7a09967d19 Bridge Servo touch tap input 2026-05-08 15:00:06 -04:00
ZacharyZhang-NY 292824dc10 Bridge Servo keyboard text input 2026-05-08 14:36:48 -04:00
ZacharyZhang-NY b786073826 Bridge Servo click input 2026-05-08 14:23:12 -04:00
ZacharyZhang-NY 7178174e20 Add Servo scroll snapshots 2026-05-08 13:54:56 -04:00
ZacharyZhang-NY 8e12d6690b Render PRD sites in real viewport 2026-05-08 13:20:43 -04:00
ZacharyZhang-NY fcdc2de076 Add Servo sidecar snapshot command 2026-05-08 12:17:41 -04:00