Wait for actual paint before setting paint related metrics

This commit is contained in:
Fernando Jiménez Moreno 2017-07-26 20:24:42 +02:00
parent 1059ef4fde
commit 1b123400eb
16 changed files with 203 additions and 72 deletions

View file

@ -186,6 +186,13 @@ pub struct IOCompositor<Window: WindowMethods> {
/// GL functions interface (may be GL or GLES)
gl: Rc<gl::Gl>,
/// Map of the pending paint metrics per layout thread.
/// The layout thread for each specific pipeline expects the compositor to
/// paint frames with specific given IDs (epoch). Once the compositor paints
/// these frames, it records the paint time for each of them and sends the
/// metric to the corresponding layout thread.
pending_paint_metrics: HashMap<PipelineId, Epoch>,
}
#[derive(Copy, Clone)]
@ -371,6 +378,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
webrender: state.webrender,
webrender_document: state.webrender_document,
webrender_api: state.webrender_api,
pending_paint_metrics: HashMap::new(),
}
}
@ -593,6 +601,10 @@ impl<Window: WindowMethods> IOCompositor<Window> {
self.window.set_fullscreen_state(top_level_browsing_context_id, state);
}
(Msg::PendingPaintMetric(pipeline_id, epoch), _) => {
self.pending_paint_metrics.insert(pipeline_id, epoch);
}
// 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.
@ -1427,6 +1439,38 @@ impl<Window: WindowMethods> IOCompositor<Window> {
self.webrender.render(self.frame_size);
});
// If there are pending paint metrics, we check if any of the painted epochs is
// one of the ones that the paint metrics recorder is expecting . In that case,
// we get the current time, inform the layout thread about it and remove the
// pending metric from the list.
if !self.pending_paint_metrics.is_empty() {
let paint_time = precise_time_ns() as f64;
let mut to_remove = Vec::new();
// For each pending paint metrics pipeline id
for (id, pending_epoch) in &self.pending_paint_metrics {
// we get the last painted frame id from webrender
if let Some(webrender_api::Epoch(epoch)) = self.webrender.current_epoch(id.to_webrender()) {
// and check if it is the one the layout thread is expecting,
let epoch = Epoch(epoch);
if *pending_epoch != epoch {
continue;
}
// in which case, we remove it from the list of pending metrics,
to_remove.push(id.clone());
if let Some(pipeline) = self.pipeline(*id) {
// and inform the layout thread with the measured paint time.
let msg = LayoutControlMsg::PaintMetric(epoch, paint_time);
if let Err(e) = pipeline.layout_chan.send(msg) {
warn!("Sending PaintMetric message to layout failed ({}).", e);
}
}
}
}
for id in to_remove.iter() {
self.pending_paint_metrics.remove(id);
}
}
let rv = match target {
CompositeTarget::Window => None,
CompositeTarget::WindowAndPng => {

View file

@ -7,6 +7,7 @@
use SendableFrameTree;
use compositor::CompositingReason;
use euclid::{Point2D, Size2D};
use gfx_traits::Epoch;
use ipc_channel::ipc::IpcSender;
use msg::constellation_msg::{Key, KeyModifiers, KeyState, PipelineId, TopLevelBrowsingContextId};
use net_traits::image::base::Image;
@ -143,6 +144,10 @@ pub enum Msg {
Dispatch(Box<Fn() + Send>),
/// Enter or exit fullscreen
SetFullscreenState(TopLevelBrowsingContextId, bool),
/// Indicates to the compositor that it needs to record the time when the frame with
/// the given ID (epoch) is painted and report it to the layout thread of the given
/// pipeline ID.
PendingPaintMetric(PipelineId, Epoch),
}
impl Debug for Msg {
@ -176,6 +181,7 @@ impl Debug for Msg {
Msg::NewScrollFrameReady(..) => write!(f, "NewScrollFrameReady"),
Msg::Dispatch(..) => write!(f, "Dispatch"),
Msg::SetFullscreenState(..) => write!(f, "SetFullscreenState"),
Msg::PendingPaintMetric(..) => write!(f, "PendingPaintMetric"),
}
}
}