mirror of
https://github.com/servo/servo.git
synced 2025-07-23 15:23:42 +01:00
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:
parent
a58d816319
commit
8a0c7487e7
6 changed files with 83 additions and 9 deletions
10
Cargo.lock
generated
10
Cargo.lock
generated
|
@ -4780,6 +4780,15 @@ version = "0.3.0"
|
|||
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"
|
||||
|
@ -6207,6 +6216,7 @@ dependencies = [
|
|||
"net_traits",
|
||||
"nix",
|
||||
"ohos-sys",
|
||||
"ohos-vsync",
|
||||
"raw-window-handle",
|
||||
"serde_json",
|
||||
"servo-media",
|
||||
|
|
|
@ -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"] }
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {}
|
||||
|
||||
|
|
|
@ -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(())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue