Skip to content

Commit

Permalink
Have all new WebRender frames go through the same path
Browse files Browse the repository at this point in the history
This simplifies the way that the notifier passes new frame notifications
to WebRender and keeps a simple count of pending frames. In addition, it
makes sure that the compositor increases the pending frame count each
time it calls generate frame.
  • Loading branch information
mrobinson committed Mar 5, 2024
1 parent 28949d3 commit 46adfc1
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 93 deletions.
96 changes: 58 additions & 38 deletions components/compositing/compositor.rs
Expand Up @@ -13,7 +13,7 @@ use std::time::{SystemTime, UNIX_EPOCH};

use canvas::canvas_paint_thread::ImageUpdate;
use compositing_traits::{
CanvasToCompositorMsg, CompositingReason, CompositionPipeline, CompositorMsg,
CanvasToCompositorMsg, CompositionPipeline, CompositorMsg,
CompositorReceiver, ConstellationMsg, FontToCompositorMsg, ForwardedToCompositorMsg,
SendableFrameTree,
};
Expand Down Expand Up @@ -172,9 +172,6 @@ pub struct IOCompositor<Window: WindowMethods + ?Sized> {
/// Pending scroll/zoom events.
pending_scroll_zoom_events: Vec<ScrollZoomEvent>,

/// Whether we're waiting on a recomposite after dispatching a scroll.
waiting_for_results_of_scroll: bool,

/// Used by the logic that determines when it is safe to output an
/// image for the reftest framework.
ready_to_save_state: ReadyState,
Expand Down Expand Up @@ -234,10 +231,8 @@ pub struct IOCompositor<Window: WindowMethods + ?Sized> {
/// True to translate mouse input into touch events.
convert_mouse_to_touch: bool,

/// True if a WR frame render has been requested. Screenshots
/// taken before the render is complete will not reflect the
/// most up to date rendering.
waiting_on_pending_frame: bool,
/// The number of frames pending to receive from WebRender.
pending_frames: u32,

/// Waiting for external code to call present.
waiting_on_present: bool,
Expand All @@ -262,6 +257,23 @@ enum ScrollZoomEvent {
Scroll(ScrollEvent),
}

/// Why we performed a composite. This is used for debugging.
///
/// TODO: It would be good to have a bit more precision here about why a composite
/// was originally triggered, but that would require tracking the reason when a
/// frame is queued in WebRender and then remembering when the frame is ready.
#[derive(Clone, Copy, Debug, PartialEq)]
enum CompositingReason {
/// We're performing the single composite in headless mode.
Headless,
/// We're performing a composite to run an animation.
Animation,
/// A new WebRender frame has arrived.
NewWebRenderFrame,
/// The window has been resized and will need to be synchronously repainted.
Resize,
}

#[derive(Debug, PartialEq)]
enum CompositionRequest {
NoCompositingNecessary,
Expand Down Expand Up @@ -376,7 +388,6 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
composition_request: CompositionRequest::NoCompositingNecessary,
touch_handler: TouchHandler::new(),
pending_scroll_zoom_events: Vec::new(),
waiting_for_results_of_scroll: false,
composite_target,
shutdown_state: ShutdownState::NotShuttingDown,
page_zoom: Scale::new(1.0),
Expand Down Expand Up @@ -404,7 +415,7 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
is_running_problem_test,
exit_after_load,
convert_mouse_to_touch,
waiting_on_pending_frame: false,
pending_frames: 0,
waiting_on_present: false,
}
}
Expand Down Expand Up @@ -537,11 +548,6 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
self.send_scroll_positions_to_layout_for_pipeline(&frame_tree.pipeline.id);
},

(CompositorMsg::Recomposite(reason), ShutdownState::NotShuttingDown) => {
self.waiting_on_pending_frame = false;
self.composition_request = CompositionRequest::CompositeNow(reason)
},

(CompositorMsg::TouchEventProcessed(result), ShutdownState::NotShuttingDown) => {
self.touch_handler.on_event_processed(result);
},
Expand All @@ -562,8 +568,7 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
self.ready_to_save_state,
ReadyState::WaitingForConstellationReply
);
if is_ready && !self.waiting_on_pending_frame && !self.waiting_for_results_of_scroll
{
if is_ready && self.pending_frames <= 0 {
self.ready_to_save_state = ReadyState::ReadyToSaveImage;
if self.is_running_problem_test {
println!("ready to save image!");
Expand Down Expand Up @@ -592,17 +597,18 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
},

(
CompositorMsg::NewScrollFrameReady(recomposite_needed),
ShutdownState::NotShuttingDown,
CompositorMsg::NewWebRenderFrameReady(recomposite_needed),
_,
) => {
self.waiting_for_results_of_scroll = false;
if let Some(result) = self.hit_test_at_device_point(self.cursor_pos) {
self.update_cursor(result);
}
if recomposite_needed {
self.composition_request = CompositionRequest::CompositeNow(
CompositingReason::NewWebRenderScrollFrame,
);
assert!(self.pending_frames > 0);
self.pending_frames -= 1;

if self.shutdown_state != ShutdownState::NotShuttingDown && recomposite_needed {
if let Some(result) = self.hit_test_at_device_point(self.cursor_pos) {
self.update_cursor(result);
}
self.composition_request =
CompositionRequest::CompositeNow(CompositingReason::NewWebRenderFrame);
}
},

Expand Down Expand Up @@ -685,19 +691,19 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
ForwardedToCompositorMsg::Layout(
script_traits::ScriptToCompositorMsg::SendInitialTransaction(pipeline),
) => {
self.waiting_on_pending_frame = true;
let mut txn = Transaction::new();
txn.set_display_list(WebRenderEpoch(0), (pipeline, Default::default()));

self.pending_frames += 1;
txn.generate_frame(0, RenderReasons::APZ);

self.webrender_api
.send_transaction(self.webrender_document, txn);
},

ForwardedToCompositorMsg::Layout(
script_traits::ScriptToCompositorMsg::SendScrollNode(point, scroll_id),
) => {
self.waiting_for_results_of_scroll = true;

let mut txn = Transaction::new();
let offset = point.to_vector();
txn.set_scroll_offsets(
Expand All @@ -707,7 +713,10 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
generation: 0,
}],
);

self.pending_frames += 1;
txn.generate_frame(0, RenderReasons::APZ);

self.webrender_api
.send_transaction(self.webrender_document, txn);
},
Expand Down Expand Up @@ -753,8 +762,6 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
display_list_descriptor,
);

self.waiting_on_pending_frame = true;

let pipeline_id = display_list_info.pipeline_id;
let details = self.pipeline_details(PipelineId::from_webrender(pipeline_id));
details.most_recent_display_list_epoch = Some(display_list_info.epoch);
Expand All @@ -778,7 +785,9 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
}
}

self.pending_frames += 1;
transaction.generate_frame(0, RenderReasons::SCENE);

self.webrender_api
.send_transaction(self.webrender_document, transaction);
},
Expand Down Expand Up @@ -1039,7 +1048,10 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {

let mut txn = Transaction::new();
self.set_root_content_pipeline_handling_device_scaling(&mut txn);

self.pending_frames += 1;
txn.generate_frame(0, RenderReasons::NONE);

self.webrender_api
.send_transaction(self.webrender_document, txn);

Expand Down Expand Up @@ -1089,6 +1101,10 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
}

pub fn on_resize_window_event(&mut self) -> bool {
if self.shutdown_state != ShutdownState::NotShuttingDown {
return false;
}

let old_coords = self.embedder_coordinates;
self.embedder_coordinates = self.window.get_coordinates();

Expand Down Expand Up @@ -1460,10 +1476,11 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
}],
);
self.send_scroll_positions_to_layout_for_pipeline(&pipeline_id);
self.waiting_for_results_of_scroll = true
}

self.pending_frames += 1;
transaction.generate_frame(0, RenderReasons::APZ);

self.webrender_api
.send_transaction(self.webrender_document, transaction);
}
Expand Down Expand Up @@ -1954,7 +1971,6 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
self.composition_request = CompositionRequest::NoCompositingNecessary;

self.process_animations();
self.waiting_for_results_of_scroll = false;

Ok(rv)
}
Expand Down Expand Up @@ -2037,8 +2053,8 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
let mut found_recomposite_msg = false;
while let Some(msg) = self.port.try_recv_compositor_msg() {
match msg {
CompositorMsg::Recomposite(_) if found_recomposite_msg => {},
CompositorMsg::Recomposite(_) => {
CompositorMsg::NewWebRenderFrameReady(..) if found_recomposite_msg => {},
CompositorMsg::NewWebRenderFrameReady(..) => {
found_recomposite_msg = true;
compositor_messages.push(msg)
},
Expand Down Expand Up @@ -2078,7 +2094,7 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
// The WebXR thread may make a different context current
let _ = self.rendering_context.make_gl_context_current();

if !self.pending_scroll_zoom_events.is_empty() && !self.waiting_for_results_of_scroll {
if !self.pending_scroll_zoom_events.is_empty() {
self.process_pending_scroll_events()
}
self.shutdown_state != ShutdownState::FinishedShuttingDown
Expand All @@ -2092,7 +2108,7 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
while self.shutdown_state != ShutdownState::ShuttingDown {
let msg = self.port.recv_compositor_msg();
let need_recomposite = match msg {
CompositorMsg::Recomposite(_) => true,
CompositorMsg::NewWebRenderFrameReady(..) => true,
_ => false,
};
let keep_going = self.handle_browser_message(msg);
Expand Down Expand Up @@ -2137,7 +2153,11 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
self.webrender.set_debug_flags(flags);

let mut txn = Transaction::new();


self.pending_frames += 1;
txn.generate_frame(0, RenderReasons::TESTING);

self.webrender_api
.send_transaction(self.webrender_document, txn);
}
Expand Down
19 changes: 5 additions & 14 deletions components/servo/lib.rs
Expand Up @@ -33,7 +33,7 @@ use canvas_traits::webgl::WebGLThreads;
use compositing::windowing::{EmbedderEvent, EmbedderMethods, WindowMethods};
use compositing::{CompositeTarget, IOCompositor, InitialCompositorState, ShutdownState};
use compositing_traits::{
CanvasToCompositorMsg, CompositingReason, CompositorMsg, CompositorProxy, CompositorReceiver,
CanvasToCompositorMsg, CompositorMsg, CompositorProxy, CompositorReceiver,
ConstellationMsg, FontToCompositorMsg, ForwardedToCompositorMsg,
};
#[cfg(all(
Expand Down Expand Up @@ -198,26 +198,17 @@ impl webrender_api::RenderNotifier for RenderNotifier {
Box::new(RenderNotifier::new(self.compositor_proxy.clone()))
}

fn wake_up(&self, composite_needed: bool) {
if composite_needed {
self.compositor_proxy
.recomposite(CompositingReason::NewWebRenderFrame);
}
}
fn wake_up(&self, _composite_needed: bool) { }

fn new_frame_ready(
&self,
_document_id: DocumentId,
scrolled: bool,
_scrolled: bool,
composite_needed: bool,
_frame_publish_id: FramePublishId,
) {
if scrolled {
self.compositor_proxy
.send(CompositorMsg::NewScrollFrameReady(composite_needed));
} else {
self.wake_up(true);
}
self.compositor_proxy
.send(CompositorMsg::NewWebRenderFrameReady(composite_needed));
}
}

Expand Down
46 changes: 5 additions & 41 deletions components/shared/compositing/lib.rs
Expand Up @@ -27,33 +27,6 @@ use style_traits::CSSPixel;
use webrender_api::units::{DeviceIntPoint, DeviceIntSize};
use webrender_api::{self, FontInstanceKey, FontKey, ImageKey};

/// Why we performed a composite. This is used for debugging.
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum CompositingReason {
/// We hit the delayed composition timeout. (See `delayed_composition.rs`.)
DelayedCompositeTimeout,
/// The window has been scrolled and we're starting the first recomposite.
Scroll,
/// A scroll has continued and we need to recomposite again.
ContinueScroll,
/// We're performing the single composite in headless mode.
Headless,
/// We're performing a composite to run an animation.
Animation,
/// A new frame tree has been loaded.
NewFrameTree,
/// New painted buffers have been received.
NewPaintedBuffers,
/// The window has been zoomed.
Zoom,
/// A new WebRender frame has arrived.
NewWebRenderFrame,
/// WebRender has processed a scroll event and has generated a new frame.
NewWebRenderScrollFrame,
/// The window has been resized and will need to be synchronously repainted.
Resize,
}

/// Sends messages to the compositor.
pub struct CompositorProxy {
pub sender: Sender<CompositorMsg>,
Expand Down Expand Up @@ -92,12 +65,6 @@ impl CompositorReceiver {
}
}

impl CompositorProxy {
pub fn recomposite(&self, reason: CompositingReason) {
self.send(CompositorMsg::Recomposite(reason));
}
}

/// Messages from (or via) the constellation thread to the compositor.
pub enum CompositorMsg {
/// Informs the compositor that the constellation has completed shutdown.
Expand All @@ -108,8 +75,6 @@ pub enum CompositorMsg {
ChangeRunningAnimationsState(PipelineId, AnimationState),
/// Replaces the current frame tree, typically called during main frame navigation.
SetFrameTree(SendableFrameTree),
/// Composite.
Recomposite(CompositingReason),
/// Script has handled a touch event, and either prevented or allowed default actions.
TouchEventProcessed(EventResult),
/// Composite to a PNG file and return the Image over a passed channel.
Expand All @@ -118,16 +83,16 @@ pub enum CompositorMsg {
IsReadyToSaveImageReply(bool),
/// Pipeline visibility changed
PipelineVisibilityChanged(PipelineId, bool),
/// WebRender has successfully processed a scroll. The boolean specifies whether a composite is
/// needed.
NewScrollFrameReady(bool),
/// WebRender has produced a new frame. This message informs the compositor that
/// the frame is ready, so that it may trigger a recomposite.
NewWebRenderFrameReady(bool /* composite_needed */),
/// A pipeline was shut down.
// This message acts as a synchronization point between the constellation,
// when it shuts down a pipeline, to the compositor; when the compositor
// sends a reply on the IpcSender, the constellation knows it's safe to
// tear down the other threads associated with this pipeline.
PipelineExited(PipelineId, IpcSender<()>),
/// Runs a closure in the compositor thread.
/// Runs a closure in, bool /* scrolled */ the compositor thread.
/// It's used to dispatch functions from webrender to the main thread's event loop.
/// Required to allow WGL GLContext sharing in Windows.
Dispatch(Box<dyn Fn() + Send>),
Expand Down Expand Up @@ -193,13 +158,12 @@ impl Debug for CompositorMsg {
write!(f, "ChangeRunningAnimationsState({:?})", state)
},
CompositorMsg::SetFrameTree(..) => write!(f, "SetFrameTree"),
CompositorMsg::Recomposite(..) => write!(f, "Recomposite"),
CompositorMsg::TouchEventProcessed(..) => write!(f, "TouchEventProcessed"),
CompositorMsg::CreatePng(..) => write!(f, "CreatePng"),
CompositorMsg::IsReadyToSaveImageReply(..) => write!(f, "IsReadyToSaveImageReply"),
CompositorMsg::PipelineVisibilityChanged(..) => write!(f, "PipelineVisibilityChanged"),
CompositorMsg::PipelineExited(..) => write!(f, "PipelineExited"),
CompositorMsg::NewScrollFrameReady(..) => write!(f, "NewScrollFrameReady"),
CompositorMsg::NewWebRenderFrameReady(..) => write!(f, "NewWebRenderFrameReady"),
CompositorMsg::Dispatch(..) => write!(f, "Dispatch"),
CompositorMsg::PendingPaintMetric(..) => write!(f, "PendingPaintMetric"),
CompositorMsg::LoadComplete(..) => write!(f, "LoadComplete"),
Expand Down

0 comments on commit 46adfc1

Please sign in to comment.