aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock10
-rw-r--r--ports/servoshell/Cargo.toml1
-rw-r--r--ports/servoshell/egl/android.rs6
-rw-r--r--ports/servoshell/egl/host_trait.rs8
-rw-r--r--ports/servoshell/egl/ohos.rs54
-rw-r--r--ports/servoshell/egl/servo_glue.rs13
6 files changed, 83 insertions, 9 deletions
diff --git a/Cargo.lock b/Cargo.lock
index fac0ef27045..10ab7b05da4 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4781,6 +4781,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f2fd4c1b349c53cd06dfa959bb53076453960d793961caafd367e64c3bb5522"
[[package]]
+name = "ohos-vsync"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5871e38034a33e8d43c711a40d39e24fd3500f43b61b9269b8586f608a70aec3"
+dependencies = [
+ "ohos-sys",
+]
+
+[[package]]
name = "once_cell"
version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -6207,6 +6216,7 @@ dependencies = [
"net_traits",
"nix",
"ohos-sys",
+ "ohos-vsync",
"raw-window-handle",
"serde_json",
"servo-media",
diff --git a/ports/servoshell/Cargo.toml b/ports/servoshell/Cargo.toml
index 1d7826cf333..c898206bda9 100644
--- a/ports/servoshell/Cargo.toml
+++ b/ports/servoshell/Cargo.toml
@@ -81,6 +81,7 @@ hilog = "0.1.0"
napi-derive-ohos = "0.0.9"
napi-ohos = "0.1"
ohos-sys = { version = "0.3.0", features = ["xcomponent"] }
+ohos-vsync = "0.1"
[target.'cfg(any(target_os = "android", target_env = "ohos"))'.dependencies]
nix = { workspace = true, features = ["fs"] }
diff --git a/ports/servoshell/egl/android.rs b/ports/servoshell/egl/android.rs
index 865222d910e..2e54b43e518 100644
--- a/ports/servoshell/egl/android.rs
+++ b/ports/servoshell/egl/android.rs
@@ -196,7 +196,11 @@ pub extern "C" fn Java_org_servo_servoview_JNIServo_performUpdates<'local>(
_class: JClass<'local>,
) {
debug!("performUpdates");
- call(&mut env, |s| s.perform_updates());
+ call(&mut env, |s| {
+ s.perform_updates()?;
+ s.present_if_needed();
+ Ok(())
+ });
}
#[no_mangle]
diff --git a/ports/servoshell/egl/host_trait.rs b/ports/servoshell/egl/host_trait.rs
index 361d431d237..99fac91356c 100644
--- a/ports/servoshell/egl/host_trait.rs
+++ b/ports/servoshell/egl/host_trait.rs
@@ -39,7 +39,13 @@ pub trait HostTrait {
/// Page animation state has changed. If animating, it's recommended
/// that the embedder doesn't wait for the wake function to be called
/// to call perform_updates. Usually, it means doing:
- /// while true { servo.perform_updates() }. This will end up calling flush
+ /// ```rust
+ /// while true {
+ /// servo.perform_updates();
+ /// servo.present_if_needed();
+ /// }
+ /// ```
+ /// . This will end up calling flush
/// which will call swap_buffer which will be blocking long enough to limit
/// drawing at 60 FPS.
/// If not animating, call perform_updates only when needed (when the embedder
diff --git a/ports/servoshell/egl/ohos.rs b/ports/servoshell/egl/ohos.rs
index 425471cd4ce..0864e16b27f 100644
--- a/ports/servoshell/egl/ohos.rs
+++ b/ports/servoshell/egl/ohos.rs
@@ -11,7 +11,7 @@ use std::thread;
use std::thread::sleep;
use std::time::Duration;
-use log::{debug, error, info, warn, LevelFilter};
+use log::{debug, error, info, trace, warn, LevelFilter};
use napi_derive_ohos::{module_exports, napi};
use napi_ohos::threadsafe_function::{
ErrorStrategy, ThreadsafeFunction, ThreadsafeFunctionCallMode,
@@ -93,6 +93,7 @@ enum ServoAction {
pointer_id: i32,
},
Initialize(Box<InitOpts>),
+ Vsync,
}
// Todo: Need to check if OnceLock is suitable, or if the TS function can be destroyed, e.g.
@@ -132,6 +133,13 @@ impl ServoAction {
Initialize(_init_opts) => {
panic!("Received Initialize event, even though servo is already initialized")
},
+
+ Vsync => {
+ servo.perform_updates().expect("Infallible");
+ servo.present_if_needed();
+ // Todo: perform_updates() (before or after present) if animating?
+ Ok(())
+ },
};
if let Err(e) = res {
error!("Failed to do {self:?} with error {e}");
@@ -139,6 +147,31 @@ impl ServoAction {
}
}
+/// Vsync callback
+///
+/// # Safety
+///
+/// The caller should pass a valid raw NativeVsync object to us via
+/// `native_vsync.request_raw_callback_with_self(Some(on_vsync_cb))`
+unsafe extern "C" fn on_vsync_cb(
+ timestamp: ::core::ffi::c_longlong,
+ data: *mut ::core::ffi::c_void,
+) {
+ trace!("Vsync callback at time {timestamp}");
+ // SAFETY: We require the function registering us as a callback
+ let (native_vsync, data) = unsafe {
+ let native = ohos_vsync::NativeVsync::from_raw(data.cast());
+ (native, 0)
+ };
+ call(ServoAction::Vsync).unwrap();
+ // Todo: Do we have a callback for when the frame finished rendering?
+ unsafe {
+ native_vsync
+ .request_raw_callback_with_self(Some(on_vsync_cb))
+ .unwrap();
+ }
+}
+
static SERVO_CHANNEL: OnceLock<Sender<ServoAction>> = OnceLock::new();
#[no_mangle]
@@ -148,6 +181,9 @@ pub extern "C" fn on_surface_created_cb(xcomponent: *mut OH_NativeXComponent, wi
let xc_wrapper = XComponentWrapper(xcomponent);
let window_wrapper = WindowWrapper(window);
+ // Todo: Perhaps it would be better to move this thread into the vsync signal thread.
+ // This would allow us to save one thread and the IPC for the vsync signal.
+ //
// Each thread will send its id via the channel
let _main_surface_thread = thread::spawn(move || {
let (tx, rx): (Sender<ServoAction>, Receiver<ServoAction>) = mpsc::channel();
@@ -178,9 +214,19 @@ pub extern "C" fn on_surface_created_cb(xcomponent: *mut OH_NativeXComponent, wi
.expect("Servo initialization failed");
info!("Surface created!");
+ let native_vsync =
+ ohos_vsync::NativeVsync::new("ServoVsync").expect("Failed to create NativeVsync");
+ // get_period() returns an error - perhaps we need to wait until the first callback?
+ // info!("Native vsync period is {} nanoseconds", native_vsync.get_period().unwrap());
+ unsafe {
+ native_vsync
+ .request_raw_callback_with_self(Some(on_vsync_cb))
+ .expect("Failed to request vsync callback")
+ }
+ info!("Enabled Vsync!");
while let Ok(action) = rx.recv() {
- info!("Wakeup message received!");
+ trace!("Wakeup message received!");
action.do_action(&mut servo);
}
@@ -513,7 +559,9 @@ impl HostTrait for HostCallbacks {
fn on_history_changed(&self, can_go_back: bool, can_go_forward: bool) {}
- fn on_animating_changed(&self, animating: bool) {}
+ fn on_animating_changed(&self, animating: bool) {
+ // todo: should we tell the vsync thread that it should perform updates?
+ }
fn on_shutdown_complete(&self) {}
diff --git a/ports/servoshell/egl/servo_glue.rs b/ports/servoshell/egl/servo_glue.rs
index 13022145fe5..48e3954bdb2 100644
--- a/ports/servoshell/egl/servo_glue.rs
+++ b/ports/servoshell/egl/servo_glue.rs
@@ -82,6 +82,7 @@ pub struct ServoGlue {
rendering_context: RenderingContext,
servo: Servo<ServoWindowCallbacks>,
batch_mode: bool,
+ need_present: bool,
callbacks: Rc<ServoWindowCallbacks>,
events: Vec<EmbedderEvent>,
context_menu_sender: Option<IpcSender<ContextMenuResult>>,
@@ -110,6 +111,7 @@ impl ServoGlue {
rendering_context,
servo,
batch_mode: false,
+ need_present: false,
callbacks,
events: vec![],
context_menu_sender: None,
@@ -432,7 +434,6 @@ impl ServoGlue {
fn handle_servo_events(&mut self) -> Result<(), &'static str> {
let mut need_update = false;
- let mut need_present = false;
for (browser_id, event) in self.servo.get_events() {
match event {
EmbedderMsg::ChangePageTitle(title) => {
@@ -611,7 +612,7 @@ impl ServoGlue {
self.callbacks.host_callbacks.on_panic(reason, backtrace);
},
EmbedderMsg::ReadyToPresent(_webview_ids) => {
- need_present = true;
+ self.need_present = true;
},
EmbedderMsg::Status(..) |
EmbedderMsg::SelectFiles(..) |
@@ -632,10 +633,14 @@ impl ServoGlue {
if need_update {
let _ = self.perform_updates();
}
- if need_present {
+ Ok(())
+ }
+
+ pub fn present_if_needed(&mut self) {
+ if self.need_present {
+ self.need_present = false;
self.servo.present();
}
- Ok(())
}
}