Auto merge of #27766 - jdm:embedding-blit, r=asajeffrey

Embedding support for offscreen-rendering

The current embedding API assumes it should render directly to a native widget at all times. These changes expose an option to render to an offscreen surface when starting the engine, as well as a new WebrenderSurfman API for temporarily acquiring  the surface corresponding to the front buffer so it can be used for blitting purposes.

Demonstrated to work in https://github.com/jdm/servo-embedding-example.

---
- [x] `./mach build -d` does not report any errors
- [x] `./mach test-tidy` does not report any errors
This commit is contained in:
bors-servo 2020-11-15 17:33:40 -05:00 committed by GitHub
commit c7f4eba3db
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 51 additions and 9 deletions

View file

@ -162,6 +162,23 @@ impl WebrenderSurfman {
}) })
} }
/// Invoke a closure with the surface associated with the current front buffer.
/// This can be used to create a surfman::SurfaceTexture to blit elsewhere.
pub fn with_front_buffer<F: FnMut(&Device, Surface) -> Surface>(&self, mut f: F) {
let ref mut device = self.0.device.borrow_mut();
let ref mut context = self.0.context.borrow_mut();
let surface = device
.unbind_surface_from_context(context)
.unwrap()
.unwrap();
let surface = f(device, surface);
device.bind_surface_to_context(context, surface).unwrap();
}
pub fn device(&self) -> std::cell::Ref<Device> {
self.0.device.borrow()
}
pub fn connection(&self) -> Connection { pub fn connection(&self) -> Connection {
let ref device = self.0.device.borrow(); let ref device = self.0.device.borrow();
device.connection() device.connection()

View file

@ -63,10 +63,18 @@ pub struct InitOptions {
pub xr_discovery: Option<webxr::Discovery>, pub xr_discovery: Option<webxr::Discovery>,
pub gl_context_pointer: Option<*const c_void>, pub gl_context_pointer: Option<*const c_void>,
pub native_display_pointer: Option<*const c_void>, pub native_display_pointer: Option<*const c_void>,
pub native_widget: *mut c_void, pub surfman_integration: SurfmanIntegration,
pub prefs: Option<HashMap<String, PrefValue>>, pub prefs: Option<HashMap<String, PrefValue>>,
} }
/// 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),
/// Render to an offscreen surface.
Surface,
}
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Coordinates { pub struct Coordinates {
pub viewport: Rect<i32, DevicePixel>, pub viewport: Rect<i32, DevicePixel>,
@ -153,6 +161,7 @@ pub trait HostTrait {
} }
pub struct ServoGlue { pub struct ServoGlue {
webrender_surfman: WebrenderSurfman,
servo: Servo<ServoWindowCallbacks>, servo: Servo<ServoWindowCallbacks>,
batch_mode: bool, batch_mode: bool,
callbacks: Rc<ServoWindowCallbacks>, callbacks: Rc<ServoWindowCallbacks>,
@ -253,13 +262,21 @@ pub fn init(
.create_adapter() .create_adapter()
.or(Err("Failed to create adapter"))?, .or(Err("Failed to create adapter"))?,
}; };
let native_widget = unsafe { let surface_type = match init_opts.surfman_integration {
connection.create_native_widget_from_ptr( SurfmanIntegration::Widget(native_widget) => {
init_opts.native_widget, let native_widget = unsafe {
init_opts.coordinates.framebuffer.to_untyped(), connection.create_native_widget_from_ptr(
) native_widget,
init_opts.coordinates.framebuffer.to_untyped(),
)
};
SurfaceType::Widget { native_widget }
},
SurfmanIntegration::Surface => {
let size = init_opts.coordinates.framebuffer.to_untyped();
SurfaceType::Generic { size }
},
}; };
let surface_type = SurfaceType::Widget { native_widget };
let webrender_surfman = WebrenderSurfman::create(&connection, &adapter, surface_type) let webrender_surfman = WebrenderSurfman::create(&connection, &adapter, surface_type)
.or(Err("Failed to create surface manager"))?; .or(Err("Failed to create surface manager"))?;
@ -269,7 +286,7 @@ pub fn init(
density: init_opts.density, density: init_opts.density,
gl_context_pointer: init_opts.gl_context_pointer, gl_context_pointer: init_opts.gl_context_pointer,
native_display_pointer: init_opts.native_display_pointer, native_display_pointer: init_opts.native_display_pointer,
webrender_surfman, webrender_surfman: webrender_surfman.clone(),
}); });
let embedder_callbacks = Box::new(ServoEmbedderCallbacks { let embedder_callbacks = Box::new(ServoEmbedderCallbacks {
@ -282,6 +299,7 @@ pub fn init(
SERVO.with(|s| { SERVO.with(|s| {
let mut servo_glue = ServoGlue { let mut servo_glue = ServoGlue {
webrender_surfman,
servo, servo,
batch_mode: false, batch_mode: false,
callbacks: window_callbacks, callbacks: window_callbacks,
@ -322,6 +340,12 @@ impl ServoGlue {
self.servo.deinit(); self.servo.deinit();
} }
/// Returns the webrender surface management integration interface.
/// This provides the embedder access to the current front buffer.
pub fn surfman(&self) -> WebrenderSurfman {
self.webrender_surfman.clone()
}
/// This is the Servo heartbeat. This needs to be called /// This is the Servo heartbeat. This needs to be called
/// everytime wakeup is called or when embedder wants Servo /// everytime wakeup is called or when embedder wants Servo
/// to act on its pending events. /// to act on its pending events.

View file

@ -21,6 +21,7 @@ use simpleservo::{self, gl_glue, ServoGlue, SERVO};
use simpleservo::{ use simpleservo::{
ContextMenuResult, Coordinates, DeviceIntRect, EventLoopWaker, HostTrait, InitOptions, ContextMenuResult, Coordinates, DeviceIntRect, EventLoopWaker, HostTrait, InitOptions,
InputMethodType, MediaSessionActionType, MediaSessionPlaybackState, MouseButton, PromptResult, InputMethodType, MediaSessionActionType, MediaSessionPlaybackState, MouseButton, PromptResult,
SurfmanIntegration,
}; };
use std::ffi::{CStr, CString}; use std::ffi::{CStr, CString};
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
@ -463,7 +464,7 @@ unsafe fn init(
xr_discovery: None, xr_discovery: None,
gl_context_pointer: gl_context, gl_context_pointer: gl_context,
native_display_pointer: display, native_display_pointer: display,
native_widget: opts.native_widget, surfman_integration: SurfmanIntegration::Widget(opts.native_widget),
}; };
let wakeup = Box::new(WakeupCallback::new(wakeup)); let wakeup = Box::new(WakeupCallback::new(wakeup));