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.
This commit is contained in:
@@ -136,8 +136,8 @@ fn write_outcome(
|
|||||||
let outcome = outcome.unwrap_or_else(|error| LiveOutcome::error(error.to_string()));
|
let outcome = outcome.unwrap_or_else(|error| LiveOutcome::error(error.to_string()));
|
||||||
serde_json::to_writer(&mut *stdout, &outcome.response)?;
|
serde_json::to_writer(&mut *stdout, &outcome.response)?;
|
||||||
stdout.write_all(b"\n")?;
|
stdout.write_all(b"\n")?;
|
||||||
if let Some(frame_bytes) = outcome.frame_bytes {
|
if let Some(frame) = outcome.frame.as_ref() {
|
||||||
stdout.write_all(&frame_bytes)?;
|
stdout.write_all(frame.rgba_bytes())?;
|
||||||
}
|
}
|
||||||
stdout.flush()?;
|
stdout.flush()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -271,7 +271,8 @@ fn poll_frame(
|
|||||||
let frame = host.last_rendered_frame()?;
|
let frame = host.last_rendered_frame()?;
|
||||||
let has_visible_content =
|
let has_visible_content =
|
||||||
frame.non_white_pixel_count() > 0 && frame.content_pixel_count() > 0;
|
frame.non_white_pixel_count() > 0 && frame.content_pixel_count() > 0;
|
||||||
let outcome = LiveOutcome::frame(LiveFrameReport::new(&snapshot, &frame), &frame);
|
let report = LiveFrameReport::new(&snapshot, &frame);
|
||||||
|
let outcome = LiveOutcome::from_frame(report, frame);
|
||||||
if has_visible_content {
|
if has_visible_content {
|
||||||
session.awaiting_visible_frame = false;
|
session.awaiting_visible_frame = false;
|
||||||
return Ok(outcome);
|
return Ok(outcome);
|
||||||
@@ -353,28 +354,29 @@ struct LiveSitePermission {
|
|||||||
decision: String,
|
decision: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A handle plus an optional raw-bytes payload, kept together until
|
/// A handle plus an optional rendered frame, kept together until the
|
||||||
/// the moment of writing to stdout. The JSON header advertises
|
/// moment of writing to stdout. The JSON header advertises
|
||||||
/// `rgba_byte_count`; the binary follows on the same pipe.
|
/// `rgba_byte_count`; the binary follows on the same pipe. We carry
|
||||||
|
/// the `RenderedFrame` (one host-side clone, already paid for inside
|
||||||
|
/// `host.last_rendered_frame`) instead of doing another `to_vec()`
|
||||||
|
/// over `rgba_bytes()` — `write_all(&self.rgba_bytes()[..])` writes
|
||||||
|
/// the existing slice straight to the pipe.
|
||||||
struct LiveOutcome {
|
struct LiveOutcome {
|
||||||
response: LiveResponse,
|
response: LiveResponse,
|
||||||
frame_bytes: Option<Vec<u8>>,
|
frame: Option<RenderedFrame>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LiveOutcome {
|
impl LiveOutcome {
|
||||||
fn empty() -> Self {
|
fn empty() -> Self {
|
||||||
Self { response: LiveResponse::empty(), frame_bytes: None }
|
Self { response: LiveResponse::empty(), frame: None }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn error(message: String) -> Self {
|
fn error(message: String) -> Self {
|
||||||
Self { response: LiveResponse::error(message), frame_bytes: None }
|
Self { response: LiveResponse::error(message), frame: None }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn frame(report: LiveFrameReport, frame: &RenderedFrame) -> Self {
|
fn from_frame(report: LiveFrameReport, frame: RenderedFrame) -> Self {
|
||||||
Self {
|
Self { response: LiveResponse::frame(report), frame: Some(frame) }
|
||||||
response: LiveResponse::frame(report),
|
|
||||||
frame_bytes: Some(frame.rgba_bytes().to_vec()),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user