mirror of
https://github.com/servo/servo.git
synced 2025-09-30 16:49:16 +01:00
layout: Ensure that the Epoch
stored in layout is accurate (#39568)
The first epoch is 0 as that is the one used in the initial transaction, but the code was setting the first `Epoch` to `Epoch(1)`. This means that when layout advanced the epoch, the `Epoch` of the first produced display list was `Epoch(2)`. This change makes the value reflected in `current_epoch` actually match the index of the display list produced. In addition, we always store this epoch in `PipelineDetails` in the renderer. This will be important when adding the `WebView::take_screenshot` API. Testing: This should not change behavior, so is covered by existing tests which rely on proper `Epoch` advancement. Signed-off-by: Martin Robinson <mrobinson@igalia.com>
This commit is contained in:
parent
91e4188a64
commit
6a2a9a6e33
5 changed files with 39 additions and 22 deletions
|
@ -221,6 +221,10 @@ pub(crate) struct PipelineDetails {
|
||||||
/// Which parts of Servo have reported that this `Pipeline` has exited. Only when all
|
/// Which parts of Servo have reported that this `Pipeline` has exited. Only when all
|
||||||
/// have done so will it be discarded.
|
/// have done so will it be discarded.
|
||||||
pub exited: PipelineExitSource,
|
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<Epoch>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PipelineDetails {
|
impl PipelineDetails {
|
||||||
|
@ -246,6 +250,7 @@ impl PipelineDetails {
|
||||||
first_paint_metric: PaintMetricState::Waiting,
|
first_paint_metric: PaintMetricState::Waiting,
|
||||||
first_contentful_paint_metric: PaintMetricState::Waiting,
|
first_contentful_paint_metric: PaintMetricState::Waiting,
|
||||||
exited: PipelineExitSource::empty(),
|
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();
|
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.generate_frame(&mut txn, RenderReasons::SCENE);
|
||||||
self.global.borrow_mut().send_transaction(txn);
|
self.global.borrow_mut().send_transaction(txn);
|
||||||
},
|
},
|
||||||
|
@ -653,6 +666,8 @@ impl IOCompositor {
|
||||||
Some(display_list_info.viewport_details.hidpi_scale_factor);
|
Some(display_list_info.viewport_details.hidpi_scale_factor);
|
||||||
|
|
||||||
let epoch = display_list_info.epoch;
|
let epoch = display_list_info.epoch;
|
||||||
|
details.display_list_epoch = Some(Epoch(epoch.0));
|
||||||
|
|
||||||
let first_reflow = display_list_info.first_reflow;
|
let first_reflow = display_list_info.first_reflow;
|
||||||
if details.first_paint_metric == PaintMetricState::Waiting {
|
if details.first_paint_metric == PaintMetricState::Waiting {
|
||||||
details.first_paint_metric = PaintMetricState::Seen(epoch, first_reflow);
|
details.first_paint_metric = PaintMetricState::Seen(epoch, first_reflow);
|
||||||
|
|
|
@ -175,8 +175,10 @@ pub struct LayoutThread {
|
||||||
/// The [`StackingContextTree`] cached from previous layouts.
|
/// The [`StackingContextTree`] cached from previous layouts.
|
||||||
stacking_context_tree: RefCell<Option<StackingContextTree>>,
|
stacking_context_tree: RefCell<Option<StackingContextTree>>,
|
||||||
|
|
||||||
/// A counter for epoch messages
|
/// The epoch of the current display list that's been sent to [`WebRender`]. Every
|
||||||
epoch: Cell<Epoch>,
|
/// 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<Epoch>,
|
||||||
|
|
||||||
// A cache that maps image resources specified in CSS (e.g as the `url()` value
|
// 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
|
// for `background-image` or `content` properties) to either the final resolved
|
||||||
|
@ -223,7 +225,7 @@ impl Layout for LayoutThread {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn current_epoch(&self) -> Epoch {
|
fn current_epoch(&self) -> Epoch {
|
||||||
self.epoch.get()
|
self.current_epoch.get()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_web_fonts_from_stylesheet(&self, stylesheet: ServoArc<Stylesheet>) {
|
fn load_web_fonts_from_stylesheet(&self, stylesheet: ServoArc<Stylesheet>) {
|
||||||
|
@ -646,7 +648,7 @@ impl LayoutThread {
|
||||||
// Let webrender know about this pipeline by sending an empty display list.
|
// Let webrender know about this pipeline by sending an empty display list.
|
||||||
config
|
config
|
||||||
.compositor_api
|
.compositor_api
|
||||||
.send_initial_transaction(config.id.into());
|
.send_initial_transaction(config.webview_id, config.id.into());
|
||||||
|
|
||||||
let mut font = Font::initial_values();
|
let mut font = Font::initial_values();
|
||||||
let default_font_size = pref!(fonts_default_size);
|
let default_font_size = pref!(fonts_default_size);
|
||||||
|
@ -685,8 +687,7 @@ impl LayoutThread {
|
||||||
box_tree: Default::default(),
|
box_tree: Default::default(),
|
||||||
fragment_tree: Default::default(),
|
fragment_tree: Default::default(),
|
||||||
stacking_context_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
|
current_epoch: Cell::new(Epoch(0)),
|
||||||
epoch: Cell::new(Epoch(1)),
|
|
||||||
compositor_api: config.compositor_api,
|
compositor_api: config.compositor_api,
|
||||||
stylist: Stylist::new(device, QuirksMode::NoQuirks),
|
stylist: Stylist::new(device, QuirksMode::NoQuirks),
|
||||||
resolved_images_cache: Default::default(),
|
resolved_images_cache: Default::default(),
|
||||||
|
@ -1232,10 +1233,8 @@ impl LayoutThread {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut epoch = self.epoch.get();
|
self.current_epoch.set(self.current_epoch().next());
|
||||||
epoch.next();
|
stacking_context_tree.compositor_info.epoch = self.current_epoch.get().into();
|
||||||
self.epoch.set(epoch);
|
|
||||||
stacking_context_tree.compositor_info.epoch = epoch.into();
|
|
||||||
|
|
||||||
let built_display_list = DisplayListBuilder::build(
|
let built_display_list = DisplayListBuilder::build(
|
||||||
stacking_context_tree,
|
stacking_context_tree,
|
||||||
|
|
|
@ -569,8 +569,7 @@ pub(crate) struct Document {
|
||||||
/// uploaded to the renderer after a rendering update. Until those images are uploaded
|
/// uploaded to the renderer after a rendering update. Until those images are uploaded
|
||||||
/// this `Document` will not perform any more rendering updates.
|
/// this `Document` will not perform any more rendering updates.
|
||||||
#[no_trace]
|
#[no_trace]
|
||||||
current_canvas_epoch: RefCell<Epoch>,
|
current_canvas_epoch: Cell<Epoch>,
|
||||||
|
|
||||||
/// The global custom element reaction stack for this script thread.
|
/// The global custom element reaction stack for this script thread.
|
||||||
#[conditional_malloc_size_of]
|
#[conditional_malloc_size_of]
|
||||||
custom_element_reaction_stack: Rc<CustomElementReactionStack>,
|
custom_element_reaction_stack: Rc<CustomElementReactionStack>,
|
||||||
|
@ -2742,8 +2741,9 @@ impl Document {
|
||||||
}
|
}
|
||||||
|
|
||||||
// All dirty canvases are flushed before updating the rendering.
|
// All dirty canvases are flushed before updating the rendering.
|
||||||
self.current_canvas_epoch.borrow_mut().next();
|
self.current_canvas_epoch
|
||||||
let canvas_epoch = *self.current_canvas_epoch.borrow();
|
.set(self.current_canvas_epoch.get().next());
|
||||||
|
let canvas_epoch = self.current_canvas_epoch.get();
|
||||||
let mut image_keys = Vec::new();
|
let mut image_keys = Vec::new();
|
||||||
|
|
||||||
#[cfg(feature = "webgpu")]
|
#[cfg(feature = "webgpu")]
|
||||||
|
@ -3499,7 +3499,7 @@ impl Document {
|
||||||
pending_scroll_event_targets: Default::default(),
|
pending_scroll_event_targets: Default::default(),
|
||||||
resize_observer_started_observing_target: Cell::new(false),
|
resize_observer_started_observing_target: Cell::new(false),
|
||||||
waiting_on_canvas_image_updates: 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,
|
custom_element_reaction_stack,
|
||||||
active_sandboxing_flag_set: Cell::new(SandboxingFlagSet::empty()),
|
active_sandboxing_flag_set: Cell::new(SandboxingFlagSet::empty()),
|
||||||
favicon: RefCell::new(None),
|
favicon: RefCell::new(None),
|
||||||
|
|
|
@ -77,8 +77,8 @@ where
|
||||||
pub struct Epoch(pub u32);
|
pub struct Epoch(pub u32);
|
||||||
|
|
||||||
impl Epoch {
|
impl Epoch {
|
||||||
pub fn next(&mut self) {
|
pub fn next(&self) -> Self {
|
||||||
self.0 += 1;
|
Self(self.0 + 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -103,7 +103,7 @@ pub enum CompositorMsg {
|
||||||
/// The load of a page has completed
|
/// The load of a page has completed
|
||||||
LoadComplete(WebViewId),
|
LoadComplete(WebViewId),
|
||||||
/// Inform WebRender of the existence of this pipeline.
|
/// Inform WebRender of the existence of this pipeline.
|
||||||
SendInitialTransaction(WebRenderPipelineId),
|
SendInitialTransaction(WebViewId, WebRenderPipelineId),
|
||||||
/// Perform a scroll operation.
|
/// Perform a scroll operation.
|
||||||
SendScrollNode(
|
SendScrollNode(
|
||||||
WebViewId,
|
WebViewId,
|
||||||
|
@ -204,8 +204,11 @@ impl CrossProcessCompositorApi {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Inform WebRender of the existence of this pipeline.
|
/// Inform WebRender of the existence of this pipeline.
|
||||||
pub fn send_initial_transaction(&self, pipeline: WebRenderPipelineId) {
|
pub fn send_initial_transaction(&self, webview_id: WebViewId, pipeline: WebRenderPipelineId) {
|
||||||
if let Err(e) = self.0.send(CompositorMsg::SendInitialTransaction(pipeline)) {
|
if let Err(e) = self
|
||||||
|
.0
|
||||||
|
.send(CompositorMsg::SendInitialTransaction(webview_id, pipeline))
|
||||||
|
{
|
||||||
warn!("Error sending initial transaction: {}", e);
|
warn!("Error sending initial transaction: {}", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue