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 {
let ref device = self.0.device.borrow();
device.connection()

View file

@ -63,10 +63,18 @@ pub struct InitOptions {
pub xr_discovery: Option<webxr::Discovery>,
pub gl_context_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>>,
}
/// 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)]
pub struct Coordinates {
pub viewport: Rect<i32, DevicePixel>,
@ -153,6 +161,7 @@ pub trait HostTrait {
}
pub struct ServoGlue {
webrender_surfman: WebrenderSurfman,
servo: Servo<ServoWindowCallbacks>,
batch_mode: bool,
callbacks: Rc<ServoWindowCallbacks>,
@ -253,13 +262,21 @@ pub fn init(
.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(
init_opts.native_widget,
native_widget,
init_opts.coordinates.framebuffer.to_untyped(),
)
};
let surface_type = SurfaceType::Widget { native_widget };
SurfaceType::Widget { native_widget }
},
SurfmanIntegration::Surface => {
let size = init_opts.coordinates.framebuffer.to_untyped();
SurfaceType::Generic { size }
},
};
let webrender_surfman = WebrenderSurfman::create(&connection, &adapter, surface_type)
.or(Err("Failed to create surface manager"))?;
@ -269,7 +286,7 @@ pub fn init(
density: init_opts.density,
gl_context_pointer: init_opts.gl_context_pointer,
native_display_pointer: init_opts.native_display_pointer,
webrender_surfman,
webrender_surfman: webrender_surfman.clone(),
});
let embedder_callbacks = Box::new(ServoEmbedderCallbacks {
@ -282,6 +299,7 @@ pub fn init(
SERVO.with(|s| {
let mut servo_glue = ServoGlue {
webrender_surfman,
servo,
batch_mode: false,
callbacks: window_callbacks,
@ -322,6 +340,12 @@ impl ServoGlue {
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
/// everytime wakeup is called or when embedder wants Servo
/// to act on its pending events.

View file

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