mirror of
https://github.com/servo/servo.git
synced 2025-07-29 18:20:24 +01:00
Auto merge of #8314 - jdm:timeoutinvestigations, r=metajack
Investigations for #7787 I'm just going to keep throwing stuff at try, because running directly on the builders isn't yielding results. <!-- Reviewable:start --> [<img src="https://reviewable.io/review_button.png" height=40 alt="Review on Reviewable"/>](https://reviewable.io/reviews/servo/servo/8314) <!-- Reviewable:end -->
This commit is contained in:
commit
c78da15abb
3 changed files with 93 additions and 26 deletions
|
@ -55,6 +55,24 @@ use util::opts;
|
||||||
use util::print_tree::PrintTree;
|
use util::print_tree::PrintTree;
|
||||||
use windowing::{self, MouseWindowEvent, WindowEvent, WindowMethods, WindowNavigateMsg};
|
use windowing::{self, MouseWindowEvent, WindowEvent, WindowMethods, WindowNavigateMsg};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum UnableToComposite {
|
||||||
|
NoContext,
|
||||||
|
WindowUnprepared,
|
||||||
|
NotReadyToPaintImage(NotReadyToPaint),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum NotReadyToPaint {
|
||||||
|
LayerHasOutstandingPaintMessages,
|
||||||
|
MissingRoot,
|
||||||
|
PendingSubpages(usize),
|
||||||
|
AnimationsRunning,
|
||||||
|
AnimationCallbacksRunning,
|
||||||
|
JustNotifiedConstellation,
|
||||||
|
WaitingOnConstellation,
|
||||||
|
}
|
||||||
|
|
||||||
const BUFFER_MAP_SIZE: usize = 10000000;
|
const BUFFER_MAP_SIZE: usize = 10000000;
|
||||||
|
|
||||||
// Default viewport constraints
|
// Default viewport constraints
|
||||||
|
@ -211,7 +229,7 @@ pub struct ScrollEvent {
|
||||||
cursor: TypedPoint2D<DevicePixel, i32>,
|
cursor: TypedPoint2D<DevicePixel, i32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq)]
|
#[derive(PartialEq, Debug)]
|
||||||
enum CompositionRequest {
|
enum CompositionRequest {
|
||||||
NoCompositingNecessary,
|
NoCompositingNecessary,
|
||||||
CompositeOnScrollTimeout(u64),
|
CompositeOnScrollTimeout(u64),
|
||||||
|
@ -579,8 +597,14 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
||||||
assert!(self.ready_to_save_state == ReadyState::WaitingForConstellationReply);
|
assert!(self.ready_to_save_state == ReadyState::WaitingForConstellationReply);
|
||||||
if is_ready {
|
if is_ready {
|
||||||
self.ready_to_save_state = ReadyState::ReadyToSaveImage;
|
self.ready_to_save_state = ReadyState::ReadyToSaveImage;
|
||||||
|
if opts::get().is_running_problem_test {
|
||||||
|
println!("ready to save image!");
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
self.ready_to_save_state = ReadyState::Unknown;
|
self.ready_to_save_state = ReadyState::Unknown;
|
||||||
|
if opts::get().is_running_problem_test {
|
||||||
|
println!("resetting ready_to_save_state!");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
self.composite_if_necessary(CompositingReason::Headless);
|
self.composite_if_necessary(CompositingReason::Headless);
|
||||||
}
|
}
|
||||||
|
@ -1678,7 +1702,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
||||||
/// Query the constellation to see if the current compositor
|
/// Query the constellation to see if the current compositor
|
||||||
/// output matches the current frame tree output, and if the
|
/// output matches the current frame tree output, and if the
|
||||||
/// associated script tasks are idle.
|
/// associated script tasks are idle.
|
||||||
fn is_ready_to_paint_image_output(&mut self) -> bool {
|
fn is_ready_to_paint_image_output(&mut self) -> Result<(), NotReadyToPaint> {
|
||||||
match self.ready_to_save_state {
|
match self.ready_to_save_state {
|
||||||
ReadyState::Unknown => {
|
ReadyState::Unknown => {
|
||||||
// Unsure if the output image is stable.
|
// Unsure if the output image is stable.
|
||||||
|
@ -1689,17 +1713,17 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
||||||
match self.scene.root {
|
match self.scene.root {
|
||||||
Some(ref root_layer) => {
|
Some(ref root_layer) => {
|
||||||
if self.does_layer_have_outstanding_paint_messages(root_layer) {
|
if self.does_layer_have_outstanding_paint_messages(root_layer) {
|
||||||
return false;
|
return Err(NotReadyToPaint::LayerHasOutstandingPaintMessages);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
return false;
|
return Err(NotReadyToPaint::MissingRoot);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if there are any pending frames. If so, the image is not stable yet.
|
// Check if there are any pending frames. If so, the image is not stable yet.
|
||||||
if self.pending_subpages.len() > 0 {
|
if self.pending_subpages.len() > 0 {
|
||||||
return false
|
return Err(NotReadyToPaint::PendingSubpages(self.pending_subpages.len()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect the currently painted epoch of each pipeline that is
|
// Collect the currently painted epoch of each pipeline that is
|
||||||
|
@ -1710,8 +1734,11 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
||||||
for (id, details) in &self.pipeline_details {
|
for (id, details) in &self.pipeline_details {
|
||||||
// If animations are currently running, then don't bother checking
|
// If animations are currently running, then don't bother checking
|
||||||
// with the constellation if the output image is stable.
|
// with the constellation if the output image is stable.
|
||||||
if details.animations_running || details.animation_callbacks_running {
|
if details.animations_running {
|
||||||
return false;
|
return Err(NotReadyToPaint::AnimationsRunning);
|
||||||
|
}
|
||||||
|
if details.animation_callbacks_running {
|
||||||
|
return Err(NotReadyToPaint::AnimationCallbacksRunning);
|
||||||
}
|
}
|
||||||
|
|
||||||
pipeline_epochs.insert(*id, details.current_epoch);
|
pipeline_epochs.insert(*id, details.current_epoch);
|
||||||
|
@ -1722,12 +1749,12 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
||||||
let ConstellationChan(ref chan) = self.constellation_chan;
|
let ConstellationChan(ref chan) = self.constellation_chan;
|
||||||
chan.send(ConstellationMsg::IsReadyToSaveImage(pipeline_epochs)).unwrap();
|
chan.send(ConstellationMsg::IsReadyToSaveImage(pipeline_epochs)).unwrap();
|
||||||
self.ready_to_save_state = ReadyState::WaitingForConstellationReply;
|
self.ready_to_save_state = ReadyState::WaitingForConstellationReply;
|
||||||
false
|
Err(NotReadyToPaint::JustNotifiedConstellation)
|
||||||
}
|
}
|
||||||
ReadyState::WaitingForConstellationReply => {
|
ReadyState::WaitingForConstellationReply => {
|
||||||
// If waiting on a reply from the constellation to the last
|
// If waiting on a reply from the constellation to the last
|
||||||
// query if the image is stable, then assume not ready yet.
|
// query if the image is stable, then assume not ready yet.
|
||||||
false
|
Err(NotReadyToPaint::WaitingOnConstellation)
|
||||||
}
|
}
|
||||||
ReadyState::ReadyToSaveImage => {
|
ReadyState::ReadyToSaveImage => {
|
||||||
// Constellation has replied at some point in the past
|
// Constellation has replied at some point in the past
|
||||||
|
@ -1735,8 +1762,9 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
||||||
// for saving.
|
// for saving.
|
||||||
// Reset the flag so that we check again in the future
|
// Reset the flag so that we check again in the future
|
||||||
// TODO: only reset this if we load a new document?
|
// TODO: only reset this if we load a new document?
|
||||||
|
println!("was ready to save, resetting ready_to_save_state");
|
||||||
self.ready_to_save_state = ReadyState::Unknown;
|
self.ready_to_save_state = ReadyState::Unknown;
|
||||||
true
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1746,8 +1774,10 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
||||||
let composited = self.composite_specific_target(target);
|
let composited = self.composite_specific_target(target);
|
||||||
if composited.is_ok() &&
|
if composited.is_ok() &&
|
||||||
(opts::get().output_file.is_some() || opts::get().exit_after_load) {
|
(opts::get().output_file.is_some() || opts::get().exit_after_load) {
|
||||||
debug!("Shutting down the Constellation after generating an output file or exit flag specified");
|
println!("Shutting down the Constellation after generating an output file or exit flag specified");
|
||||||
self.start_shutting_down();
|
self.start_shutting_down();
|
||||||
|
} else if composited.is_err() && opts::get().is_running_problem_test {
|
||||||
|
println!("not ready to composite: {:?}", composited.err().unwrap());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1756,26 +1786,28 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
||||||
/// for some reason. If CompositeTarget is Window or Png no image data is returned;
|
/// for some reason. If CompositeTarget is Window or Png no image data is returned;
|
||||||
/// in the latter case the image is written directly to a file. If CompositeTarget
|
/// in the latter case the image is written directly to a file. If CompositeTarget
|
||||||
/// is WindowAndPng Ok(Some(png::Image)) is returned.
|
/// is WindowAndPng Ok(Some(png::Image)) is returned.
|
||||||
pub fn composite_specific_target(&mut self, target: CompositeTarget) -> Result<Option<Image>, ()> {
|
pub fn composite_specific_target(&mut self, target: CompositeTarget) -> Result<Option<Image>, UnableToComposite> {
|
||||||
|
|
||||||
if !self.context.is_some() {
|
if !self.context.is_some() {
|
||||||
return Err(())
|
return Err(UnableToComposite::NoContext)
|
||||||
}
|
}
|
||||||
let (width, height) =
|
let (width, height) =
|
||||||
(self.window_size.width.get() as usize, self.window_size.height.get() as usize);
|
(self.window_size.width.get() as usize, self.window_size.height.get() as usize);
|
||||||
if !self.window.prepare_for_composite(width, height) {
|
if !self.window.prepare_for_composite(width, height) {
|
||||||
return Err(())
|
return Err(UnableToComposite::WindowUnprepared)
|
||||||
}
|
}
|
||||||
|
|
||||||
match target {
|
match target {
|
||||||
CompositeTarget::WindowAndPng | CompositeTarget::PngFile => {
|
CompositeTarget::WindowAndPng | CompositeTarget::PngFile => {
|
||||||
if !self.is_ready_to_paint_image_output() {
|
if let Err(result) = self.is_ready_to_paint_image_output() {
|
||||||
return Err(())
|
return Err(UnableToComposite::NotReadyToPaintImage(result))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CompositeTarget::Window => {
|
CompositeTarget::Window => {
|
||||||
if opts::get().exit_after_load && !self.is_ready_to_paint_image_output() {
|
if opts::get().exit_after_load {
|
||||||
return Err(())
|
if let Err(result) = self.is_ready_to_paint_image_output() {
|
||||||
|
return Err(UnableToComposite::NotReadyToPaintImage(result))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1892,7 +1924,12 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
||||||
|
|
||||||
fn composite_if_necessary(&mut self, reason: CompositingReason) {
|
fn composite_if_necessary(&mut self, reason: CompositingReason) {
|
||||||
if self.composition_request == CompositionRequest::NoCompositingNecessary {
|
if self.composition_request == CompositionRequest::NoCompositingNecessary {
|
||||||
|
if opts::get().is_running_problem_test {
|
||||||
|
println!("updating composition_request ({:?})", reason);
|
||||||
|
}
|
||||||
self.composition_request = CompositionRequest::CompositeNow(reason)
|
self.composition_request = CompositionRequest::CompositeNow(reason)
|
||||||
|
} else if opts::get().is_running_problem_test {
|
||||||
|
println!("composition_request is already {:?}", self.composition_request);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2145,7 +2182,7 @@ impl<Window> CompositorEventListener for IOCompositor<Window> where Window: Wind
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Why we performed a composite. This is used for debugging.
|
/// Why we performed a composite. This is used for debugging.
|
||||||
#[derive(Copy, Clone, PartialEq)]
|
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||||
pub enum CompositingReason {
|
pub enum CompositingReason {
|
||||||
/// We hit the scroll timeout and are therefore drawing unrendered content.
|
/// We hit the scroll timeout and are therefore drawing unrendered content.
|
||||||
HitScrollTimeout,
|
HitScrollTimeout,
|
||||||
|
|
|
@ -57,6 +57,16 @@ use util::geometry::PagePx;
|
||||||
use util::task::spawn_named;
|
use util::task::spawn_named;
|
||||||
use util::{opts, prefs};
|
use util::{opts, prefs};
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
enum ReadyToSave {
|
||||||
|
NoRootFrame,
|
||||||
|
WebFontNotLoaded,
|
||||||
|
DocumentLoading,
|
||||||
|
EpochMismatch,
|
||||||
|
PipelineUnknown,
|
||||||
|
Ready,
|
||||||
|
}
|
||||||
|
|
||||||
/// Maintains the pipelines and navigation context and grants permission to composite.
|
/// Maintains the pipelines and navigation context and grants permission to composite.
|
||||||
///
|
///
|
||||||
/// It is parameterized over a `LayoutTaskFactory` and a
|
/// It is parameterized over a `LayoutTaskFactory` and a
|
||||||
|
@ -516,7 +526,14 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
|
||||||
}
|
}
|
||||||
ConstellationMsg::IsReadyToSaveImage(pipeline_states) => {
|
ConstellationMsg::IsReadyToSaveImage(pipeline_states) => {
|
||||||
let is_ready = self.handle_is_ready_to_save_image(pipeline_states);
|
let is_ready = self.handle_is_ready_to_save_image(pipeline_states);
|
||||||
|
if opts::get().is_running_problem_test {
|
||||||
|
println!("got ready to save image query, result is {:?}", is_ready);
|
||||||
|
}
|
||||||
|
let is_ready = is_ready == ReadyToSave::Ready;
|
||||||
self.compositor_proxy.send(CompositorMsg::IsReadyToSaveImageReply(is_ready));
|
self.compositor_proxy.send(CompositorMsg::IsReadyToSaveImageReply(is_ready));
|
||||||
|
if opts::get().is_running_problem_test {
|
||||||
|
println!("sent response");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ConstellationMsg::RemoveIFrame(pipeline_id) => {
|
ConstellationMsg::RemoveIFrame(pipeline_id) => {
|
||||||
debug!("constellation got remove iframe message");
|
debug!("constellation got remove iframe message");
|
||||||
|
@ -1188,11 +1205,11 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
|
||||||
/// to check if the output image is "stable" and can be written as a screenshot
|
/// to check if the output image is "stable" and can be written as a screenshot
|
||||||
/// for reftests.
|
/// for reftests.
|
||||||
fn handle_is_ready_to_save_image(&mut self,
|
fn handle_is_ready_to_save_image(&mut self,
|
||||||
pipeline_states: HashMap<PipelineId, Epoch>) -> bool {
|
pipeline_states: HashMap<PipelineId, Epoch>) -> ReadyToSave {
|
||||||
// If there is no root frame yet, the initial page has
|
// If there is no root frame yet, the initial page has
|
||||||
// not loaded, so there is nothing to save yet.
|
// not loaded, so there is nothing to save yet.
|
||||||
if self.root_frame_id.is_none() {
|
if self.root_frame_id.is_none() {
|
||||||
return false;
|
return ReadyToSave::NoRootFrame;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step through the current frame tree, checking that the script
|
// Step through the current frame tree, checking that the script
|
||||||
|
@ -1215,7 +1232,7 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
|
||||||
let msg = LayoutControlMsg::GetWebFontLoadState(sender);
|
let msg = LayoutControlMsg::GetWebFontLoadState(sender);
|
||||||
pipeline.layout_chan.0.send(msg).unwrap();
|
pipeline.layout_chan.0.send(msg).unwrap();
|
||||||
if receiver.recv().unwrap() {
|
if receiver.recv().unwrap() {
|
||||||
return false;
|
return ReadyToSave::WebFontNotLoaded;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Synchronously query the script task for this pipeline
|
// Synchronously query the script task for this pipeline
|
||||||
|
@ -1225,7 +1242,7 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
|
||||||
pipeline.script_chan.send(msg).unwrap();
|
pipeline.script_chan.send(msg).unwrap();
|
||||||
let result = receiver.recv().unwrap();
|
let result = receiver.recv().unwrap();
|
||||||
if result == ScriptState::DocumentLoading {
|
if result == ScriptState::DocumentLoading {
|
||||||
return false;
|
return ReadyToSave::DocumentLoading;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check the visible rectangle for this pipeline. If the constellation has received a
|
// Check the visible rectangle for this pipeline. If the constellation has received a
|
||||||
|
@ -1253,20 +1270,20 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
|
||||||
layout_chan.send(LayoutControlMsg::GetCurrentEpoch(sender)).unwrap();
|
layout_chan.send(LayoutControlMsg::GetCurrentEpoch(sender)).unwrap();
|
||||||
let layout_task_epoch = receiver.recv().unwrap();
|
let layout_task_epoch = receiver.recv().unwrap();
|
||||||
if layout_task_epoch != *compositor_epoch {
|
if layout_task_epoch != *compositor_epoch {
|
||||||
return false;
|
return ReadyToSave::EpochMismatch;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
// The compositor doesn't know about this pipeline yet.
|
// The compositor doesn't know about this pipeline yet.
|
||||||
// Assume it hasn't rendered yet.
|
// Assume it hasn't rendered yet.
|
||||||
return false;
|
return ReadyToSave::PipelineUnknown;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// All script tasks are idle and layout epochs match compositor, so output image!
|
// All script tasks are idle and layout epochs match compositor, so output image!
|
||||||
true
|
ReadyToSave::Ready
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close a frame (and all children)
|
// Close a frame (and all children)
|
||||||
|
|
|
@ -23,6 +23,8 @@ use url::{self, Url};
|
||||||
/// Global flags for Servo, currently set on the command line.
|
/// Global flags for Servo, currently set on the command line.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Opts {
|
pub struct Opts {
|
||||||
|
pub is_running_problem_test: bool,
|
||||||
|
|
||||||
/// The initial URL to load.
|
/// The initial URL to load.
|
||||||
pub url: Option<Url>,
|
pub url: Option<Url>,
|
||||||
|
|
||||||
|
@ -397,6 +399,7 @@ const DEFAULT_USER_AGENT: UserAgent = UserAgent::Desktop;
|
||||||
|
|
||||||
pub fn default_opts() -> Opts {
|
pub fn default_opts() -> Opts {
|
||||||
Opts {
|
Opts {
|
||||||
|
is_running_problem_test: false,
|
||||||
url: Some(Url::parse("about:blank").unwrap()),
|
url: Some(Url::parse("about:blank").unwrap()),
|
||||||
paint_threads: 1,
|
paint_threads: 1,
|
||||||
gpu_painting: false,
|
gpu_painting: false,
|
||||||
|
@ -518,6 +521,15 @@ pub fn from_cmdline_args(args: &[String]) {
|
||||||
} else {
|
} else {
|
||||||
homepage_pref.as_string()
|
homepage_pref.as_string()
|
||||||
};
|
};
|
||||||
|
let is_running_problem_test =
|
||||||
|
url_opt
|
||||||
|
.as_ref()
|
||||||
|
.map(|url|
|
||||||
|
url.starts_with("http://web-platform.test:8000/2dcontext/drawing-images-to-the-canvas/") ||
|
||||||
|
url.starts_with("http://web-platform.test:8000/_mozilla/mozilla/canvas/") ||
|
||||||
|
url.starts_with("http://web-platform.test:8000/_mozilla/css/canvas_over_area.html"))
|
||||||
|
.unwrap_or(false);
|
||||||
|
|
||||||
let url = match url_opt {
|
let url = match url_opt {
|
||||||
Some(url_string) => {
|
Some(url_string) => {
|
||||||
parse_url_or_filename(&cwd, url_string)
|
parse_url_or_filename(&cwd, url_string)
|
||||||
|
@ -605,6 +617,7 @@ pub fn from_cmdline_args(args: &[String]) {
|
||||||
}).collect();
|
}).collect();
|
||||||
|
|
||||||
let opts = Opts {
|
let opts = Opts {
|
||||||
|
is_running_problem_test: is_running_problem_test,
|
||||||
url: Some(url),
|
url: Some(url),
|
||||||
paint_threads: paint_threads,
|
paint_threads: paint_threads,
|
||||||
gpu_painting: gpu_painting,
|
gpu_painting: gpu_painting,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue