mirror of
https://github.com/servo/servo.git
synced 2025-08-03 20:50:07 +01:00
Auto merge of #25822 - jdm:delay-reftest-async-render, r=emilio
Delay reftest screenshot while WR frame is rendering This PR addresses the theory that #24726 occurs when WR is performing an async frame render and the reftest screenshot decides it's time to synchronously read the framebuffer. If there have not been any completed frames rendered yet, that would yield the page background colour. The changes in this PR introduce an additional layer of synchronization - the compositor stores an AtomicBool value that indicates whether we know that a WR frame has started rendering, which is set to true when an IPC request from layout that submits a new display list is received. This bool is set to false when WR notifies us that a frame has been rendered. The screenshot code refuses to take a screenshot if the bool is true, causing us to delay taking a screenshot until there is no frame pending.
This commit is contained in:
commit
be4ecb9233
4 changed files with 35 additions and 2 deletions
|
@ -39,6 +39,8 @@ use std::fs::{create_dir_all, File};
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::num::NonZeroU32;
|
use std::num::NonZeroU32;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
use std::sync::Arc;
|
||||||
use style_traits::viewport::ViewportConstraints;
|
use style_traits::viewport::ViewportConstraints;
|
||||||
use style_traits::{CSSPixel, DevicePixel, PinchZoomFactor};
|
use style_traits::{CSSPixel, DevicePixel, PinchZoomFactor};
|
||||||
use time::{now, precise_time_ns, precise_time_s};
|
use time::{now, precise_time_ns, precise_time_s};
|
||||||
|
@ -208,6 +210,11 @@ pub struct IOCompositor<Window: WindowMethods + ?Sized> {
|
||||||
|
|
||||||
/// True to translate mouse input into touch events.
|
/// True to translate mouse input into touch events.
|
||||||
convert_mouse_to_touch: bool,
|
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: Arc<AtomicBool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
|
@ -322,6 +329,7 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
|
||||||
is_running_problem_test,
|
is_running_problem_test,
|
||||||
exit_after_load,
|
exit_after_load,
|
||||||
convert_mouse_to_touch,
|
convert_mouse_to_touch,
|
||||||
|
waiting_on_pending_frame: state.pending_wr_frame,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -425,6 +433,7 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
|
||||||
},
|
},
|
||||||
|
|
||||||
(Msg::Recomposite(reason), ShutdownState::NotShuttingDown) => {
|
(Msg::Recomposite(reason), ShutdownState::NotShuttingDown) => {
|
||||||
|
self.waiting_on_pending_frame.store(false, Ordering::SeqCst);
|
||||||
self.composition_request = CompositionRequest::CompositeNow(reason)
|
self.composition_request = CompositionRequest::CompositeNow(reason)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -455,7 +464,7 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
|
||||||
self.ready_to_save_state,
|
self.ready_to_save_state,
|
||||||
ReadyState::WaitingForConstellationReply
|
ReadyState::WaitingForConstellationReply
|
||||||
);
|
);
|
||||||
if is_ready {
|
if is_ready && !self.waiting_on_pending_frame.load(Ordering::SeqCst) {
|
||||||
self.ready_to_save_state = ReadyState::ReadyToSaveImage;
|
self.ready_to_save_state = ReadyState::ReadyToSaveImage;
|
||||||
if self.is_running_problem_test {
|
if self.is_running_problem_test {
|
||||||
println!("ready to save image!");
|
println!("ready to save image!");
|
||||||
|
|
|
@ -17,6 +17,8 @@ use profile_traits::mem;
|
||||||
use profile_traits::time;
|
use profile_traits::time;
|
||||||
use script_traits::{AnimationState, EventResult, MouseButton, MouseEventType};
|
use script_traits::{AnimationState, EventResult, MouseButton, MouseEventType};
|
||||||
use std::fmt::{Debug, Error, Formatter};
|
use std::fmt::{Debug, Error, Formatter};
|
||||||
|
use std::sync::atomic::AtomicBool;
|
||||||
|
use std::sync::Arc;
|
||||||
use style_traits::viewport::ViewportConstraints;
|
use style_traits::viewport::ViewportConstraints;
|
||||||
use style_traits::CSSPixel;
|
use style_traits::CSSPixel;
|
||||||
use webrender_api;
|
use webrender_api;
|
||||||
|
@ -167,4 +169,5 @@ pub struct InitialCompositorState {
|
||||||
pub webrender_api: webrender_api::RenderApi,
|
pub webrender_api: webrender_api::RenderApi,
|
||||||
pub webvr_heartbeats: Vec<Box<dyn WebVRMainThreadHeartbeat>>,
|
pub webvr_heartbeats: Vec<Box<dyn WebVRMainThreadHeartbeat>>,
|
||||||
pub webxr_main_thread: webxr::MainThreadRegistry,
|
pub webxr_main_thread: webxr::MainThreadRegistry,
|
||||||
|
pub pending_wr_frame: Arc<AtomicBool>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -166,6 +166,7 @@ use std::marker::PhantomData;
|
||||||
use std::mem::replace;
|
use std::mem::replace;
|
||||||
use std::process;
|
use std::process;
|
||||||
use std::rc::{Rc, Weak};
|
use std::rc::{Rc, Weak};
|
||||||
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use style_traits::viewport::ViewportConstraints;
|
use style_traits::viewport::ViewportConstraints;
|
||||||
|
@ -546,6 +547,9 @@ pub struct InitialConstellationState {
|
||||||
|
|
||||||
/// Mechanism to force the compositor to process events.
|
/// Mechanism to force the compositor to process events.
|
||||||
pub event_loop_waker: Option<Box<dyn EventLoopWaker>>,
|
pub event_loop_waker: Option<Box<dyn EventLoopWaker>>,
|
||||||
|
|
||||||
|
/// A flag share with the compositor to indicate that a WR frame is in progress.
|
||||||
|
pub pending_wr_frame: Arc<AtomicBool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Data needed for webdriver
|
/// Data needed for webdriver
|
||||||
|
@ -720,12 +724,17 @@ enum WebrenderMsg {
|
||||||
|
|
||||||
/// Accept messages from content processes that need to be relayed to the WebRender
|
/// Accept messages from content processes that need to be relayed to the WebRender
|
||||||
/// instance in the parent process.
|
/// instance in the parent process.
|
||||||
fn handle_webrender_message(webrender_api: &webrender_api::RenderApi, msg: WebrenderMsg) {
|
fn handle_webrender_message(
|
||||||
|
pending_wr_frame: &AtomicBool,
|
||||||
|
webrender_api: &webrender_api::RenderApi,
|
||||||
|
msg: WebrenderMsg,
|
||||||
|
) {
|
||||||
match msg {
|
match msg {
|
||||||
WebrenderMsg::Layout(script_traits::WebrenderMsg::SendInitialTransaction(
|
WebrenderMsg::Layout(script_traits::WebrenderMsg::SendInitialTransaction(
|
||||||
doc,
|
doc,
|
||||||
pipeline,
|
pipeline,
|
||||||
)) => {
|
)) => {
|
||||||
|
pending_wr_frame.store(true, Ordering::SeqCst);
|
||||||
let mut txn = webrender_api::Transaction::new();
|
let mut txn = webrender_api::Transaction::new();
|
||||||
txn.set_display_list(
|
txn.set_display_list(
|
||||||
webrender_api::Epoch(0),
|
webrender_api::Epoch(0),
|
||||||
|
@ -757,6 +766,7 @@ fn handle_webrender_message(webrender_api: &webrender_api::RenderApi, msg: Webre
|
||||||
data,
|
data,
|
||||||
descriptor,
|
descriptor,
|
||||||
)) => {
|
)) => {
|
||||||
|
pending_wr_frame.store(true, Ordering::SeqCst);
|
||||||
let mut txn = webrender_api::Transaction::new();
|
let mut txn = webrender_api::Transaction::new();
|
||||||
txn.set_display_list(
|
txn.set_display_list(
|
||||||
epoch,
|
epoch,
|
||||||
|
@ -881,10 +891,12 @@ where
|
||||||
ipc::channel().expect("ipc channel failure");
|
ipc::channel().expect("ipc channel failure");
|
||||||
|
|
||||||
let webrender_api = state.webrender_api_sender.create_api();
|
let webrender_api = state.webrender_api_sender.create_api();
|
||||||
|
let pending_wr_frame_clone = state.pending_wr_frame.clone();
|
||||||
ROUTER.add_route(
|
ROUTER.add_route(
|
||||||
webrender_ipc_receiver.to_opaque(),
|
webrender_ipc_receiver.to_opaque(),
|
||||||
Box::new(move |message| {
|
Box::new(move |message| {
|
||||||
handle_webrender_message(
|
handle_webrender_message(
|
||||||
|
&pending_wr_frame_clone,
|
||||||
&webrender_api,
|
&webrender_api,
|
||||||
WebrenderMsg::Layout(message.to().expect("conversion failure")),
|
WebrenderMsg::Layout(message.to().expect("conversion failure")),
|
||||||
)
|
)
|
||||||
|
@ -892,10 +904,12 @@ where
|
||||||
);
|
);
|
||||||
|
|
||||||
let webrender_api = state.webrender_api_sender.create_api();
|
let webrender_api = state.webrender_api_sender.create_api();
|
||||||
|
let pending_wr_frame_clone = state.pending_wr_frame.clone();
|
||||||
ROUTER.add_route(
|
ROUTER.add_route(
|
||||||
webrender_image_ipc_receiver.to_opaque(),
|
webrender_image_ipc_receiver.to_opaque(),
|
||||||
Box::new(move |message| {
|
Box::new(move |message| {
|
||||||
handle_webrender_message(
|
handle_webrender_message(
|
||||||
|
&pending_wr_frame_clone,
|
||||||
&webrender_api,
|
&webrender_api,
|
||||||
WebrenderMsg::Net(message.to().expect("conversion failure")),
|
WebrenderMsg::Net(message.to().expect("conversion failure")),
|
||||||
)
|
)
|
||||||
|
|
|
@ -115,6 +115,7 @@ use std::borrow::Cow;
|
||||||
use std::cmp::max;
|
use std::cmp::max;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
use std::sync::atomic::AtomicBool;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
#[cfg(not(target_os = "windows"))]
|
#[cfg(not(target_os = "windows"))]
|
||||||
use surfman::platform::default::device::Device as HWDevice;
|
use surfman::platform::default::device::Device as HWDevice;
|
||||||
|
@ -505,6 +506,8 @@ where
|
||||||
device_pixel_ratio: Scale::new(device_pixel_ratio),
|
device_pixel_ratio: Scale::new(device_pixel_ratio),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let pending_wr_frame = Arc::new(AtomicBool::new(false));
|
||||||
|
|
||||||
// Create the constellation, which maintains the engine
|
// Create the constellation, which maintains the engine
|
||||||
// pipelines, including the script and layout threads, as well
|
// pipelines, including the script and layout threads, as well
|
||||||
// as the navigation context.
|
// as the navigation context.
|
||||||
|
@ -527,6 +530,7 @@ where
|
||||||
glplayer_threads,
|
glplayer_threads,
|
||||||
event_loop_waker,
|
event_loop_waker,
|
||||||
window_size,
|
window_size,
|
||||||
|
pending_wr_frame.clone(),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Send the constellation's swmanager sender to service worker manager thread
|
// Send the constellation's swmanager sender to service worker manager thread
|
||||||
|
@ -553,6 +557,7 @@ where
|
||||||
webrender_api,
|
webrender_api,
|
||||||
webvr_heartbeats,
|
webvr_heartbeats,
|
||||||
webxr_main_thread,
|
webxr_main_thread,
|
||||||
|
pending_wr_frame,
|
||||||
},
|
},
|
||||||
opts.output_file.clone(),
|
opts.output_file.clone(),
|
||||||
opts.is_running_problem_test,
|
opts.is_running_problem_test,
|
||||||
|
@ -865,6 +870,7 @@ fn create_constellation(
|
||||||
glplayer_threads: Option<GLPlayerThreads>,
|
glplayer_threads: Option<GLPlayerThreads>,
|
||||||
event_loop_waker: Option<Box<dyn EventLoopWaker>>,
|
event_loop_waker: Option<Box<dyn EventLoopWaker>>,
|
||||||
initial_window_size: WindowSizeData,
|
initial_window_size: WindowSizeData,
|
||||||
|
pending_wr_frame: Arc<AtomicBool>,
|
||||||
) -> (Sender<ConstellationMsg>, SWManagerSenders) {
|
) -> (Sender<ConstellationMsg>, SWManagerSenders) {
|
||||||
// Global configuration options, parsed from the command line.
|
// Global configuration options, parsed from the command line.
|
||||||
let opts = opts::get();
|
let opts = opts::get();
|
||||||
|
@ -907,6 +913,7 @@ fn create_constellation(
|
||||||
glplayer_threads,
|
glplayer_threads,
|
||||||
player_context,
|
player_context,
|
||||||
event_loop_waker,
|
event_loop_waker,
|
||||||
|
pending_wr_frame,
|
||||||
};
|
};
|
||||||
|
|
||||||
let (canvas_chan, ipc_canvas_chan) = canvas::canvas_paint_thread::CanvasPaintThread::start();
|
let (canvas_chan, ipc_canvas_chan) = canvas::canvas_paint_thread::CanvasPaintThread::start();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue