mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
libservo: Don't bounce ready-to-present frame notifications to the Constellation (#35369)
Instead of telling the Constellation to tell the embedder that new frames are ready, have the compositor tell the embedder directly. This should reduce frame latency. Now, after processing compositor updates, run any pending `WebView::new_frame_ready` delegate methods. This change also removes the `refresh` call from the Java interface as that was the only other place that the compositor was rendering the WebRender scene outside of event looping spinning. This `refresh` call was completely unused. Signed-off-by: Martin Robinson <mrobinson@igalia.com>
This commit is contained in:
parent
8c46749740
commit
71bfd2d13f
11 changed files with 26 additions and 63 deletions
|
@ -3,6 +3,7 @@
|
||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use std::cell::OnceCell;
|
use std::cell::OnceCell;
|
||||||
|
use std::collections::hash_set::Iter;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::fs::{create_dir_all, File};
|
use std::fs::{create_dir_all, File};
|
||||||
|
@ -212,8 +213,9 @@ pub struct IOCompositor {
|
||||||
/// The number of frames pending to receive from WebRender.
|
/// The number of frames pending to receive from WebRender.
|
||||||
pending_frames: usize,
|
pending_frames: usize,
|
||||||
|
|
||||||
/// Waiting for external code to call present.
|
/// A list of [`WebViewId`]s of WebViews that have new frames ready that are waiting to
|
||||||
waiting_on_present: bool,
|
/// be presented.
|
||||||
|
webviews_waiting_on_present: FnvHashSet<WebViewId>,
|
||||||
|
|
||||||
/// The [`Instant`] of the last animation tick, used to avoid flooding the Constellation and
|
/// The [`Instant`] of the last animation tick, used to avoid flooding the Constellation and
|
||||||
/// ScriptThread with a deluge of animation ticks.
|
/// ScriptThread with a deluge of animation ticks.
|
||||||
|
@ -403,7 +405,7 @@ impl IOCompositor {
|
||||||
exit_after_load,
|
exit_after_load,
|
||||||
convert_mouse_to_touch,
|
convert_mouse_to_touch,
|
||||||
pending_frames: 0,
|
pending_frames: 0,
|
||||||
waiting_on_present: false,
|
webviews_waiting_on_present: Default::default(),
|
||||||
last_animation_tick: Instant::now(),
|
last_animation_tick: Instant::now(),
|
||||||
version_string,
|
version_string,
|
||||||
};
|
};
|
||||||
|
@ -424,6 +426,10 @@ impl IOCompositor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn webviews_waiting_on_present(&self) -> Iter<'_, WebViewId> {
|
||||||
|
self.webviews_waiting_on_present.iter()
|
||||||
|
}
|
||||||
|
|
||||||
fn update_cursor(&mut self, result: CompositorHitTestResult) {
|
fn update_cursor(&mut self, result: CompositorHitTestResult) {
|
||||||
let cursor = match result.cursor {
|
let cursor = match result.cursor {
|
||||||
Some(cursor) if cursor != self.cursor => cursor,
|
Some(cursor) if cursor != self.cursor => cursor,
|
||||||
|
@ -1976,7 +1982,7 @@ impl IOCompositor {
|
||||||
target: CompositeTarget,
|
target: CompositeTarget,
|
||||||
page_rect: Option<Rect<f32, CSSPixel>>,
|
page_rect: Option<Rect<f32, CSSPixel>>,
|
||||||
) -> Result<Option<Image>, UnableToComposite> {
|
) -> Result<Option<Image>, UnableToComposite> {
|
||||||
if self.waiting_on_present {
|
if !self.webviews_waiting_on_present.is_empty() {
|
||||||
debug!("tried to composite while waiting on present");
|
debug!("tried to composite while waiting on present");
|
||||||
return Err(UnableToComposite::NotReadyToPaintImage(
|
return Err(UnableToComposite::NotReadyToPaintImage(
|
||||||
NotReadyToPaint::WaitingOnConstellation,
|
NotReadyToPaint::WaitingOnConstellation,
|
||||||
|
@ -2146,15 +2152,11 @@ impl IOCompositor {
|
||||||
let _span =
|
let _span =
|
||||||
tracing::trace_span!("ConstellationMsg::ReadyToPresent", servo_profiling = true)
|
tracing::trace_span!("ConstellationMsg::ReadyToPresent", servo_profiling = true)
|
||||||
.entered();
|
.entered();
|
||||||
|
|
||||||
// Notify embedder that servo is ready to present.
|
// Notify embedder that servo is ready to present.
|
||||||
// Embedder should call `present` to tell compositor to continue rendering.
|
// Embedder should call `present` to tell compositor to continue rendering.
|
||||||
self.waiting_on_present = true;
|
self.webviews_waiting_on_present
|
||||||
let webview_ids = self.webviews.painting_order().map(|(&id, _)| id);
|
.extend(self.webviews.painting_order().map(|(&id, _)| id));
|
||||||
let msg = ConstellationMsg::ReadyToPresent(webview_ids.collect());
|
|
||||||
if let Err(e) = self.constellation_chan.send(msg) {
|
|
||||||
warn!("Sending event to constellation failed ({:?}).", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.composition_request = CompositionRequest::NoCompositingNecessary;
|
self.composition_request = CompositionRequest::NoCompositingNecessary;
|
||||||
|
|
||||||
self.process_animations(true);
|
self.process_animations(true);
|
||||||
|
@ -2245,7 +2247,7 @@ impl IOCompositor {
|
||||||
let _span =
|
let _span =
|
||||||
tracing::trace_span!("Compositor Present Surface", servo_profiling = true).entered();
|
tracing::trace_span!("Compositor Present Surface", servo_profiling = true).entered();
|
||||||
self.rendering_context.present();
|
self.rendering_context.present();
|
||||||
self.waiting_on_present = false;
|
self.webviews_waiting_on_present.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn composite_if_necessary(&mut self, reason: CompositingReason) {
|
fn composite_if_necessary(&mut self, reason: CompositingReason) {
|
||||||
|
|
|
@ -1459,16 +1459,6 @@ where
|
||||||
FromCompositorMsg::SetWebViewThrottled(webview_id, throttled) => {
|
FromCompositorMsg::SetWebViewThrottled(webview_id, throttled) => {
|
||||||
self.set_webview_throttled(webview_id, throttled);
|
self.set_webview_throttled(webview_id, throttled);
|
||||||
},
|
},
|
||||||
FromCompositorMsg::ReadyToPresent(webview_ids) => {
|
|
||||||
#[cfg(feature = "tracing")]
|
|
||||||
let _span = tracing::trace_span!(
|
|
||||||
"FromCompositorMsg::ReadyToPresent",
|
|
||||||
servo_profiling = true,
|
|
||||||
)
|
|
||||||
.entered();
|
|
||||||
self.embedder_proxy
|
|
||||||
.send(EmbedderMsg::ReadyToPresent(webview_ids));
|
|
||||||
},
|
|
||||||
FromCompositorMsg::Gamepad(gamepad_event) => {
|
FromCompositorMsg::Gamepad(gamepad_event) => {
|
||||||
self.handle_gamepad_msg(gamepad_event);
|
self.handle_gamepad_msg(gamepad_event);
|
||||||
},
|
},
|
||||||
|
|
|
@ -90,7 +90,6 @@ mod from_compositor {
|
||||||
Self::MediaSessionAction(_) => target!("MediaSessionAction"),
|
Self::MediaSessionAction(_) => target!("MediaSessionAction"),
|
||||||
Self::SetWebViewThrottled(_, _) => target!("SetWebViewThrottled"),
|
Self::SetWebViewThrottled(_, _) => target!("SetWebViewThrottled"),
|
||||||
Self::IMEDismissed => target!("IMEDismissed"),
|
Self::IMEDismissed => target!("IMEDismissed"),
|
||||||
Self::ReadyToPresent(..) => target!("ReadyToPresent"),
|
|
||||||
Self::Gamepad(..) => target!("Gamepad"),
|
Self::Gamepad(..) => target!("Gamepad"),
|
||||||
Self::Clipboard(..) => target!("Clipboard"),
|
Self::Clipboard(..) => target!("Clipboard"),
|
||||||
}
|
}
|
||||||
|
@ -248,7 +247,6 @@ mod from_script {
|
||||||
Self::MediaSessionEvent(..) => target_variant!("MediaSessionEvent"),
|
Self::MediaSessionEvent(..) => target_variant!("MediaSessionEvent"),
|
||||||
Self::OnDevtoolsStarted(..) => target_variant!("OnDevtoolsStarted"),
|
Self::OnDevtoolsStarted(..) => target_variant!("OnDevtoolsStarted"),
|
||||||
Self::RequestDevtoolsConnection(..) => target_variant!("RequestDevtoolsConnection"),
|
Self::RequestDevtoolsConnection(..) => target_variant!("RequestDevtoolsConnection"),
|
||||||
Self::ReadyToPresent(..) => target_variant!("ReadyToPresent"),
|
|
||||||
Self::EventDelivered(..) => target_variant!("EventDelivered"),
|
Self::EventDelivered(..) => target_variant!("EventDelivered"),
|
||||||
Self::PlayGamepadHapticEffect(..) => target_variant!("PlayGamepadHapticEffect"),
|
Self::PlayGamepadHapticEffect(..) => target_variant!("PlayGamepadHapticEffect"),
|
||||||
Self::StopGamepadHapticEffect(..) => target_variant!("StopGamepadHapticEffect"),
|
Self::StopGamepadHapticEffect(..) => target_variant!("StopGamepadHapticEffect"),
|
||||||
|
|
|
@ -643,6 +643,7 @@ impl Servo {
|
||||||
}
|
}
|
||||||
|
|
||||||
self.compositor.borrow_mut().perform_updates();
|
self.compositor.borrow_mut().perform_updates();
|
||||||
|
self.send_new_frame_ready_messages();
|
||||||
|
|
||||||
if self.compositor.borrow().shutdown_state == ShutdownState::FinishedShuttingDown {
|
if self.compositor.borrow().shutdown_state == ShutdownState::FinishedShuttingDown {
|
||||||
return false;
|
return false;
|
||||||
|
@ -651,6 +652,17 @@ impl Servo {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn send_new_frame_ready_messages(&self) {
|
||||||
|
for webview in self
|
||||||
|
.compositor
|
||||||
|
.borrow()
|
||||||
|
.webviews_waiting_on_present()
|
||||||
|
.filter_map(|id| self.get_webview_handle(*id))
|
||||||
|
{
|
||||||
|
webview.delegate().notify_new_frame_ready(webview);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn pinch_zoom_level(&self) -> f32 {
|
pub fn pinch_zoom_level(&self) -> f32 {
|
||||||
self.compositor.borrow_mut().pinch_zoom_level().get()
|
self.compositor.borrow_mut().pinch_zoom_level().get()
|
||||||
}
|
}
|
||||||
|
@ -987,13 +999,6 @@ impl Servo {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
EmbedderMsg::ReadyToPresent(webview_ids) => {
|
|
||||||
for webview_id in webview_ids {
|
|
||||||
if let Some(webview) = self.get_webview_handle(webview_id) {
|
|
||||||
webview.delegate().notify_new_frame_ready(webview);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
EmbedderMsg::EventDelivered(webview_id, event) => {
|
EmbedderMsg::EventDelivered(webview_id, event) => {
|
||||||
if let Some(webview) = self.get_webview_handle(webview_id) {
|
if let Some(webview) = self.get_webview_handle(webview_id) {
|
||||||
webview.delegate().notify_event_delivered(webview, event);
|
webview.delegate().notify_event_delivered(webview, event);
|
||||||
|
|
|
@ -441,10 +441,6 @@ impl WebView {
|
||||||
self.inner().compositor.borrow_mut().capture_webrender();
|
self.inner().compositor.borrow_mut().capture_webrender();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn composite(&self) {
|
|
||||||
self.inner().compositor.borrow_mut().composite();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn toggle_sampling_profiler(&self, rate: Duration, max_duration: Duration) {
|
pub fn toggle_sampling_profiler(&self, rate: Duration, max_duration: Duration) {
|
||||||
self.inner()
|
self.inner()
|
||||||
.constellation_proxy
|
.constellation_proxy
|
||||||
|
|
|
@ -84,8 +84,6 @@ pub enum ConstellationMsg {
|
||||||
SetWebViewThrottled(TopLevelBrowsingContextId, bool),
|
SetWebViewThrottled(TopLevelBrowsingContextId, bool),
|
||||||
/// Virtual keyboard was dismissed
|
/// Virtual keyboard was dismissed
|
||||||
IMEDismissed,
|
IMEDismissed,
|
||||||
/// Notify the embedder that it needs to present a new frame.
|
|
||||||
ReadyToPresent(Vec<WebViewId>),
|
|
||||||
/// Gamepad state has changed
|
/// Gamepad state has changed
|
||||||
Gamepad(GamepadEvent),
|
Gamepad(GamepadEvent),
|
||||||
/// Inform the constellation of a clipboard event.
|
/// Inform the constellation of a clipboard event.
|
||||||
|
@ -133,7 +131,6 @@ impl ConstellationMsg {
|
||||||
SetWebViewThrottled(..) => "SetWebViewThrottled",
|
SetWebViewThrottled(..) => "SetWebViewThrottled",
|
||||||
IMEDismissed => "IMEDismissed",
|
IMEDismissed => "IMEDismissed",
|
||||||
ClearCache => "ClearCache",
|
ClearCache => "ClearCache",
|
||||||
ReadyToPresent(..) => "ReadyToPresent",
|
|
||||||
Gamepad(..) => "Gamepad",
|
Gamepad(..) => "Gamepad",
|
||||||
Clipboard(..) => "Clipboard",
|
Clipboard(..) => "Clipboard",
|
||||||
}
|
}
|
||||||
|
|
|
@ -250,8 +250,6 @@ pub enum EmbedderMsg {
|
||||||
OnDevtoolsStarted(Result<u16, ()>, String),
|
OnDevtoolsStarted(Result<u16, ()>, String),
|
||||||
/// Ask the user to allow a devtools client to connect.
|
/// Ask the user to allow a devtools client to connect.
|
||||||
RequestDevtoolsConnection(IpcSender<AllowOrDeny>),
|
RequestDevtoolsConnection(IpcSender<AllowOrDeny>),
|
||||||
/// Notify the embedder that it needs to present a new frame.
|
|
||||||
ReadyToPresent(Vec<WebViewId>),
|
|
||||||
/// The given event was delivered to a pipeline in the given browser.
|
/// The given event was delivered to a pipeline in the given browser.
|
||||||
EventDelivered(WebViewId, CompositorEventVariant),
|
EventDelivered(WebViewId, CompositorEventVariant),
|
||||||
/// Request to play a haptic effect on a connected gamepad.
|
/// Request to play a haptic effect on a connected gamepad.
|
||||||
|
@ -314,7 +312,6 @@ impl Debug for EmbedderMsg {
|
||||||
EmbedderMsg::OnDevtoolsStarted(..) => write!(f, "OnDevtoolsStarted"),
|
EmbedderMsg::OnDevtoolsStarted(..) => write!(f, "OnDevtoolsStarted"),
|
||||||
EmbedderMsg::RequestDevtoolsConnection(..) => write!(f, "RequestDevtoolsConnection"),
|
EmbedderMsg::RequestDevtoolsConnection(..) => write!(f, "RequestDevtoolsConnection"),
|
||||||
EmbedderMsg::ShowContextMenu(..) => write!(f, "ShowContextMenu"),
|
EmbedderMsg::ShowContextMenu(..) => write!(f, "ShowContextMenu"),
|
||||||
EmbedderMsg::ReadyToPresent(..) => write!(f, "ReadyToPresent"),
|
|
||||||
EmbedderMsg::EventDelivered(..) => write!(f, "HitTestedEvent"),
|
EmbedderMsg::EventDelivered(..) => write!(f, "HitTestedEvent"),
|
||||||
EmbedderMsg::PlayGamepadHapticEffect(..) => write!(f, "PlayGamepadHapticEffect"),
|
EmbedderMsg::PlayGamepadHapticEffect(..) => write!(f, "PlayGamepadHapticEffect"),
|
||||||
EmbedderMsg::StopGamepadHapticEffect(..) => write!(f, "StopGamepadHapticEffect"),
|
EmbedderMsg::StopGamepadHapticEffect(..) => write!(f, "StopGamepadHapticEffect"),
|
||||||
|
|
|
@ -222,15 +222,6 @@ pub extern "C" fn Java_org_servo_servoview_JNIServo_stop<'local>(
|
||||||
call(&mut env, |s| s.stop());
|
call(&mut env, |s| s.stop());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn Java_org_servo_servoview_JNIServo_refresh<'local>(
|
|
||||||
mut env: JNIEnv<'local>,
|
|
||||||
_class: JClass<'local>,
|
|
||||||
) {
|
|
||||||
debug!("refresh");
|
|
||||||
call(&mut env, |s| s.refresh());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn Java_org_servo_servoview_JNIServo_goBack<'local>(
|
pub extern "C" fn Java_org_servo_servoview_JNIServo_goBack<'local>(
|
||||||
mut env: JNIEnv<'local>,
|
mut env: JNIEnv<'local>,
|
||||||
|
|
|
@ -401,13 +401,6 @@ impl RunningAppState {
|
||||||
self.perform_updates();
|
self.perform_updates();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Redraw the page.
|
|
||||||
pub fn refresh(&self) {
|
|
||||||
info!("refresh");
|
|
||||||
self.active_webview().composite();
|
|
||||||
self.perform_updates();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Stop loading the page.
|
/// Stop loading the page.
|
||||||
pub fn stop(&self) {
|
pub fn stop(&self) {
|
||||||
warn!("TODO can't stop won't stop");
|
warn!("TODO can't stop won't stop");
|
||||||
|
|
|
@ -35,8 +35,6 @@ public class JNIServo {
|
||||||
|
|
||||||
public native void stop();
|
public native void stop();
|
||||||
|
|
||||||
public native void refresh();
|
|
||||||
|
|
||||||
public native void goBack();
|
public native void goBack();
|
||||||
|
|
||||||
public native void goForward();
|
public native void goForward();
|
||||||
|
|
|
@ -87,10 +87,6 @@ public class Servo {
|
||||||
mRunCallback.inGLThread(() -> mJNI.resize(coords));
|
mRunCallback.inGLThread(() -> mJNI.resize(coords));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void refresh() {
|
|
||||||
mRunCallback.inGLThread(() -> mJNI.refresh());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void reload() {
|
public void reload() {
|
||||||
mRunCallback.inGLThread(() -> mJNI.reload());
|
mRunCallback.inGLThread(() -> mJNI.reload());
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue