mirror of
https://github.com/servo/servo.git
synced 2025-08-23 14:25:33 +01:00
libservo: Expose SoftwareRenderingContext
and WindowRenderingContext
(#35501)
Expose two easy-to-use wrappers around `SurfmanRenderingContext` that make the API simpler to use: - `WindowRenderingContext`: This `RenderingContext` is a newtype around `SurfmanRenderingContext` takes a `raw-window-handle` display and window and creates a full window rendering context. - `SoftwareRenderingContext`: is wraps `SurfmanRenderingContext` and adds a swap chain in order to expose a software GL rendering context. Signed-off-by: Martin Robinson <mrobinson@igalia.com>
This commit is contained in:
parent
73507f58e6
commit
f34f2d9d0a
18 changed files with 514 additions and 470 deletions
|
@ -8,6 +8,7 @@ mod resources;
|
|||
mod simpleservo;
|
||||
|
||||
use std::os::raw::{c_char, c_int, c_void};
|
||||
use std::ptr::NonNull;
|
||||
use std::sync::Arc;
|
||||
|
||||
use android_logger::{self, Config, FilterBuilder};
|
||||
|
@ -15,6 +16,9 @@ use jni::objects::{GlobalRef, JClass, JObject, JString, JValue, JValueOwned};
|
|||
use jni::sys::{jboolean, jfloat, jint, jobject};
|
||||
use jni::{JNIEnv, JavaVM};
|
||||
use log::{debug, error, info, warn};
|
||||
use raw_window_handle::{
|
||||
AndroidDisplayHandle, AndroidNdkWindowHandle, RawDisplayHandle, RawWindowHandle,
|
||||
};
|
||||
use servo::{LoadStatus, MediaSessionActionType};
|
||||
use simpleservo::{
|
||||
DeviceIntRect, EventLoopWaker, InitOptions, InputMethodType, MediaSessionPlaybackState,
|
||||
|
@ -391,12 +395,15 @@ pub extern "C" fn Java_org_servo_servoview_JNIServo_resumeCompositor<'local>(
|
|||
coordinates: JObject<'local>,
|
||||
) {
|
||||
debug!("resumeCompositor");
|
||||
let widget = unsafe { ANativeWindow_fromSurface(env.get_native_interface(), surface.as_raw()) };
|
||||
let coords = jni_coords_to_rust_coords(&mut env, &coordinates);
|
||||
match coords {
|
||||
Ok(coords) => call(&mut env, |s| s.resume_compositor(widget, coords.clone())),
|
||||
Err(error) => throw(&mut env, &error),
|
||||
}
|
||||
let coords = match jni_coords_to_rust_coords(&mut env, &coordinates) {
|
||||
Ok(coords) => coords,
|
||||
Err(error) => return throw(&mut env, &error),
|
||||
};
|
||||
|
||||
let (_, window_handle) = display_and_window_handle(&mut env, &surface);
|
||||
call(&mut env, |s| {
|
||||
s.resume_compositor(window_handle, coords.clone())
|
||||
});
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
|
@ -795,17 +802,29 @@ fn get_options<'local>(
|
|||
None => None,
|
||||
};
|
||||
|
||||
let native_window =
|
||||
unsafe { ANativeWindow_fromSurface(env.get_native_interface(), surface.as_raw()) };
|
||||
|
||||
let (display_handle, window_handle) = display_and_window_handle(env, surface);
|
||||
let opts = InitOptions {
|
||||
args: args.unwrap_or(vec![]),
|
||||
url,
|
||||
coordinates,
|
||||
density,
|
||||
xr_discovery: None,
|
||||
surfman_integration: simpleservo::SurfmanIntegration::Widget(native_window),
|
||||
window_handle,
|
||||
display_handle,
|
||||
};
|
||||
|
||||
Ok((opts, log, log_str, gst_debug_str))
|
||||
}
|
||||
|
||||
fn display_and_window_handle(
|
||||
env: &mut JNIEnv<'_>,
|
||||
surface: &JObject<'_>,
|
||||
) -> (RawDisplayHandle, RawWindowHandle) {
|
||||
let native_window =
|
||||
unsafe { ANativeWindow_fromSurface(env.get_native_interface(), surface.as_raw()) };
|
||||
let native_window = NonNull::new(native_window).expect("Could not get Android window");
|
||||
(
|
||||
RawDisplayHandle::Android(AndroidDisplayHandle::new()),
|
||||
RawWindowHandle::AndroidNdk(AndroidNdkWindowHandle::new(native_window)),
|
||||
)
|
||||
}
|
||||
|
|
|
@ -4,19 +4,17 @@
|
|||
|
||||
use std::cell::RefCell;
|
||||
use std::mem;
|
||||
use std::os::raw::c_void;
|
||||
use std::rc::Rc;
|
||||
|
||||
use raw_window_handle::{DisplayHandle, RawDisplayHandle, RawWindowHandle, WindowHandle};
|
||||
use servo::compositing::CompositeTarget;
|
||||
pub use servo::webrender_api::units::DeviceIntRect;
|
||||
use servo::webrender_traits::SurfmanRenderingContext;
|
||||
/// The EventLoopWaker::wake function will be called from any thread.
|
||||
/// It will be called to notify embedder that some events are available,
|
||||
/// and that perform_updates need to be called
|
||||
pub use servo::EventLoopWaker;
|
||||
use servo::{self, resources, Servo};
|
||||
pub use servo::{InputMethodType, MediaSessionPlaybackState, PromptResult};
|
||||
use surfman::{Connection, SurfaceType};
|
||||
pub use servo::{InputMethodType, MediaSessionPlaybackState, PromptResult, WindowRenderingContext};
|
||||
|
||||
use crate::egl::android::resources::ResourceReaderInstance;
|
||||
use crate::egl::app_state::{
|
||||
|
@ -36,13 +34,8 @@ pub struct InitOptions {
|
|||
pub density: f32,
|
||||
#[cfg(feature = "webxr")]
|
||||
pub xr_discovery: Option<servo::webxr::Discovery>,
|
||||
pub surfman_integration: SurfmanIntegration,
|
||||
}
|
||||
|
||||
/// Controls how this embedding's rendering will integrate with the embedder.
|
||||
pub enum SurfmanIntegration {
|
||||
/// Render directly to a provided native widget (see surfman::NativeWidget).
|
||||
Widget(*mut c_void),
|
||||
pub window_handle: RawWindowHandle,
|
||||
pub display_handle: RawDisplayHandle,
|
||||
}
|
||||
|
||||
/// Initialize Servo. At that point, we need a valid GL context.
|
||||
|
@ -70,30 +63,20 @@ pub fn init(
|
|||
|
||||
crate::init_tracing(servoshell_preferences.tracing_filter.as_deref());
|
||||
|
||||
// Initialize surfman
|
||||
let connection = Connection::new().or(Err("Failed to create connection"))?;
|
||||
let adapter = connection
|
||||
.create_adapter()
|
||||
.or(Err("Failed to create adapter"))?;
|
||||
let surface_type = match init_opts.surfman_integration {
|
||||
SurfmanIntegration::Widget(native_widget) => {
|
||||
let native_widget = unsafe {
|
||||
connection.create_native_widget_from_ptr(
|
||||
native_widget,
|
||||
init_opts.coordinates.framebuffer.to_untyped(),
|
||||
)
|
||||
};
|
||||
SurfaceType::Widget { native_widget }
|
||||
},
|
||||
let (display_handle, window_handle) = unsafe {
|
||||
(
|
||||
DisplayHandle::borrow_raw(init_opts.display_handle),
|
||||
WindowHandle::borrow_raw(init_opts.window_handle),
|
||||
)
|
||||
};
|
||||
let rendering_context = SurfmanRenderingContext::create(&connection, &adapter, None)
|
||||
.or(Err("Failed to create surface manager"))?;
|
||||
let surface = rendering_context
|
||||
.create_surface(surface_type)
|
||||
.or(Err("Failed to create surface"))?;
|
||||
rendering_context
|
||||
.bind_surface(surface)
|
||||
.or(Err("Failed to bind surface"))?;
|
||||
let rendering_context = Rc::new(
|
||||
WindowRenderingContext::new(
|
||||
display_handle,
|
||||
window_handle,
|
||||
&init_opts.coordinates.framebuffer_size(),
|
||||
)
|
||||
.expect("Could not create RenderingContext"),
|
||||
);
|
||||
|
||||
let window_callbacks = Rc::new(ServoWindowCallbacks::new(
|
||||
callbacks,
|
||||
|
@ -110,7 +93,7 @@ pub fn init(
|
|||
let servo = Servo::new(
|
||||
opts,
|
||||
preferences,
|
||||
Rc::new(rendering_context.clone()),
|
||||
rendering_context.clone(),
|
||||
embedder_callbacks,
|
||||
window_callbacks.clone(),
|
||||
None,
|
||||
|
|
|
@ -3,12 +3,13 @@
|
|||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
use std::cell::{Ref, RefCell, RefMut};
|
||||
use std::collections::HashMap;
|
||||
use std::os::raw::c_void;
|
||||
use std::rc::Rc;
|
||||
|
||||
use dpi::PhysicalSize;
|
||||
use ipc_channel::ipc::IpcSender;
|
||||
use keyboard_types::{CompositionEvent, CompositionState};
|
||||
use log::{debug, error, info, warn};
|
||||
use raw_window_handle::{RawWindowHandle, WindowHandle};
|
||||
use servo::base::id::WebViewId;
|
||||
use servo::compositing::windowing::{
|
||||
AnimationState, EmbedderCoordinates, EmbedderMethods, WindowMethods,
|
||||
|
@ -17,14 +18,13 @@ use servo::euclid::{Box2D, Point2D, Rect, Scale, Size2D, Vector2D};
|
|||
use servo::servo_geometry::DeviceIndependentPixel;
|
||||
use servo::webrender_api::units::{DeviceIntRect, DeviceIntSize, DevicePixel, DeviceRect};
|
||||
use servo::webrender_api::ScrollLocation;
|
||||
use servo::webrender_traits::SurfmanRenderingContext;
|
||||
use servo::{
|
||||
AllowOrDenyRequest, ContextMenuResult, EmbedderProxy, EventLoopWaker, ImeEvent, InputEvent,
|
||||
InputMethodType, Key, KeyState, KeyboardEvent, LoadStatus, MediaSessionActionType,
|
||||
MediaSessionEvent, MouseButton, MouseButtonAction, MouseButtonEvent, MouseMoveEvent,
|
||||
NavigationRequest, PermissionRequest, PromptDefinition, PromptOrigin, PromptResult, Servo,
|
||||
ServoDelegate, ServoError, TouchAction, TouchEvent, TouchEventType, TouchId, WebView,
|
||||
WebViewDelegate,
|
||||
NavigationRequest, PermissionRequest, PromptDefinition, PromptOrigin, PromptResult,
|
||||
RenderingContext, Servo, ServoDelegate, ServoError, TouchAction, TouchEvent, TouchEventType,
|
||||
TouchId, WebView, WebViewDelegate, WindowRenderingContext,
|
||||
};
|
||||
use url::Url;
|
||||
|
||||
|
@ -51,6 +51,13 @@ impl Coordinates {
|
|||
framebuffer: Size2D::new(fb_width, fb_height),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn framebuffer_size(&self) -> PhysicalSize<u32> {
|
||||
PhysicalSize::new(
|
||||
self.framebuffer.width as u32,
|
||||
self.framebuffer.height as u32,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) struct ServoWindowCallbacks {
|
||||
|
@ -75,7 +82,7 @@ impl ServoWindowCallbacks {
|
|||
|
||||
pub struct RunningAppState {
|
||||
servo: Servo,
|
||||
rendering_context: SurfmanRenderingContext,
|
||||
rendering_context: Rc<WindowRenderingContext>,
|
||||
callbacks: Rc<ServoWindowCallbacks>,
|
||||
inner: RefCell<RunningAppStateInner>,
|
||||
/// servoshell specific preferences created during startup of the application.
|
||||
|
@ -283,7 +290,7 @@ impl WebViewDelegate for RunningAppState {
|
|||
impl RunningAppState {
|
||||
pub(super) fn new(
|
||||
initial_url: Option<String>,
|
||||
rendering_context: SurfmanRenderingContext,
|
||||
rendering_context: Rc<WindowRenderingContext>,
|
||||
servo: Servo,
|
||||
callbacks: Rc<ServoWindowCallbacks>,
|
||||
servoshell_preferences: ServoShellPreferences,
|
||||
|
@ -367,12 +374,6 @@ impl RunningAppState {
|
|||
self.servo.deinit();
|
||||
}
|
||||
|
||||
/// Returns the webrender surface management integration interface.
|
||||
/// This provides the embedder access to the current front buffer.
|
||||
pub fn surfman(&self) -> SurfmanRenderingContext {
|
||||
self.rendering_context.clone()
|
||||
}
|
||||
|
||||
/// This is the Servo heartbeat. This needs to be called
|
||||
/// everytime wakeup is called or when embedder wants Servo
|
||||
/// to act on its pending events.
|
||||
|
@ -429,10 +430,8 @@ impl RunningAppState {
|
|||
pub fn resize(&self, coordinates: Coordinates) {
|
||||
info!("resize to {:?}", coordinates);
|
||||
let size = coordinates.viewport.size;
|
||||
let _ = self
|
||||
.rendering_context
|
||||
.resize(Size2D::new(size.width, size.height))
|
||||
.inspect_err(|e| error!("Failed to resize rendering context: {e:?}"));
|
||||
self.rendering_context
|
||||
.resize(Size2D::new(size.width, size.height));
|
||||
*self.callbacks.coordinates.borrow_mut() = coordinates;
|
||||
self.active_webview().notify_rendering_context_resized();
|
||||
self.active_webview()
|
||||
|
@ -632,24 +631,17 @@ impl RunningAppState {
|
|||
}
|
||||
|
||||
pub fn pause_compositor(&self) {
|
||||
if let Err(e) = self.rendering_context.unbind_native_surface_from_context() {
|
||||
if let Err(e) = self.rendering_context.take_window() {
|
||||
warn!("Unbinding native surface from context failed ({:?})", e);
|
||||
}
|
||||
self.perform_updates();
|
||||
}
|
||||
|
||||
pub fn resume_compositor(&self, native_surface: *mut c_void, coords: Coordinates) {
|
||||
if native_surface.is_null() {
|
||||
panic!("null passed for native_surface");
|
||||
}
|
||||
let connection = self.rendering_context.connection();
|
||||
let native_widget = unsafe {
|
||||
connection
|
||||
.create_native_widget_from_ptr(native_surface, coords.framebuffer.to_untyped())
|
||||
};
|
||||
pub fn resume_compositor(&self, window_handle: RawWindowHandle, coords: Coordinates) {
|
||||
let window_handle = unsafe { WindowHandle::borrow_raw(window_handle) };
|
||||
if let Err(e) = self
|
||||
.rendering_context
|
||||
.bind_native_surface_to_context(native_widget)
|
||||
.set_window(window_handle, &coords.framebuffer_size())
|
||||
{
|
||||
warn!("Binding native surface to context failed ({:?})", e);
|
||||
}
|
||||
|
@ -688,6 +680,7 @@ impl RunningAppState {
|
|||
pub fn present_if_needed(&self) {
|
||||
if self.inner().need_present {
|
||||
self.inner_mut().need_present = false;
|
||||
self.active_webview().paint_immediately();
|
||||
self.servo.present();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,20 +2,22 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
use std::cell::RefCell;
|
||||
use std::convert::TryInto;
|
||||
use std::os::raw::c_void;
|
||||
use std::path::PathBuf;
|
||||
use std::ptr::NonNull;
|
||||
use std::rc::Rc;
|
||||
|
||||
use log::{debug, info};
|
||||
use raw_window_handle::{
|
||||
DisplayHandle, OhosDisplayHandle, OhosNdkWindowHandle, RawDisplayHandle, RawWindowHandle,
|
||||
WindowHandle,
|
||||
};
|
||||
use servo::compositing::CompositeTarget;
|
||||
use servo::webrender_traits::SurfmanRenderingContext;
|
||||
/// The EventLoopWaker::wake function will be called from any thread.
|
||||
/// It will be called to notify embedder that some events are available,
|
||||
/// and that perform_updates need to be called
|
||||
pub use servo::EventLoopWaker;
|
||||
use servo::{self, resources, Servo};
|
||||
use surfman::{Connection, SurfaceType};
|
||||
use servo::{self, resources, Servo, WindowRenderingContext};
|
||||
use xcomponent_sys::OH_NativeXComponent;
|
||||
|
||||
use crate::egl::app_state::{
|
||||
|
@ -62,43 +64,39 @@ pub fn init(
|
|||
|
||||
crate::init_tracing(servoshell_preferences.tracing_filter.as_deref());
|
||||
|
||||
// Initialize surfman
|
||||
let connection = Connection::new().or(Err("Failed to create connection"))?;
|
||||
let adapter = connection
|
||||
.create_adapter()
|
||||
.or(Err("Failed to create adapter"))?;
|
||||
|
||||
let Ok(window_size) = (unsafe { super::get_xcomponent_size(xcomponent, native_window) }) else {
|
||||
return Err("Failed to get xcomponent size");
|
||||
};
|
||||
let coordinates = Coordinates::new(
|
||||
0,
|
||||
0,
|
||||
window_size.width,
|
||||
window_size.height,
|
||||
window_size.width,
|
||||
window_size.height,
|
||||
);
|
||||
|
||||
debug!("Creating surfman widget with {window_size:?}");
|
||||
let native_widget =
|
||||
unsafe { connection.create_native_widget_from_ptr(native_window, window_size) };
|
||||
let surface_type = SurfaceType::Widget { native_widget };
|
||||
let display_handle = RawDisplayHandle::Ohos(OhosDisplayHandle::new());
|
||||
let display_handle = unsafe { DisplayHandle::borrow_raw(display_handle) };
|
||||
|
||||
info!("Creating rendering context");
|
||||
let rendering_context = SurfmanRenderingContext::create(&connection, &adapter, None)
|
||||
.or(Err("Failed to create surface manager"))?;
|
||||
let surface = rendering_context
|
||||
.create_surface(surface_type)
|
||||
.or(Err("Failed to create surface"))?;
|
||||
rendering_context
|
||||
.bind_surface(surface)
|
||||
.or(Err("Failed to bind surface"))?;
|
||||
let native_window = NonNull::new(native_window).expect("Could not get native window");
|
||||
let window_handle = RawWindowHandle::OhosNdk(OhosNdkWindowHandle::new(native_window));
|
||||
let window_handle = unsafe { WindowHandle::borrow_raw(window_handle) };
|
||||
|
||||
let rendering_context = Rc::new(
|
||||
WindowRenderingContext::new(
|
||||
display_handle,
|
||||
window_handle,
|
||||
&coordinates.framebuffer_size(),
|
||||
)
|
||||
.expect("Could not create RenderingContext"),
|
||||
);
|
||||
|
||||
info!("before ServoWindowCallbacks...");
|
||||
|
||||
let window_callbacks = Rc::new(ServoWindowCallbacks::new(
|
||||
callbacks,
|
||||
RefCell::new(Coordinates::new(
|
||||
0,
|
||||
0,
|
||||
window_size.width,
|
||||
window_size.height,
|
||||
window_size.width,
|
||||
window_size.height,
|
||||
)),
|
||||
RefCell::new(coordinates),
|
||||
options.display_density as f32,
|
||||
));
|
||||
|
||||
|
@ -111,7 +109,7 @@ pub fn init(
|
|||
let servo = Servo::new(
|
||||
opts,
|
||||
preferences,
|
||||
Rc::new(rendering_context.clone()),
|
||||
rendering_context.clone(),
|
||||
embedder_callbacks,
|
||||
window_callbacks.clone(),
|
||||
None, /* user_agent */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue