mirror of
https://github.com/servo/servo.git
synced 2025-08-04 13:10:20 +01:00
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:
commit
c7f4eba3db
3 changed files with 51 additions and 9 deletions
|
@ -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()
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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));
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue