From 5f0866379a731628c535593d0022b91cfabfb868 Mon Sep 17 00:00:00 2001 From: Martin Robinson Date: Mon, 27 May 2024 09:30:51 +0200 Subject: [PATCH] Remove more IPC messages between script and layout (#32377) Instead of bouncing messages from the compositor to script and then to layout, just have script call methods on Layout. Additionally, we do not need to send any followup messages to script for these messages. Instead just execute code after calling the method on Layout. --- components/compositing/compositor.rs | 23 +++---- components/layout_thread/lib.rs | 57 ++++------------ components/layout_thread_2020/lib.rs | 56 ++++----------- components/script/script_thread.rs | 94 +++++++++++++------------- components/shared/script/lib.rs | 25 ++----- components/shared/script_layout/lib.rs | 13 ++-- 6 files changed, 103 insertions(+), 165 deletions(-) diff --git a/components/compositing/compositor.rs b/components/compositing/compositor.rs index 826c48dc836..aa118066d49 100644 --- a/components/compositing/compositor.rs +++ b/components/compositing/compositor.rs @@ -30,9 +30,8 @@ use pixels::{CorsStatus, Image, PixelFormat}; use profile_traits::time::{self as profile_time, profile, ProfilerCategory}; use script_traits::CompositorEvent::{MouseButtonEvent, MouseMoveEvent, TouchEvent, WheelEvent}; use script_traits::{ - AnimationState, AnimationTickType, ConstellationControlMsg, LayoutControlMsg, MouseButton, - MouseEventType, ScrollState, TouchEventType, TouchId, WheelDelta, WindowSizeData, - WindowSizeType, + AnimationState, AnimationTickType, ConstellationControlMsg, MouseButton, MouseEventType, + ScrollState, TouchEventType, TouchId, WheelDelta, WindowSizeData, WindowSizeType, }; use servo_geometry::{DeviceIndependentPixel, FramebufferUintLength}; use style_traits::{CSSPixel, DevicePixel, PinchZoomFactor}; @@ -1940,10 +1939,7 @@ impl IOCompositor { }); if let Some(pipeline) = details.pipeline.as_ref() { - let message = ConstellationControlMsg::ForLayoutFromConstellation( - LayoutControlMsg::SetScrollStates(scroll_states), - *pipeline_id, - ); + let message = ConstellationControlMsg::SetScrollStates(*pipeline_id, scroll_states); let _ = pipeline.script_chan.send(message); } } @@ -2154,11 +2150,14 @@ impl IOCompositor { to_remove.push(*id); if let Some(pipeline) = self.pipeline(*id) { // and inform layout with the measured paint time. - let message = LayoutControlMsg::PaintMetric(epoch, paint_time); - let message = - ConstellationControlMsg::ForLayoutFromConstellation(message, *id); - if let Err(e) = pipeline.script_chan.send(message) { - warn!("Sending PaintMetric message to layout failed ({:?}).", e); + if let Err(e) = + pipeline + .script_chan + .send(ConstellationControlMsg::SetEpochPaintTime( + *id, epoch, paint_time, + )) + { + warn!("Sending RequestLayoutPaintMetric message to layout failed ({e:?})."); } } } diff --git a/components/layout_thread/lib.rs b/components/layout_thread/lib.rs index 0192f58a4f4..705e8f5ee50 100644 --- a/components/layout_thread/lib.rs +++ b/components/layout_thread/lib.rs @@ -10,7 +10,6 @@ use std::borrow::ToOwned; use std::cell::{Cell, RefCell}; -use std::collections::HashMap; use std::ops::{Deref, DerefMut}; use std::process; use std::sync::{Arc, Mutex}; @@ -63,13 +62,12 @@ use profile_traits::time::{ use script::layout_dom::{ServoLayoutDocument, ServoLayoutElement, ServoLayoutNode}; use script_layout_interface::wrapper_traits::LayoutNode; use script_layout_interface::{ - node_id_from_scroll_id, Layout, LayoutConfig, LayoutFactory, NodesFromPointQueryType, - OffsetParentResponse, Reflow, ReflowComplete, ReflowGoal, ScriptReflow, TrustedNodeAddress, + Layout, LayoutConfig, LayoutFactory, NodesFromPointQueryType, OffsetParentResponse, Reflow, + ReflowComplete, ReflowGoal, ScriptReflow, TrustedNodeAddress, }; use script_traits::{ - ConstellationControlMsg, DrawAPaintImageResult, IFrameSizeMsg, LayoutControlMsg, - LayoutMsg as ConstellationMsg, PaintWorkletError, Painter, ScrollState, UntrustedNodeAddress, - WindowSizeData, WindowSizeType, + ConstellationControlMsg, DrawAPaintImageResult, IFrameSizeMsg, LayoutMsg as ConstellationMsg, + PaintWorkletError, Painter, ScrollState, UntrustedNodeAddress, WindowSizeData, WindowSizeType, }; use servo_arc::Arc as ServoArc; use servo_atoms::Atom; @@ -245,20 +243,6 @@ impl Drop for ScriptReflowResult { } impl Layout for LayoutThread { - fn handle_constellation_message( - &mut self, - constellation_message: script_traits::LayoutControlMsg, - ) { - match constellation_message { - LayoutControlMsg::SetScrollStates(new_scroll_states) => { - self.set_scroll_states(new_scroll_states); - }, - LayoutControlMsg::PaintMetric(epoch, paint_time) => { - self.paint_time_metrics.maybe_set_metric(epoch, paint_time); - }, - } - } - fn device(&self) -> &Device { self.stylist.device() } @@ -550,6 +534,17 @@ impl Layout for LayoutThread { || self.handle_reflow(&mut result), ); } + + fn set_scroll_states(&mut self, scroll_states: &[ScrollState]) { + *self.scroll_offsets.borrow_mut() = scroll_states + .iter() + .map(|scroll_state| (scroll_state.scroll_id, scroll_state.scroll_offset)) + .collect(); + } + + fn set_epoch_paint_time(&mut self, epoch: Epoch, paint_time: u64) { + self.paint_time_metrics.maybe_set_metric(epoch, paint_time); + } } impl LayoutThread { fn root_flow_for_query(&self) -> Option { @@ -1181,28 +1176,6 @@ impl LayoutThread { ); } - fn set_scroll_states(&mut self, new_scroll_states: Vec) { - let mut script_scroll_states = vec![]; - let mut layout_scroll_states = HashMap::new(); - for new_state in &new_scroll_states { - let offset = new_state.scroll_offset; - layout_scroll_states.insert(new_state.scroll_id, offset); - - if new_state.scroll_id.is_root() { - script_scroll_states.push((UntrustedNodeAddress::from_id(0), offset)) - } else if let Some(node_id) = node_id_from_scroll_id(new_state.scroll_id.0 as usize) { - script_scroll_states.push((UntrustedNodeAddress::from_id(node_id), offset)) - } - } - let _ = self - .script_chan - .send(ConstellationControlMsg::SetScrollState( - self.id, - script_scroll_states, - )); - *self.scroll_offsets.borrow_mut() = layout_scroll_states - } - /// Cancel animations for any nodes which have been removed from flow tree. /// TODO(mrobinson): We should look into a way of doing this during flow tree construction. /// This also doesn't yet handles nodes that have been reparented. diff --git a/components/layout_thread_2020/lib.rs b/components/layout_thread_2020/lib.rs index 63af1c98349..4d518d78d77 100644 --- a/components/layout_thread_2020/lib.rs +++ b/components/layout_thread_2020/lib.rs @@ -50,13 +50,12 @@ use profile_traits::time::{ }; use script::layout_dom::{ServoLayoutDocument, ServoLayoutElement, ServoLayoutNode}; use script_layout_interface::{ - node_id_from_scroll_id, Layout, LayoutConfig, LayoutFactory, NodesFromPointQueryType, - OffsetParentResponse, ReflowComplete, ReflowGoal, ScriptReflow, TrustedNodeAddress, + Layout, LayoutConfig, LayoutFactory, NodesFromPointQueryType, OffsetParentResponse, + ReflowComplete, ReflowGoal, ScriptReflow, TrustedNodeAddress, }; use script_traits::{ - ConstellationControlMsg, DrawAPaintImageResult, IFrameSizeMsg, LayoutControlMsg, - LayoutMsg as ConstellationMsg, PaintWorkletError, Painter, ScrollState, UntrustedNodeAddress, - WindowSizeData, WindowSizeType, + ConstellationControlMsg, DrawAPaintImageResult, IFrameSizeMsg, LayoutMsg as ConstellationMsg, + PaintWorkletError, Painter, ScrollState, UntrustedNodeAddress, WindowSizeData, WindowSizeType, }; use servo_arc::Arc as ServoArc; use servo_atoms::Atom; @@ -221,20 +220,6 @@ impl Drop for ScriptReflowResult { } impl Layout for LayoutThread { - fn handle_constellation_message( - &mut self, - constellation_message: script_traits::LayoutControlMsg, - ) { - match constellation_message { - LayoutControlMsg::SetScrollStates(new_scroll_states) => { - self.set_scroll_states(new_scroll_states); - }, - LayoutControlMsg::PaintMetric(epoch, paint_time) => { - self.paint_time_metrics.maybe_set_metric(epoch, paint_time); - }, - } - } - fn device(&self) -> &Device { self.stylist.device() } @@ -469,6 +454,17 @@ impl Layout for LayoutThread { _painter: Box, ) { } + + fn set_scroll_states(&mut self, scroll_states: &[ScrollState]) { + *self.scroll_offsets.borrow_mut() = scroll_states + .iter() + .map(|scroll_state| (scroll_state.scroll_id, scroll_state.scroll_offset)) + .collect(); + } + + fn set_epoch_paint_time(&mut self, epoch: Epoch, paint_time: u64) { + self.paint_time_metrics.maybe_set_metric(epoch, paint_time); + } } impl LayoutThread { @@ -831,28 +827,6 @@ impl LayoutThread { ); } - fn set_scroll_states(&mut self, new_scroll_states: Vec) { - let mut script_scroll_states = vec![]; - let mut layout_scroll_states = HashMap::new(); - for new_state in &new_scroll_states { - let offset = new_state.scroll_offset; - layout_scroll_states.insert(new_state.scroll_id, offset); - - if new_state.scroll_id.is_root() { - script_scroll_states.push((UntrustedNodeAddress::from_id(0), offset)) - } else if let Some(node_id) = node_id_from_scroll_id(new_state.scroll_id.0 as usize) { - script_scroll_states.push((UntrustedNodeAddress::from_id(node_id), offset)) - } - } - let _ = self - .script_chan - .send(ConstellationControlMsg::SetScrollState( - self.id, - script_scroll_states, - )); - self.scroll_offsets = RefCell::new(layout_scroll_states); - } - fn perform_post_style_recalc_layout_passes( &self, fragment_tree: Arc, diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs index 25fc32fcdb7..f3b13f8deb8 100644 --- a/components/script/script_thread.rs +++ b/components/script/script_thread.rs @@ -26,8 +26,8 @@ use std::rc::Rc; use std::result::Result; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; +use std::thread; use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH}; -use std::{ptr, thread}; use background_hang_monitor_api::{ BackgroundHangMonitor, BackgroundHangMonitorExitSignal, HangAnnotation, MonitoredComponentId, @@ -36,6 +36,7 @@ use background_hang_monitor_api::{ use base::id::{ BrowsingContextId, HistoryStateId, PipelineId, PipelineNamespace, TopLevelBrowsingContextId, }; +use base::Epoch; use bluetooth_traits::BluetoothRequest; use canvas_traits::webgl::WebGLPipeline; use chrono::{DateTime, Local}; @@ -46,7 +47,6 @@ use devtools_traits::{ }; use embedder_traits::EmbedderMsg; use euclid::default::{Point2D, Rect}; -use euclid::Vector2D; use gfx::font_cache_thread::FontCacheThread; use headers::{HeaderMapExt, LastModified, ReferrerPolicy as ReferrerPolicyHeader}; use html5ever::{local_name, namespace_url, ns}; @@ -73,13 +73,15 @@ use parking_lot::Mutex; use percent_encoding::percent_decode; use profile_traits::mem::{self as profile_mem, OpaqueSender, ReportsChan}; use profile_traits::time::{self as profile_time, profile, ProfilerCategory}; -use script_layout_interface::{LayoutConfig, LayoutFactory, ReflowGoal, ScriptThreadFactory}; +use script_layout_interface::{ + node_id_from_scroll_id, LayoutConfig, LayoutFactory, ReflowGoal, ScriptThreadFactory, +}; use script_traits::webdriver_msg::WebDriverScriptCommand; use script_traits::{ CompositorEvent, ConstellationControlMsg, DiscardBrowsingContext, DocumentActivity, - EventResult, HistoryEntryReplacement, InitialScriptState, JsEvalResult, LayoutControlMsg, - LayoutMsg, LoadData, LoadOrigin, MediaSessionActionType, MouseButton, MouseEventType, - NewLayoutInfo, Painter, ProgressiveWebMetricType, ScriptMsg, ScriptToConstellationChan, + EventResult, HistoryEntryReplacement, InitialScriptState, JsEvalResult, LayoutMsg, LoadData, + LoadOrigin, MediaSessionActionType, MouseButton, MouseEventType, NewLayoutInfo, Painter, + ProgressiveWebMetricType, ScriptMsg, ScriptToConstellationChan, ScrollState, StructuredSerializedData, TimerSchedulerMsg, TouchEventType, TouchId, UntrustedNodeAddress, UpdatePipelineIdReason, WheelDelta, WindowSizeData, WindowSizeType, }; @@ -91,7 +93,6 @@ use style::thread_state::{self, ThreadState}; use time::precise_time_ns; use url::Position; use webgpu::WebGPUMsg; -use webrender_api::units::LayoutPixel; use webrender_api::DocumentId; use webrender_traits::WebRenderScriptApi; @@ -1836,11 +1837,6 @@ impl ScriptThread { .profile_event(ScriptThreadEventCategory::SetViewport, Some(id), || { self.handle_viewport(id, rect); }), - FromConstellation(ConstellationControlMsg::SetScrollState(id, scroll_state)) => { - self.profile_event(ScriptThreadEventCategory::SetScrollState, Some(id), || { - self.handle_set_scroll_state(id, &scroll_state); - }) - }, FromConstellation(ConstellationControlMsg::TickAllAnimations( pipeline_id, tick_type, @@ -2097,7 +2093,6 @@ impl ScriptThread { ExitScriptThread => None, SendEvent(id, ..) => Some(id), Viewport(id, ..) => Some(id), - SetScrollState(id, ..) => Some(id), GetTitle(id) => Some(id), SetDocumentActivity(id, ..) => Some(id), SetThrottled(id, ..) => Some(id), @@ -2123,7 +2118,8 @@ impl ScriptThread { ExitFullScreen(id, ..) => Some(id), MediaSessionAction(..) => None, SetWebGPUPort(..) => None, - ForLayoutFromConstellation(_, id) => Some(id), + SetScrollStates(id, ..) => Some(id), + SetEpochPaintTime(id, ..) => Some(id), }, MixedMessage::FromDevtools(_) => None, MixedMessage::FromScript(ref inner_msg) => match *inner_msg { @@ -2348,7 +2344,6 @@ impl ScriptThread { }, msg @ ConstellationControlMsg::AttachLayout(..) | msg @ ConstellationControlMsg::Viewport(..) | - msg @ ConstellationControlMsg::SetScrollState(..) | msg @ ConstellationControlMsg::Resize(..) | msg @ ConstellationControlMsg::ExitFullScreen(..) | msg @ ConstellationControlMsg::SendEvent(..) | @@ -2356,22 +2351,53 @@ impl ScriptThread { msg @ ConstellationControlMsg::ExitScriptThread => { panic!("should have handled {:?} already", msg) }, - ConstellationControlMsg::ForLayoutFromConstellation(msg, pipeline_id) => { - self.handle_layout_message_from_constellation(msg, pipeline_id) + ConstellationControlMsg::SetScrollStates(pipeline_id, scroll_states) => { + self.handle_set_scroll_states_msg(pipeline_id, scroll_states) + }, + ConstellationControlMsg::SetEpochPaintTime(pipeline_id, epoch, time) => { + self.handle_set_epoch_paint_time(pipeline_id, epoch, time) }, } } - fn handle_layout_message_from_constellation( + fn handle_set_scroll_states_msg( &self, - msg: LayoutControlMsg, pipeline_id: PipelineId, + scroll_states: Vec, ) { let Some(window) = self.documents.borrow().find_window(pipeline_id) else { - warn!("Received layout message pipeline {pipeline_id} closed: {msg:?}."); + warn!("Received scroll states for closed pipeline {pipeline_id}"); return; }; - window.layout_mut().handle_constellation_message(msg); + + self.profile_event( + ScriptThreadEventCategory::SetScrollState, + Some(pipeline_id), + || { + window.layout_mut().set_scroll_states(&scroll_states); + + let mut scroll_offsets = HashMap::new(); + for scroll_state in scroll_states.into_iter() { + let scroll_offset = scroll_state.scroll_offset; + if scroll_state.scroll_id.is_root() { + window.update_viewport_for_scroll(-scroll_offset.x, -scroll_offset.y); + } else if let Some(node_id) = + node_id_from_scroll_id(scroll_state.scroll_id.0 as usize) + { + scroll_offsets.insert(OpaqueNode(node_id), -scroll_offset); + } + } + window.set_scroll_offsets(scroll_offsets) + }, + ) + } + + fn handle_set_epoch_paint_time(&self, pipeline_id: PipelineId, epoch: Epoch, time: u64) { + let Some(window) = self.documents.borrow().find_window(pipeline_id) else { + warn!("Received set epoch paint time message for closed pipeline {pipeline_id}."); + return; + }; + window.layout_mut().set_epoch_paint_time(epoch, time); } fn handle_msg_from_webgpu_server(&self, msg: WebGPUMsg) { @@ -2763,32 +2789,6 @@ impl ScriptThread { warn!("Page rect message sent to nonexistent pipeline"); } - fn handle_set_scroll_state( - &self, - id: PipelineId, - scroll_states: &[(UntrustedNodeAddress, Vector2D)], - ) { - let window = match self.documents.borrow().find_window(id) { - Some(window) => window, - None => { - return warn!( - "Set scroll state message sent to nonexistent pipeline: {:?}", - id - ); - }, - }; - - let mut scroll_offsets = HashMap::new(); - for &(node_address, ref scroll_offset) in scroll_states { - if node_address == UntrustedNodeAddress(ptr::null()) { - window.update_viewport_for_scroll(-scroll_offset.x, -scroll_offset.y); - } else { - scroll_offsets.insert(OpaqueNode(node_address.0 as usize), -*scroll_offset); - } - } - window.set_scroll_offsets(scroll_offsets) - } - fn handle_new_layout(&self, new_layout_info: NewLayoutInfo, origin: MutableOrigin) { let NewLayoutInfo { parent_info, diff --git a/components/shared/script/lib.rs b/components/shared/script/lib.rs index 931e34c2a2b..2a1947f58a7 100644 --- a/components/shared/script/lib.rs +++ b/components/shared/script/lib.rs @@ -110,15 +110,6 @@ impl UntrustedNodeAddress { } } -/// Messages sent to layout from the constellation and/or compositor. -#[derive(Debug, Deserialize, Serialize)] -pub enum LayoutControlMsg { - /// Tells layout about the new scrolling offsets of each scrollable stacking context. - SetScrollStates(Vec), - /// Send the paint time for a specific epoch to layout. - PaintMetric(Epoch, u64), -} - /// The origin where a given load was initiated. /// Useful for origin checks, for example before evaluation a JS URL. #[derive(Clone, Debug, Deserialize, Serialize)] @@ -302,11 +293,6 @@ pub enum ConstellationControlMsg { SendEvent(PipelineId, CompositorEvent), /// Notifies script of the viewport. Viewport(PipelineId, Rect), - /// Notifies script of a new set of scroll offsets. - SetScrollState( - PipelineId, - Vec<(UntrustedNodeAddress, Vector2D)>, - ), /// Requests that the script thread immediately send the constellation the title of a pipeline. GetTitle(PipelineId), /// Notifies script thread of a change to one of its document's activity @@ -391,8 +377,11 @@ pub enum ConstellationControlMsg { MediaSessionAction(PipelineId, MediaSessionActionType), /// Notifies script thread that WebGPU server has started SetWebGPUPort(IpcReceiver), - /// A mesage for a layout from the constellation. - ForLayoutFromConstellation(LayoutControlMsg, PipelineId), + /// The compositor scrolled and is updating the scroll states of the nodes in the given + /// pipeline via the Constellation. + SetScrollStates(PipelineId, Vec), + /// Send the paint time for a specific epoch. + SetEpochPaintTime(PipelineId, Epoch, u64), } impl fmt::Debug for ConstellationControlMsg { @@ -409,7 +398,6 @@ impl fmt::Debug for ConstellationControlMsg { ExitScriptThread => "ExitScriptThread", SendEvent(..) => "SendEvent", Viewport(..) => "Viewport", - SetScrollState(..) => "SetScrollState", GetTitle(..) => "GetTitle", SetDocumentActivity(..) => "SetDocumentActivity", SetThrottled(..) => "SetThrottled", @@ -431,7 +419,8 @@ impl fmt::Debug for ConstellationControlMsg { ExitFullScreen(..) => "ExitFullScreen", MediaSessionAction(..) => "MediaSessionAction", SetWebGPUPort(..) => "SetWebGPUPort", - ForLayoutFromConstellation(..) => "ForLayoutFromConstellation", + SetScrollStates(..) => "SetScrollStates", + SetEpochPaintTime(..) => "SetEpochPaintTime", }; write!(formatter, "ConstellationControlMsg::{}", variant) } diff --git a/components/shared/script_layout/lib.rs b/components/shared/script_layout/lib.rs index b65d42d1731..baf885e3524 100644 --- a/components/shared/script_layout/lib.rs +++ b/components/shared/script_layout/lib.rs @@ -33,8 +33,8 @@ use net_traits::ResourceThreads; use profile_traits::mem::Report; use profile_traits::time; use script_traits::{ - ConstellationControlMsg, InitialScriptState, LayoutControlMsg, LayoutMsg, LoadData, Painter, - ScrollState, UntrustedNodeAddress, WindowSizeData, + ConstellationControlMsg, InitialScriptState, LayoutMsg, LoadData, Painter, ScrollState, + UntrustedNodeAddress, WindowSizeData, }; use serde::{Deserialize, Serialize}; use servo_arc::Arc as ServoArc; @@ -178,9 +178,6 @@ pub trait LayoutFactory: Send + Sync { } pub trait Layout { - /// Handle a single message from the Constellation. - fn handle_constellation_message(&mut self, msg: LayoutControlMsg); - /// Get a reference to this Layout's Stylo `Device` used to handle media queries and /// resolve font metrics. fn device(&self) -> &Device; @@ -228,6 +225,12 @@ pub trait Layout { painter: Box, ); + /// Set the scroll states of this layout after a compositor scroll. + fn set_scroll_states(&mut self, scroll_states: &[ScrollState]); + + /// Set the paint time for a specific epoch. + fn set_epoch_paint_time(&mut self, epoch: Epoch, paint_time: u64); + fn query_content_box(&self, node: OpaqueNode) -> Option>; fn query_content_boxes(&self, node: OpaqueNode) -> Vec>; fn query_client_rect(&self, node: OpaqueNode) -> Rect;