compositing: Split non-WebView-specific data into ServoRenderer (#35536)

This will become the new global Servo renderer while each WebView will
also have its renderer (but not yet).

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
Co-authored-by: Ngo Iok Ui (Wu Yu Wei) <yuweiwu@pm.me>
This commit is contained in:
Martin Robinson 2025-02-19 16:29:32 +01:00 committed by GitHub
parent 4a5ff01e06
commit 168f7ead15
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 170 additions and 124 deletions

View file

@ -96,17 +96,50 @@ impl FrameTreeId {
}
}
/// NB: Never block on the constellation, because sometimes the constellation blocks on us.
pub struct IOCompositor {
/// The application window.
pub window: Rc<dyn WindowMethods>,
/// The port on which we receive messages.
port: CompositorReceiver,
/// Data that is shared by all WebView renderers.
pub struct ServoRenderer {
/// Our top-level browsing contexts.
webviews: WebViewManager<WebView>,
/// Tracks whether we are in the process of shutting down, or have shut down and should close
/// the compositor.
shutdown_state: ShutdownState,
/// The port on which we receive messages.
compositor_receiver: CompositorReceiver,
/// The channel on which messages can be sent to the constellation.
constellation_sender: Sender<ConstellationMsg>,
/// The channel on which messages can be sent to the time profiler.
time_profiler_chan: profile_time::ProfilerChan,
/// The WebRender [`RenderApi`] interface used to communicate with WebRender.
webrender_api: RenderApi,
/// The GL bindings for webrender
webrender_gl: Rc<dyn gleam::gl::Gl>,
/// True to exit after page load ('-x').
exit_after_load: bool,
/// The string representing the version of Servo that is running. This is used to tag
/// WebRender capture output.
version_string: String,
#[cfg(feature = "webxr")]
/// Some XR devices want to run on the main thread.
webxr_main_thread: webxr::MainThreadRegistry,
}
/// NB: Never block on the constellation, because sometimes the constellation blocks on us.
pub struct IOCompositor {
/// Data that is shared by all WebView renderers.
global: ServoRenderer,
/// The application window.
pub window: Rc<dyn WindowMethods>,
/// Tracks details about each active pipeline that the compositor knows about.
pipeline_details: HashMap<PipelineId, PipelineDetails>,
@ -126,10 +159,6 @@ pub struct IOCompositor {
/// Tracks whether or not the view needs to be repainted.
needs_repaint: Cell<RepaintReason>,
/// Tracks whether we are in the process of shutting down, or have shut down and should close
/// the compositor.
pub shutdown_state: ShutdownState,
/// Tracks whether the zoom action has happened recently.
zoom_action: bool,
@ -139,12 +168,6 @@ pub struct IOCompositor {
/// The current frame tree ID (used to reject old paint buffers)
frame_tree_id: FrameTreeId,
/// The channel on which messages can be sent to the constellation.
constellation_chan: Sender<ConstellationMsg>,
/// The channel on which messages can be sent to the time profiler.
time_profiler_chan: profile_time::ProfilerChan,
/// Touch input state machine
touch_handler: TouchHandler,
@ -161,19 +184,9 @@ pub struct IOCompositor {
/// The active webrender document.
webrender_document: DocumentId,
/// The webrender interface, if enabled.
webrender_api: RenderApi,
/// The surfman instance that webrender targets
rendering_context: Rc<dyn RenderingContext>,
/// The GL bindings for webrender
webrender_gl: Rc<dyn gleam::gl::Gl>,
#[cfg(feature = "webxr")]
/// Some XR devices want to run on the main thread.
pub webxr_main_thread: webxr::MainThreadRegistry,
/// A per-pipeline queue of display lists that have not yet been rendered by WebRender. Layout
/// expects WebRender to paint each given epoch. Once the compositor paints a frame with that
/// epoch's display list, it will be removed from the queue and the paint time will be recorded
@ -190,9 +203,6 @@ pub struct IOCompositor {
/// Current cursor position.
cursor_pos: DevicePoint,
/// True to exit after page load ('-x').
exit_after_load: bool,
/// True to translate mouse input into touch events.
convert_mouse_to_touch: bool,
@ -202,10 +212,6 @@ pub struct IOCompositor {
/// The [`Instant`] of the last animation tick, used to avoid flooding the Constellation and
/// ScriptThread with a deluge of animation ticks.
last_animation_tick: Instant,
/// The string representing the version of Servo that is running. This is used to tag
/// WebRender capture output.
version_string: String,
}
#[derive(Clone, Copy)]
@ -341,16 +347,26 @@ impl IOCompositor {
version_string: String,
) -> Self {
let compositor = IOCompositor {
global: ServoRenderer {
shutdown_state: ShutdownState::NotShuttingDown,
webviews: WebViewManager::default(),
compositor_receiver: state.receiver,
constellation_sender: state.constellation_chan,
time_profiler_chan: state.time_profiler_chan,
webrender_api: state.webrender_api,
webrender_gl: state.webrender_gl,
exit_after_load,
version_string,
#[cfg(feature = "webxr")]
webxr_main_thread: state.webxr_main_thread,
},
embedder_coordinates: window.get_coordinates(),
window,
port: state.receiver,
webviews: WebViewManager::default(),
pipeline_details: HashMap::new(),
needs_repaint: Cell::default(),
touch_handler: TouchHandler::new(),
pending_scroll_zoom_events: Vec::new(),
composite_target,
shutdown_state: ShutdownState::NotShuttingDown,
page_zoom: Scale::new(1.0),
viewport_zoom: PinchZoomFactor::new(1.0),
min_viewport_zoom: Some(PinchZoomFactor::new(1.0)),
@ -358,33 +374,29 @@ impl IOCompositor {
zoom_action: false,
zoom_time: 0f64,
frame_tree_id: FrameTreeId(0),
constellation_chan: state.constellation_chan,
time_profiler_chan: state.time_profiler_chan,
ready_to_save_state: ReadyState::Unknown,
webrender: Some(state.webrender),
webrender_document: state.webrender_document,
webrender_api: state.webrender_api,
rendering_context: state.rendering_context,
webrender_gl: state.webrender_gl,
#[cfg(feature = "webxr")]
webxr_main_thread: state.webxr_main_thread,
pending_paint_metrics: HashMap::new(),
cursor: Cursor::None,
cursor_pos: DevicePoint::new(0.0, 0.0),
exit_after_load,
convert_mouse_to_touch,
pending_frames: 0,
last_animation_tick: Instant::now(),
version_string,
};
let gl = &compositor.webrender_gl;
let gl = &compositor.global.webrender_gl;
info!("Running on {}", gl.get_string(gleam::gl::RENDERER));
info!("OpenGL Version {}", gl.get_string(gleam::gl::VERSION));
compositor.assert_gl_framebuffer_complete();
compositor
}
pub fn shutdown_state(&self) -> ShutdownState {
self.global.shutdown_state
}
pub fn deinit(&mut self) {
if let Err(err) = self.rendering_context.make_current() {
warn!("Failed to make the rendering context current: {:?}", err);
@ -424,23 +436,27 @@ impl IOCompositor {
self.cursor = cursor;
let msg = ConstellationMsg::SetCursor(webview_id, cursor);
if let Err(e) = self.constellation_chan.send(msg) {
if let Err(e) = self.global.constellation_sender.send(msg) {
warn!("Sending event to constellation failed ({:?}).", e);
}
}
pub fn start_shutting_down(&mut self) {
if self.shutdown_state != ShutdownState::NotShuttingDown {
if self.global.shutdown_state != ShutdownState::NotShuttingDown {
warn!("Requested shutdown while already shutting down");
return;
}
debug!("Compositor sending Exit message to Constellation");
if let Err(e) = self.constellation_chan.send(ConstellationMsg::Exit) {
if let Err(e) = self
.global
.constellation_sender
.send(ConstellationMsg::Exit)
{
warn!("Sending exit message to constellation failed ({:?}).", e);
}
self.shutdown_state = ShutdownState::ShuttingDown;
self.global.shutdown_state = ShutdownState::ShuttingDown;
}
fn finish_shutting_down(&mut self) {
@ -448,22 +464,28 @@ impl IOCompositor {
// Drain compositor port, sometimes messages contain channels that are blocking
// another thread from finishing (i.e. SetFrameTree).
while self.port.try_recv_compositor_msg().is_some() {}
while self
.global
.compositor_receiver
.try_recv_compositor_msg()
.is_some()
{}
// Tell the profiler, memory profiler, and scrolling timer to shut down.
if let Ok((sender, receiver)) = ipc::channel() {
self.time_profiler_chan
self.global
.time_profiler_chan
.send(profile_time::ProfilerMsg::Exit(sender));
let _ = receiver.recv();
}
self.shutdown_state = ShutdownState::FinishedShuttingDown;
self.global.shutdown_state = ShutdownState::FinishedShuttingDown;
}
fn handle_browser_message(&mut self, msg: CompositorMsg) {
trace_msg_from_constellation!(msg, "{msg:?}");
match self.shutdown_state {
match self.global.shutdown_state {
ShutdownState::NotShuttingDown => {},
ShutdownState::ShuttingDown => {
self.handle_browser_message_while_shutting_down(msg);
@ -550,7 +572,7 @@ impl IOCompositor {
CompositorMsg::LoadComplete(_) => {
// If we're painting in headless mode, schedule a recomposite.
if matches!(self.composite_target, CompositeTarget::PngFile(_)) ||
self.exit_after_load
self.global.exit_after_load
{
self.set_needs_repaint(RepaintReason::ReadyForScreenshot);
}
@ -597,7 +619,8 @@ impl IOCompositor {
let mut txn = Transaction::new();
txn.set_display_list(WebRenderEpoch(0), (pipeline, Default::default()));
self.generate_frame(&mut txn, RenderReasons::SCENE);
self.webrender_api
self.global
.webrender_api
.send_transaction(self.webrender_document, txn);
},
@ -633,7 +656,8 @@ impl IOCompositor {
}],
);
self.generate_frame(&mut txn, RenderReasons::APZ);
self.webrender_api
self.global
.webrender_api
.send_transaction(self.webrender_document, txn);
},
@ -693,7 +717,8 @@ impl IOCompositor {
.set_display_list(display_list_info.epoch, (pipeline_id, built_display_list));
self.update_transaction_with_all_scroll_offsets(&mut transaction);
self.generate_frame(&mut transaction, RenderReasons::SCENE);
self.webrender_api
self.global
.webrender_api
.send_transaction(self.webrender_document, transaction);
},
@ -708,14 +733,14 @@ impl IOCompositor {
// would be to listen to the TransactionNotifier for previous per-pipeline
// transactions, but that isn't easily compatible with the event loop wakeup
// mechanism from libserver.
self.webrender_api.flush_scene_builder();
self.global.webrender_api.flush_scene_builder();
let result = self.hit_test_at_point_with_flags_and_pipeline(point, flags, pipeline);
let _ = sender.send(result);
},
CrossProcessCompositorMessage::GenerateImageKey(sender) => {
let _ = sender.send(self.webrender_api.generate_image_key());
let _ = sender.send(self.global.webrender_api.generate_image_key());
},
CrossProcessCompositorMessage::UpdateImages(updates) => {
@ -731,7 +756,8 @@ impl IOCompositor {
},
}
}
self.webrender_api
self.global
.webrender_api
.send_transaction(self.webrender_document, txn);
},
@ -742,7 +768,8 @@ impl IOCompositor {
CrossProcessCompositorMessage::AddSystemFont(font_key, native_handle) => {
let mut transaction = Transaction::new();
transaction.add_native_font(font_key, native_handle);
self.webrender_api
self.global
.webrender_api
.send_transaction(self.webrender_document, transaction);
},
@ -765,14 +792,16 @@ impl IOCompositor {
transaction.delete_font(key);
}
self.webrender_api
self.global
.webrender_api
.send_transaction(self.webrender_document, transaction);
},
CrossProcessCompositorMessage::AddImage(key, desc, data) => {
let mut txn = Transaction::new();
txn.add_image(key, desc, data.into(), None);
self.webrender_api
self.global
.webrender_api
.send_transaction(self.webrender_document, txn);
},
@ -782,10 +811,10 @@ impl IOCompositor {
result_sender,
) => {
let font_keys = (0..number_of_font_keys)
.map(|_| self.webrender_api.generate_font_key())
.map(|_| self.global.webrender_api.generate_font_key())
.collect();
let font_instance_keys = (0..number_of_font_instance_keys)
.map(|_| self.webrender_api.generate_font_instance_key())
.map(|_| self.global.webrender_api.generate_font_instance_key())
.collect();
let _ = result_sender.send((font_keys, font_instance_keys));
},
@ -832,7 +861,7 @@ impl IOCompositor {
CompositorMsg::CrossProcess(CrossProcessCompositorMessage::GenerateImageKey(
sender,
)) => {
let _ = sender.send(self.webrender_api.generate_image_key());
let _ = sender.send(self.global.webrender_api.generate_image_key());
},
CompositorMsg::CrossProcess(CrossProcessCompositorMessage::GenerateFontKeys(
number_of_font_keys,
@ -840,10 +869,10 @@ impl IOCompositor {
result_sender,
)) => {
let font_keys = (0..number_of_font_keys)
.map(|_| self.webrender_api.generate_font_key())
.map(|_| self.global.webrender_api.generate_font_key())
.collect();
let font_instance_keys = (0..number_of_font_instance_keys)
.map(|_| self.webrender_api.generate_font_instance_key())
.map(|_| self.global.webrender_api.generate_font_instance_key())
.collect();
let _ = result_sender.send((font_keys, font_instance_keys));
},
@ -947,7 +976,8 @@ impl IOCompositor {
let mut transaction = Transaction::new();
self.send_root_pipeline_display_list_in_transaction(&mut transaction);
self.generate_frame(&mut transaction, RenderReasons::SCENE);
self.webrender_api
self.global
.webrender_api
.send_transaction(self.webrender_document, transaction);
}
@ -986,7 +1016,7 @@ impl IOCompositor {
let root_clip_id = builder.define_clip_rect(zoom_reference_frame, scaled_viewport_rect);
let clip_chain_id = builder.define_clip_chain(None, [root_clip_id]);
for (_, webview) in self.webviews.painting_order() {
for (_, webview) in self.global.webviews.painting_order() {
if let Some(pipeline_id) = webview.pipeline_id {
let scaled_webview_rect = webview.rect / zoom_factor;
builder.push_iframe(
@ -1042,7 +1072,7 @@ impl IOCompositor {
debug!("{}: Setting frame tree for webview", frame_tree.pipeline.id);
let top_level_browsing_context_id = frame_tree.pipeline.top_level_browsing_context_id;
if let Some(webview) = self.webviews.get_mut(top_level_browsing_context_id) {
if let Some(webview) = self.global.webviews.get_mut(top_level_browsing_context_id) {
let new_pipeline_id = Some(frame_tree.pipeline.id);
if new_pipeline_id != webview.pipeline_id {
debug!(
@ -1058,7 +1088,7 @@ impl IOCompositor {
"{:?}: Creating new webview with pipeline {:?}",
top_level_browsing_context_id, pipeline_id
);
if let Err(WebViewAlreadyExists(webview_id)) = self.webviews.add(
if let Err(WebViewAlreadyExists(webview_id)) = self.global.webviews.add(
top_level_browsing_context_id,
WebView {
pipeline_id,
@ -1069,7 +1099,7 @@ impl IOCompositor {
return;
}
let msg = ConstellationMsg::WebViewOpened(top_level_browsing_context_id);
if let Err(e) = self.constellation_chan.send(msg) {
if let Err(e) = self.global.constellation_sender.send(msg) {
warn!("Sending event to constellation failed ({:?}).", e);
}
}
@ -1083,7 +1113,7 @@ impl IOCompositor {
fn remove_webview(&mut self, top_level_browsing_context_id: TopLevelBrowsingContextId) {
debug!("{}: Removing", top_level_browsing_context_id);
let Ok(webview) = self.webviews.remove(top_level_browsing_context_id) else {
let Ok(webview) = self.global.webviews.remove(top_level_browsing_context_id) else {
warn!("{top_level_browsing_context_id}: Removing unknown webview");
return;
};
@ -1100,7 +1130,7 @@ impl IOCompositor {
debug!("{webview_id}: Moving and/or resizing webview; rect={rect:?}");
let rect_changed;
let size_changed;
match self.webviews.get_mut(webview_id) {
match self.global.webviews.get_mut(webview_id) {
Some(webview) => {
rect_changed = rect != webview.rect;
size_changed = rect.size() != webview.rect.size();
@ -1129,15 +1159,16 @@ impl IOCompositor {
debug!("{webview_id}: Showing webview; hide_others={hide_others}");
let painting_order_changed = if hide_others {
let result = self
.global
.webviews
.painting_order()
.map(|(&id, _)| id)
.ne(once(webview_id));
self.webviews.hide_all();
self.webviews.show(webview_id)?;
self.global.webviews.hide_all();
self.global.webviews.show(webview_id)?;
result
} else {
self.webviews.show(webview_id)?
self.global.webviews.show(webview_id)?
};
if painting_order_changed {
self.send_root_pipeline_display_list();
@ -1147,7 +1178,7 @@ impl IOCompositor {
pub fn hide_webview(&mut self, webview_id: WebViewId) -> Result<(), UnknownWebView> {
debug!("{webview_id}: Hiding webview");
if self.webviews.hide(webview_id)? {
if self.global.webviews.hide(webview_id)? {
self.send_root_pipeline_display_list();
}
Ok(())
@ -1161,15 +1192,16 @@ impl IOCompositor {
debug!("{webview_id}: Raising webview to top; hide_others={hide_others}");
let painting_order_changed = if hide_others {
let result = self
.global
.webviews
.painting_order()
.map(|(&id, _)| id)
.ne(once(webview_id));
self.webviews.hide_all();
self.webviews.raise_to_top(webview_id)?;
self.global.webviews.hide_all();
self.global.webviews.raise_to_top(webview_id)?;
result
} else {
self.webviews.raise_to_top(webview_id)?
self.global.webviews.raise_to_top(webview_id)?
};
if painting_order_changed {
self.send_root_pipeline_display_list();
@ -1194,7 +1226,7 @@ impl IOCompositor {
},
WindowSizeType::Resize,
);
if let Err(e) = self.constellation_chan.send(msg) {
if let Err(e) = self.global.constellation_sender.send(msg) {
warn!("Sending window resize to constellation failed ({:?}).", e);
}
}
@ -1267,7 +1299,7 @@ impl IOCompositor {
}
pub fn on_rendering_context_resized(&mut self) -> bool {
if self.shutdown_state != ShutdownState::NotShuttingDown {
if self.global.shutdown_state != ShutdownState::NotShuttingDown {
return false;
}
@ -1279,7 +1311,8 @@ impl IOCompositor {
let size = self.embedder_coordinates.get_viewport();
transaction.set_document_view(size);
self.rendering_context.resize(size.size().to_untyped());
self.webrender_api
self.global
.webrender_api
.send_transaction(self.webrender_document, transaction);
}
@ -1310,7 +1343,8 @@ impl IOCompositor {
self.update_cursor(&result);
if let Err(error) = self
.constellation_chan
.global
.constellation_sender
.send(ConstellationMsg::ForwardInputEvent(event, Some(result)))
{
warn!("Sending event to constellation failed ({error:?}).");
@ -1318,7 +1352,7 @@ impl IOCompositor {
}
pub fn on_input_event(&mut self, event: InputEvent) {
if self.shutdown_state != ShutdownState::NotShuttingDown {
if self.global.shutdown_state != ShutdownState::NotShuttingDown {
return;
}
@ -1377,9 +1411,12 @@ impl IOCompositor {
) -> Vec<CompositorHitTestResult> {
// DevicePoint and WorldPoint are the same for us.
let world_point = WorldPoint::from_untyped(point.to_untyped());
let results =
self.webrender_api
.hit_test(self.webrender_document, pipeline_id, world_point, flags);
let results = self.global.webrender_api.hit_test(
self.webrender_document,
pipeline_id,
world_point,
flags,
);
results
.items
@ -1419,7 +1456,8 @@ impl IOCompositor {
let event = InputEvent::Touch(event);
if let Err(e) = self
.constellation_chan
.global
.constellation_sender
.send(ConstellationMsg::ForwardInputEvent(event, Some(result)))
{
warn!("Sending event to constellation failed ({:?}).", e);
@ -1427,7 +1465,7 @@ impl IOCompositor {
}
pub fn on_touch_event(&mut self, event: TouchEvent) {
if self.shutdown_state != ShutdownState::NotShuttingDown {
if self.global.shutdown_state != ShutdownState::NotShuttingDown {
return;
}
@ -1567,7 +1605,7 @@ impl IOCompositor {
cursor: DeviceIntPoint,
event_type: TouchEventType,
) {
if self.shutdown_state != ShutdownState::NotShuttingDown {
if self.global.shutdown_state != ShutdownState::NotShuttingDown {
return;
}
@ -1670,7 +1708,8 @@ impl IOCompositor {
}
self.generate_frame(&mut transaction, RenderReasons::APZ);
self.webrender_api
self.global
.webrender_api
.send_transaction(self.webrender_document, transaction);
}
@ -1745,7 +1784,7 @@ impl IOCompositor {
}
}
#[cfg(feature = "webxr")]
let webxr_running = self.webxr_main_thread.running();
let webxr_running = self.global.webxr_main_thread.running();
#[cfg(not(feature = "webxr"))]
let webxr_running = false;
let animation_state = if pipeline_ids.is_empty() && !webxr_running {
@ -1777,7 +1816,7 @@ impl IOCompositor {
}
let msg = ConstellationMsg::TickAnimation(pipeline_id, tick_type);
if let Err(e) = self.constellation_chan.send(msg) {
if let Err(e) = self.global.constellation_sender.send(msg) {
warn!("Sending tick to constellation failed ({:?}).", e);
}
}
@ -1800,7 +1839,7 @@ impl IOCompositor {
}
pub fn on_zoom_reset_window_event(&mut self) {
if self.shutdown_state != ShutdownState::NotShuttingDown {
if self.global.shutdown_state != ShutdownState::NotShuttingDown {
return;
}
@ -1809,7 +1848,7 @@ impl IOCompositor {
}
pub fn on_zoom_window_event(&mut self, magnification: f32) {
if self.shutdown_state != ShutdownState::NotShuttingDown {
if self.global.shutdown_state != ShutdownState::NotShuttingDown {
return;
}
@ -1819,7 +1858,7 @@ impl IOCompositor {
}
fn update_after_zoom_or_hidpi_change(&mut self) {
for (top_level_browsing_context_id, webview) in self.webviews.painting_order() {
for (top_level_browsing_context_id, webview) in self.global.webviews.painting_order() {
self.send_window_size_message_for_top_level_browser_context(
webview.rect,
*top_level_browsing_context_id,
@ -1832,7 +1871,7 @@ impl IOCompositor {
/// Simulate a pinch zoom
pub fn on_pinch_zoom_window_event(&mut self, magnification: f32) {
if self.shutdown_state != ShutdownState::NotShuttingDown {
if self.global.shutdown_state != ShutdownState::NotShuttingDown {
return;
}
@ -1923,7 +1962,7 @@ impl IOCompositor {
// Pass the pipeline/epoch states to the constellation and check
// if it's safe to output the image.
let msg = ConstellationMsg::IsReadyToSaveImage(pipeline_epochs);
if let Err(e) = self.constellation_chan.send(msg) {
if let Err(e) = self.global.constellation_sender.send(msg) {
warn!("Sending ready to save to constellation failed ({:?}).", e);
}
self.ready_to_save_state = ReadyState::WaitingForConstellationReply;
@ -1959,7 +1998,9 @@ impl IOCompositor {
// Queue up any subsequent paints for animations.
self.process_animations(true);
if matches!(self.composite_target, CompositeTarget::PngFile(_)) || self.exit_after_load {
if matches!(self.composite_target, CompositeTarget::PngFile(_)) ||
self.global.exit_after_load
{
println!("Shutting down the Constellation after generating an output file or exit flag specified");
self.start_shutting_down();
}
@ -1991,7 +2032,7 @@ impl IOCompositor {
let wait_for_stable_image = matches!(
target,
CompositeTarget::SharedMemory | CompositeTarget::PngFile(_)
) || self.exit_after_load;
) || self.global.exit_after_load;
if wait_for_stable_image {
// The current image may be ready to output. However, if there are animations active,
@ -2013,7 +2054,7 @@ impl IOCompositor {
time_profile!(
ProfilerCategory::Compositing,
None,
self.time_profiler_chan.clone(),
self.global.time_profiler_chan.clone(),
|| {
trace!("Compositing");
@ -2066,7 +2107,7 @@ impl IOCompositor {
time_profile!(
ProfilerCategory::ImageSaving,
None,
self.time_profiler_chan.clone(),
self.global.time_profiler_chan.clone(),
|| match File::create(&*path) {
Ok(mut file) => {
if let Some(image) = self.rendering_context.read_to_image(Rect::new(
@ -2157,7 +2198,7 @@ impl IOCompositor {
}
fn clear_background(&self) {
let gl = &self.webrender_gl;
let gl = &self.global.webrender_gl;
self.assert_gl_framebuffer_complete();
// Always clear the entire RenderingContext, regardless of how many WebViews there are
@ -2175,15 +2216,16 @@ impl IOCompositor {
#[track_caller]
fn assert_no_gl_error(&self) {
debug_assert_eq!(self.webrender_gl.get_error(), gleam::gl::NO_ERROR);
debug_assert_eq!(self.global.webrender_gl.get_error(), gleam::gl::NO_ERROR);
}
#[track_caller]
fn assert_gl_framebuffer_complete(&self) {
debug_assert_eq!(
(
self.webrender_gl.get_error(),
self.webrender_gl
self.global.webrender_gl.get_error(),
self.global
.webrender_gl
.check_frame_buffer_status(gleam::gl::FRAMEBUFFER)
),
(gleam::gl::NO_ERROR, gleam::gl::FRAMEBUFFER_COMPLETE)
@ -2198,7 +2240,7 @@ impl IOCompositor {
// Check for new messages coming from the other threads in the system.
let mut compositor_messages = vec![];
let mut found_recomposite_msg = false;
while let Some(msg) = self.port.try_recv_compositor_msg() {
while let Some(msg) = self.global.compositor_receiver.try_recv_compositor_msg() {
match msg {
CompositorMsg::NewWebRenderFrameReady(..) if found_recomposite_msg => {
// Only take one of duplicate NewWebRendeFrameReady messages, but do subtract
@ -2215,7 +2257,7 @@ impl IOCompositor {
for msg in compositor_messages {
self.handle_browser_message(msg);
if self.shutdown_state == ShutdownState::FinishedShuttingDown {
if self.global.shutdown_state == ShutdownState::FinishedShuttingDown {
return;
}
}
@ -2226,7 +2268,7 @@ impl IOCompositor {
tracing::instrument(skip_all, fields(servo_profiling = true), level = "trace")
)]
pub fn perform_updates(&mut self) -> bool {
if self.shutdown_state == ShutdownState::FinishedShuttingDown {
if self.global.shutdown_state == ShutdownState::FinishedShuttingDown {
return false;
}
@ -2241,7 +2283,7 @@ impl IOCompositor {
#[cfg(feature = "webxr")]
// Run the WebXR main thread
self.webxr_main_thread.run_one_frame();
self.global.webxr_main_thread.run_one_frame();
// The WebXR thread may make a different context current
if let Err(err) = self.rendering_context.make_current() {
@ -2250,7 +2292,7 @@ impl IOCompositor {
if !self.pending_scroll_zoom_events.is_empty() {
self.process_pending_scroll_events()
}
self.shutdown_state != ShutdownState::FinishedShuttingDown
self.global.shutdown_state != ShutdownState::FinishedShuttingDown
}
pub fn pinch_zoom_level(&self) -> Scale<f32, DevicePixel, DevicePixel> {
@ -2288,7 +2330,8 @@ impl IOCompositor {
let mut txn = Transaction::new();
self.generate_frame(&mut txn, RenderReasons::TESTING);
self.webrender_api
self.global
.webrender_api
.send_transaction(self.webrender_document, txn);
}
@ -2313,12 +2356,13 @@ impl IOCompositor {
};
println!("Saving WebRender capture to {capture_path:?}");
self.webrender_api
self.global
.webrender_api
.save_capture(capture_path.clone(), CaptureBits::all());
let version_file_path = capture_path.join("servo-version.txt");
if let Err(error) = File::create(version_file_path)
.and_then(|mut file| write!(file, "{}", self.version_string))
.and_then(|mut file| write!(file, "{}", self.global.version_string))
{
eprintln!("Unable to write servo version for WebRender Capture: {error:?}");
}
@ -2346,14 +2390,16 @@ impl IOCompositor {
Vec::new(),
);
self.webrender_api
self.global
.webrender_api
.send_transaction(self.webrender_document, transaction);
}
fn add_font(&mut self, font_key: FontKey, index: u32, data: Arc<IpcSharedMemory>) {
let mut transaction = Transaction::new();
transaction.add_raw_font(font_key, (**data).into(), index);
self.webrender_api
self.global
.webrender_api
.send_transaction(self.webrender_document, transaction);
}
}

View file

@ -629,14 +629,14 @@ impl Servo {
/// The return value of this method indicates whether or not Servo, false indicates that Servo
/// has finished shutting down and you should not spin the event loop any longer.
pub fn spin_event_loop(&self) -> bool {
if self.compositor.borrow().shutdown_state == ShutdownState::FinishedShuttingDown {
if self.compositor.borrow().shutdown_state() == ShutdownState::FinishedShuttingDown {
return false;
}
self.compositor.borrow_mut().receive_messages();
// Only handle incoming embedder messages if the compositor hasn't already started shutting down.
if self.compositor.borrow().shutdown_state == ShutdownState::NotShuttingDown {
if self.compositor.borrow().shutdown_state() == ShutdownState::NotShuttingDown {
while let Ok(message) = self.embedder_receiver.try_recv() {
self.handle_embedder_message(message)
}
@ -650,7 +650,7 @@ impl Servo {
self.compositor.borrow_mut().perform_updates();
self.send_new_frame_ready_messages();
if self.compositor.borrow().shutdown_state == ShutdownState::FinishedShuttingDown {
if self.compositor.borrow().shutdown_state() == ShutdownState::FinishedShuttingDown {
return false;
}