compositing: Only recomposite after a scroll if layers actually moved,

and fix the jerky scrolling "pops" during flings on Mac.

See the comments in compositor.rs for more details.

Requires servo/webrender#302 and servo/webrender_traits#64.
This commit is contained in:
Patrick Walton 2016-06-29 16:52:35 -07:00 committed by Ms2ger
parent 8052f5b80d
commit 90e970a6d2
4 changed files with 90 additions and 23 deletions

View file

@ -220,6 +220,9 @@ pub struct IOCompositor<Window: WindowMethods> {
/// 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,
@ -254,6 +257,8 @@ struct ScrollZoomEvent {
cursor: TypedPoint2D<DevicePixel, i32>,
/// The scroll event phase.
phase: ScrollEventPhase,
/// The number of OS events that have been coalesced together into this one event.
event_count: u32,
}
#[derive(PartialEq, Debug)]
@ -398,6 +403,10 @@ impl webrender_traits::RenderNotifier for RenderNotifier {
self.compositor_proxy.recomposite(CompositingReason::NewWebRenderFrame);
}
fn new_scroll_frame_ready(&mut self, composite_needed: bool) {
self.compositor_proxy.send(Msg::NewScrollFrameReady(composite_needed));
}
fn pipeline_size_changed(&mut self,
pipeline_id: webrender_traits::PipelineId,
size: Option<Size2D<f32>>) {
@ -468,6 +477,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
composition_request: CompositionRequest::NoCompositingNecessary,
touch_handler: TouchHandler::new(),
pending_scroll_zoom_events: Vec::new(),
waiting_for_results_of_scroll: false,
composite_target: composite_target,
shutdown_state: ShutdownState::NotShuttingDown,
page_zoom: ScaleFactor::new(1.0),
@ -677,7 +687,6 @@ impl<Window: WindowMethods> IOCompositor<Window> {
}
(Msg::DelayedCompositionTimeout(timestamp), ShutdownState::NotShuttingDown) => {
debug!("delayed composition timeout!");
if let CompositionRequest::DelayedComposite(this_timestamp) =
self.composition_request {
if timestamp == this_timestamp {
@ -789,6 +798,14 @@ impl<Window: WindowMethods> IOCompositor<Window> {
}
}
(Msg::NewScrollFrameReady(recomposite_needed), ShutdownState::NotShuttingDown) => {
self.waiting_for_results_of_scroll = false;
if recomposite_needed {
self.composition_request = CompositionRequest::CompositeNow(
CompositingReason::NewWebRenderScrollFrame);
}
}
// When we are shutting_down, we need to avoid performing operations
// such as Paint that may crash because we have begun tearing down
// the rest of our resources.
@ -1186,8 +1203,8 @@ impl<Window: WindowMethods> IOCompositor<Window> {
fn schedule_delayed_composite_if_necessary(&mut self) {
match self.composition_request {
CompositionRequest::CompositeNow(_) |
CompositionRequest::DelayedComposite(_) => return,
CompositionRequest::CompositeNow(_) => return,
CompositionRequest::DelayedComposite(_) |
CompositionRequest::NoCompositingNecessary => {}
}
@ -1509,6 +1526,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
delta: scroll_delta,
cursor: cursor,
phase: ScrollEventPhase::Move(true),
event_count: 1,
});
self.composite_if_necessary_if_not_using_webrender(CompositingReason::Zoom);
}
@ -1563,6 +1581,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
delta: delta,
cursor: cursor,
phase: ScrollEventPhase::Move(self.scroll_in_progress),
event_count: 1,
});
self.composite_if_necessary_if_not_using_webrender(CompositingReason::Scroll);
}
@ -1576,6 +1595,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
delta: delta,
cursor: cursor,
phase: ScrollEventPhase::Start,
event_count: 1,
});
self.composite_if_necessary_if_not_using_webrender(CompositingReason::Scroll);
}
@ -1589,6 +1609,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
delta: delta,
cursor: cursor,
phase: ScrollEventPhase::End,
event_count: 1,
});
self.composite_if_necessary_if_not_using_webrender(CompositingReason::Scroll);
}
@ -1605,35 +1626,52 @@ impl<Window: WindowMethods> IOCompositor<Window> {
let this_cursor = scroll_event.cursor;
if let Some(combined_event) = last_combined_event {
if combined_event.phase != scroll_event.phase {
webrender_api.scroll(
(combined_event.delta / self.scene.scale).to_untyped(),
(combined_event.cursor.as_f32() / self.scene.scale).to_untyped(),
combined_event.phase);
let delta = (combined_event.delta / self.scene.scale).to_untyped();
let cursor = (combined_event.cursor.as_f32() /
self.scene.scale).to_untyped();
webrender_api.scroll(delta, cursor, combined_event.phase);
last_combined_event = None
}
}
match last_combined_event {
None => {
last_combined_event = Some(ScrollZoomEvent {
match (&mut last_combined_event, scroll_event.phase) {
(last_combined_event @ &mut None, _) => {
*last_combined_event = Some(ScrollZoomEvent {
magnification: scroll_event.magnification,
delta: this_delta,
cursor: this_cursor,
phase: scroll_event.phase,
event_count: 1,
})
}
Some(ref mut last_combined_event) => {
(&mut Some(ref mut last_combined_event),
ScrollEventPhase::Move(false)) => {
// Mac OS X sometimes delivers scroll events out of vsync during a
// fling. This causes events to get bunched up occasionally, causing
// nasty-looking "pops". To mitigate this, during a fling we average
// deltas instead of summing them.
let old_event_count =
ScaleFactor::new(last_combined_event.event_count as f32);
last_combined_event.event_count += 1;
let new_event_count =
ScaleFactor::new(last_combined_event.event_count as f32);
last_combined_event.delta =
(last_combined_event.delta * old_event_count + this_delta) /
new_event_count;
}
(&mut Some(ref mut last_combined_event), _) => {
last_combined_event.delta = last_combined_event.delta + this_delta;
last_combined_event.event_count += 1
}
}
}
// TODO(gw): Support zoom (WR issue #28).
if let Some(combined_event) = last_combined_event {
webrender_api.scroll(
(combined_event.delta / self.scene.scale).to_untyped(),
(combined_event.cursor.as_f32() / self.scene.scale).to_untyped(),
combined_event.phase);
let delta = (combined_event.delta / self.scene.scale).to_untyped();
let cursor = (combined_event.cursor.as_f32() / self.scene.scale).to_untyped();
webrender_api.scroll(delta, cursor, combined_event.phase);
self.waiting_for_results_of_scroll = true
}
}
None => {
@ -1815,6 +1853,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
delta: Point2D::typed(0.0, 0.0), // TODO: Scroll to keep the center in view?
cursor: Point2D::typed(-1, -1), // Make sure this hits the base layer.
phase: ScrollEventPhase::Move(true),
event_count: 1,
});
self.composite_if_necessary_if_not_using_webrender(CompositingReason::Zoom);
}
@ -2281,6 +2320,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
self.process_animations();
self.start_scrolling_bounce_if_necessary();
self.waiting_for_results_of_scroll = false;
Ok(rv)
}
@ -2515,7 +2555,27 @@ impl<Window: WindowMethods> IOCompositor<Window> {
pub fn handle_events(&mut self, messages: Vec<WindowEvent>) -> bool {
// 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() {
match msg {
Msg::Recomposite(_) if found_recomposite_msg => {}
Msg::Recomposite(_) => {
found_recomposite_msg = true;
compositor_messages.push(msg)
}
_ => compositor_messages.push(msg),
}
}
if found_recomposite_msg {
compositor_messages.retain(|msg| {
match *msg {
Msg::DelayedCompositionTimeout(_) => false,
_ => true,
}
})
}
for msg in compositor_messages {
if !self.handle_browser_message(msg) {
break
}
@ -2537,10 +2597,6 @@ impl<Window: WindowMethods> IOCompositor<Window> {
self.send_buffer_requests_for_all_layers();
}
if !self.pending_scroll_zoom_events.is_empty() && opts::get().use_webrender {
self.process_pending_scroll_events()
}
match self.composition_request {
CompositionRequest::NoCompositingNecessary |
CompositionRequest::DelayedComposite(_) => {}
@ -2549,6 +2605,11 @@ impl<Window: WindowMethods> IOCompositor<Window> {
}
}
if !self.pending_scroll_zoom_events.is_empty() && !self.waiting_for_results_of_scroll &&
opts::get().use_webrender {
self.process_pending_scroll_events()
}
self.shutdown_state != ShutdownState::FinishedShuttingDown
}
@ -2650,4 +2711,6 @@ pub enum CompositingReason {
Zoom,
/// A new WebRender frame has arrived.
NewWebRenderFrame,
/// WebRender has processed a scroll event and has generated a new frame.
NewWebRenderScrollFrame,
}

View file

@ -185,6 +185,9 @@ pub enum Msg {
GetScrollOffset(PipelineId, LayerId, IpcSender<Point2D<f32>>),
/// Pipeline visibility changed
PipelineVisibilityChanged(PipelineId, bool),
/// WebRender has successfully processed a scroll. The boolean specifies whether a composite is
/// needed.
NewScrollFrameReady(bool),
/// 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
@ -228,6 +231,7 @@ impl Debug for Msg {
Msg::PipelineVisibilityChanged(..) => write!(f, "PipelineVisibilityChanged"),
Msg::PipelineExited(..) => write!(f, "PipelineExited"),
Msg::GetScrollOffset(..) => write!(f, "GetScrollOffset"),
Msg::NewScrollFrameReady(..) => write!(f, "NewScrollFrameReady"),
}
}
}

View file

@ -2585,7 +2585,7 @@ dependencies = [
[[package]]
name = "webrender"
version = "0.1.0"
source = "git+https://github.com/servo/webrender#85f887b21f6eac3e33aea3fee0f076dc7c890307"
source = "git+https://github.com/servo/webrender#f69f9a1a4cf31c60dc03480abfd0a74aeb305f9c"
dependencies = [
"app_units 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
"bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2609,7 +2609,7 @@ dependencies = [
[[package]]
name = "webrender_traits"
version = "0.2.0"
source = "git+https://github.com/servo/webrender_traits#a466592568193d9ec8a57de9837dddb28ee9631e"
source = "git+https://github.com/servo/webrender_traits#d86e51ace4fd1b43123e0490dc80f631be0726d0"
dependencies = [
"app_units 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",

4
ports/cef/Cargo.lock generated
View file

@ -2447,7 +2447,7 @@ dependencies = [
[[package]]
name = "webrender"
version = "0.1.0"
source = "git+https://github.com/servo/webrender#85f887b21f6eac3e33aea3fee0f076dc7c890307"
source = "git+https://github.com/servo/webrender#f69f9a1a4cf31c60dc03480abfd0a74aeb305f9c"
dependencies = [
"app_units 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
"bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2471,7 +2471,7 @@ dependencies = [
[[package]]
name = "webrender_traits"
version = "0.2.0"
source = "git+https://github.com/servo/webrender_traits#a466592568193d9ec8a57de9837dddb28ee9631e"
source = "git+https://github.com/servo/webrender_traits#d86e51ace4fd1b43123e0490dc80f631be0726d0"
dependencies = [
"app_units 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",