diff --git a/components/compositing/compositor.rs b/components/compositing/compositor.rs index 13ea3a32428..12c80f29be1 100644 --- a/components/compositing/compositor.rs +++ b/components/compositing/compositor.rs @@ -221,6 +221,10 @@ pub(crate) struct PipelineDetails { /// Which parts of Servo have reported that this `Pipeline` has exited. Only when all /// have done so will it be discarded. pub exited: PipelineExitSource, + + /// The [`Epoch`] of the latest display list received for this `Pipeline` or `None` if no + /// display list has been received. + pub display_list_epoch: Option, } impl PipelineDetails { @@ -246,6 +250,7 @@ impl PipelineDetails { first_paint_metric: PaintMetricState::Waiting, first_contentful_paint_metric: PaintMetricState::Waiting, exited: PipelineExitSource::empty(), + display_list_epoch: None, } } @@ -537,9 +542,17 @@ impl IOCompositor { } }, - CompositorMsg::SendInitialTransaction(pipeline) => { + CompositorMsg::SendInitialTransaction(webview_id, pipeline_id) => { + let Some(webview_renderer) = self.webview_renderers.get_mut(webview_id) else { + return warn!("Could not find WebView for incoming display list"); + }; + + let starting_epoch = Epoch(0); + let details = webview_renderer.ensure_pipeline_details(pipeline_id.into()); + details.display_list_epoch = Some(starting_epoch); + let mut txn = Transaction::new(); - txn.set_display_list(WebRenderEpoch(0), (pipeline, Default::default())); + txn.set_display_list(starting_epoch.into(), (pipeline_id, Default::default())); self.generate_frame(&mut txn, RenderReasons::SCENE); self.global.borrow_mut().send_transaction(txn); }, @@ -653,6 +666,8 @@ impl IOCompositor { Some(display_list_info.viewport_details.hidpi_scale_factor); let epoch = display_list_info.epoch; + details.display_list_epoch = Some(Epoch(epoch.0)); + let first_reflow = display_list_info.first_reflow; if details.first_paint_metric == PaintMetricState::Waiting { details.first_paint_metric = PaintMetricState::Seen(epoch, first_reflow); diff --git a/components/layout/layout_impl.rs b/components/layout/layout_impl.rs index 77c174b4188..7b908e45534 100644 --- a/components/layout/layout_impl.rs +++ b/components/layout/layout_impl.rs @@ -175,8 +175,10 @@ pub struct LayoutThread { /// The [`StackingContextTree`] cached from previous layouts. stacking_context_tree: RefCell>, - /// A counter for epoch messages - epoch: Cell, + /// The epoch of the current display list that's been sent to [`WebRender`]. Every + /// layout sends an initial empty display list, so this always starts at `0. The + /// next display list will have the value of this epoch plus `1`. + current_epoch: Cell, // A cache that maps image resources specified in CSS (e.g as the `url()` value // for `background-image` or `content` properties) to either the final resolved @@ -223,7 +225,7 @@ impl Layout for LayoutThread { } fn current_epoch(&self) -> Epoch { - self.epoch.get() + self.current_epoch.get() } fn load_web_fonts_from_stylesheet(&self, stylesheet: ServoArc) { @@ -646,7 +648,7 @@ impl LayoutThread { // Let webrender know about this pipeline by sending an empty display list. config .compositor_api - .send_initial_transaction(config.id.into()); + .send_initial_transaction(config.webview_id, config.id.into()); let mut font = Font::initial_values(); let default_font_size = pref!(fonts_default_size); @@ -685,8 +687,7 @@ impl LayoutThread { box_tree: Default::default(), fragment_tree: Default::default(), stacking_context_tree: Default::default(), - // Epoch starts at 1 because of the initial display list for epoch 0 that we send to WR - epoch: Cell::new(Epoch(1)), + current_epoch: Cell::new(Epoch(0)), compositor_api: config.compositor_api, stylist: Stylist::new(device, QuirksMode::NoQuirks), resolved_images_cache: Default::default(), @@ -1232,10 +1233,8 @@ impl LayoutThread { return false; } - let mut epoch = self.epoch.get(); - epoch.next(); - self.epoch.set(epoch); - stacking_context_tree.compositor_info.epoch = epoch.into(); + self.current_epoch.set(self.current_epoch().next()); + stacking_context_tree.compositor_info.epoch = self.current_epoch.get().into(); let built_display_list = DisplayListBuilder::build( stacking_context_tree, diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 7e4afd5b732..80833ad5cf0 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -569,8 +569,7 @@ pub(crate) struct Document { /// uploaded to the renderer after a rendering update. Until those images are uploaded /// this `Document` will not perform any more rendering updates. #[no_trace] - current_canvas_epoch: RefCell, - + current_canvas_epoch: Cell, /// The global custom element reaction stack for this script thread. #[conditional_malloc_size_of] custom_element_reaction_stack: Rc, @@ -2742,8 +2741,9 @@ impl Document { } // All dirty canvases are flushed before updating the rendering. - self.current_canvas_epoch.borrow_mut().next(); - let canvas_epoch = *self.current_canvas_epoch.borrow(); + self.current_canvas_epoch + .set(self.current_canvas_epoch.get().next()); + let canvas_epoch = self.current_canvas_epoch.get(); let mut image_keys = Vec::new(); #[cfg(feature = "webgpu")] @@ -3499,7 +3499,7 @@ impl Document { pending_scroll_event_targets: Default::default(), resize_observer_started_observing_target: Cell::new(false), waiting_on_canvas_image_updates: Cell::new(false), - current_canvas_epoch: RefCell::new(Epoch(0)), + current_canvas_epoch: Cell::new(Epoch(0)), custom_element_reaction_stack, active_sandboxing_flag_set: Cell::new(SandboxingFlagSet::empty()), favicon: RefCell::new(None), diff --git a/components/shared/base/lib.rs b/components/shared/base/lib.rs index a340a87f77c..99d80d208a2 100644 --- a/components/shared/base/lib.rs +++ b/components/shared/base/lib.rs @@ -77,8 +77,8 @@ where pub struct Epoch(pub u32); impl Epoch { - pub fn next(&mut self) { - self.0 += 1; + pub fn next(&self) -> Self { + Self(self.0 + 1) } } diff --git a/components/shared/compositing/lib.rs b/components/shared/compositing/lib.rs index 148328d949b..f594b3a7ef3 100644 --- a/components/shared/compositing/lib.rs +++ b/components/shared/compositing/lib.rs @@ -103,7 +103,7 @@ pub enum CompositorMsg { /// The load of a page has completed LoadComplete(WebViewId), /// Inform WebRender of the existence of this pipeline. - SendInitialTransaction(WebRenderPipelineId), + SendInitialTransaction(WebViewId, WebRenderPipelineId), /// Perform a scroll operation. SendScrollNode( WebViewId, @@ -204,8 +204,11 @@ impl CrossProcessCompositorApi { } /// Inform WebRender of the existence of this pipeline. - pub fn send_initial_transaction(&self, pipeline: WebRenderPipelineId) { - if let Err(e) = self.0.send(CompositorMsg::SendInitialTransaction(pipeline)) { + pub fn send_initial_transaction(&self, webview_id: WebViewId, pipeline: WebRenderPipelineId) { + if let Err(e) = self + .0 + .send(CompositorMsg::SendInitialTransaction(webview_id, pipeline)) + { warn!("Error sending initial transaction: {}", e); } }