ohos: Present on vsync signals (#33117)

Rely on callbacks from the vertical synchronization driver,
to drive presentation.
Future commits will base animation updates and touchless
gestures like fling off these vsync events.

Signed-off-by: Jonathan Schwender <jonathan.schwender@huawei.com>
Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>
This commit is contained in:
Jonathan Schwender 2024-08-30 21:25:50 +08:00 committed by GitHub
parent a58d816319
commit 8a0c7487e7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 83 additions and 9 deletions

View file

@ -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) {}