T10.6: drop RGBA payload from the wire when the hardware path publishes a surface
This commit is contained in:
@@ -1085,16 +1085,24 @@ fn identical_live_frames_share_render_image_arc() {
|
||||
)
|
||||
.expect("second frame builds from identical bytes");
|
||||
|
||||
let first_image = first
|
||||
.image
|
||||
.as_ref()
|
||||
.expect("software path always produces an Arc<RenderImage>");
|
||||
let second_image = second
|
||||
.image
|
||||
.as_ref()
|
||||
.expect("software path always produces an Arc<RenderImage>");
|
||||
assert!(
|
||||
Arc::ptr_eq(&first.image, &second.image),
|
||||
Arc::ptr_eq(first_image, second_image),
|
||||
"TDD red: two ServoLiveFrames with byte-identical RGBA produced \
|
||||
distinct Arc<RenderImage> instances (first={:p}, second={:p}). \
|
||||
WebSurfaceFrame::from_parts must dedup the upload against the \
|
||||
previous frame's bytes, or the rendering pipeline must switch \
|
||||
to a GPU-side source of truth (IOSurface) so per-frame host \
|
||||
allocations stop entirely.",
|
||||
Arc::as_ptr(&first.image),
|
||||
Arc::as_ptr(&second.image),
|
||||
Arc::as_ptr(first_image),
|
||||
Arc::as_ptr(second_image),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -57,12 +57,15 @@ pub(super) struct WebSurfaceFrame {
|
||||
content_pixel_count: u64,
|
||||
#[cfg(all(test, feature = "live-site-smoke"))]
|
||||
sample_hash: u64,
|
||||
pub(super) image: Arc<RenderImage>,
|
||||
/// Software-path image. `None` whenever the sidecar took the
|
||||
/// hardware shortcut and dropped the RGBA payload from the
|
||||
/// wire — the IOSurface in `pixel_buffer` is the source of truth
|
||||
/// for that frame.
|
||||
pub(super) image: Option<Arc<RenderImage>>,
|
||||
/// Hardware-path companion: when present, the view samples the
|
||||
/// IOSurface through GPUI's Metal pipeline via `gpui::surface(...)`
|
||||
/// instead of uploading the RGBA bytes again. Always `None` on
|
||||
/// the software path; the RGBA copy in `image` is the source of
|
||||
/// truth in that case.
|
||||
/// the software path; `image` is the source of truth there.
|
||||
#[cfg(target_os = "macos")]
|
||||
pub(super) pixel_buffer: Option<CVPixelBuffer>,
|
||||
}
|
||||
@@ -100,8 +103,21 @@ impl WebSurfaceFrame {
|
||||
}
|
||||
|
||||
fn from_parts(parts: WebSurfaceFrameParts) -> Result<Self, WebSurfaceError> {
|
||||
let bytes_hash = rgba_hash(&parts.rgba_bytes);
|
||||
let image = resolve_render_image(parts.width, parts.height, parts.rgba_bytes, bytes_hash)?;
|
||||
// Hardware path frames arrive with `rgba_bytes` empty — the
|
||||
// sidecar dropped the 8 MB payload from the wire and the
|
||||
// receiver samples the IOSurface directly. In that case the
|
||||
// RGBA hash + LAST_FRAME_IMAGE dedup are skipped entirely.
|
||||
let image = if parts.rgba_bytes.is_empty() {
|
||||
None
|
||||
} else {
|
||||
let bytes_hash = rgba_hash(&parts.rgba_bytes);
|
||||
Some(resolve_render_image(
|
||||
parts.width,
|
||||
parts.height,
|
||||
parts.rgba_bytes,
|
||||
bytes_hash,
|
||||
)?)
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
requested_url: parts.requested_url,
|
||||
|
||||
@@ -18,9 +18,10 @@ pub(super) fn render_ready_web_surface(
|
||||
// IOSurface and we successfully imported it into a CVPixelBuffer.
|
||||
// GPUI's `surface(...)` hands the buffer to its Blade Metal
|
||||
// renderer, which samples the IOSurface directly — no
|
||||
// RGBA→texture upload, no LAST_FRAME_IMAGE dedup needed. Falls
|
||||
// back to the software RGBA image when the buffer is missing
|
||||
// (software webview, import failure, non-macOS host).
|
||||
// RGBA→texture upload, no LAST_FRAME_IMAGE dedup needed. The
|
||||
// sidecar drops the RGBA payload from the wire whenever it
|
||||
// populates `pixel_buffer`, so `image` is `None` on this branch
|
||||
// and there's no software memcpy to fall back on.
|
||||
#[cfg(target_os = "macos")]
|
||||
if let Some(pixel_buffer) = frame.pixel_buffer.as_ref() {
|
||||
return render_web_surface(
|
||||
@@ -29,11 +30,20 @@ pub(super) fn render_ready_web_surface(
|
||||
surface(pixel_buffer.clone()).size_full().object_fit(ObjectFit::Fill),
|
||||
);
|
||||
}
|
||||
render_web_surface(
|
||||
tab,
|
||||
state_entity,
|
||||
img(ImageSource::Render(frame.image.clone())).size_full().object_fit(ObjectFit::Fill),
|
||||
)
|
||||
// Software path: the sidecar streamed the RGBA payload and the
|
||||
// receiver decoded it into an Arc<RenderImage>.
|
||||
if let Some(image) = frame.image.as_ref() {
|
||||
return render_web_surface(
|
||||
tab,
|
||||
state_entity,
|
||||
img(ImageSource::Render(image.clone())).size_full().object_fit(ObjectFit::Fill),
|
||||
);
|
||||
}
|
||||
// Both image variants empty: shouldn't happen because the sidecar
|
||||
// only drops RGBA when it has a hardware surface to publish, but
|
||||
// a blank canvas is the honest user-facing fallback if it ever
|
||||
// does.
|
||||
render_web_surface(tab, state_entity, div().size_full())
|
||||
}
|
||||
|
||||
pub(super) fn render_loading_web_surface(
|
||||
|
||||
Reference in New Issue
Block a user