mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00: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
3
Cargo.lock
generated
3
Cargo.lock
generated
|
@ -6876,6 +6876,7 @@ dependencies = [
|
|||
"cc",
|
||||
"cfg-if",
|
||||
"dirs",
|
||||
"dpi",
|
||||
"egui",
|
||||
"egui-file-dialog",
|
||||
"egui-winit",
|
||||
|
@ -8592,6 +8593,7 @@ name = "webrender_traits"
|
|||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"base",
|
||||
"dpi",
|
||||
"embedder_traits",
|
||||
"euclid",
|
||||
"gleam",
|
||||
|
@ -8600,6 +8602,7 @@ dependencies = [
|
|||
"ipc-channel",
|
||||
"libc",
|
||||
"log",
|
||||
"raw-window-handle",
|
||||
"serde",
|
||||
"servo-media",
|
||||
"servo_geometry",
|
||||
|
|
|
@ -48,6 +48,7 @@ ctr = "0.9.2"
|
|||
darling = { version = "0.20", default-features = false }
|
||||
data-url = "0.3"
|
||||
devtools_traits = { path = "components/shared/devtools" }
|
||||
dpi = { version = "0.1" }
|
||||
embedder_traits = { path = "components/shared/embedder" }
|
||||
encoding_rs = "0.8"
|
||||
env_logger = "0.10"
|
||||
|
|
|
@ -36,7 +36,6 @@ script_traits = { workspace = true }
|
|||
servo_config = { path = "../config" }
|
||||
servo_geometry = { path = "../geometry" }
|
||||
style_traits = { workspace = true }
|
||||
surfman = { workspace = true }
|
||||
tracing = { workspace = true, optional = true }
|
||||
webrender = { workspace = true }
|
||||
webrender_api = { workspace = true }
|
||||
|
|
|
@ -8,14 +8,12 @@ use std::rc::Rc;
|
|||
|
||||
use compositing::windowing::{AnimationState, EmbedderMethods, WindowMethods};
|
||||
use euclid::{Point2D, Scale, Size2D};
|
||||
use servo::{Servo, TouchEventType, WebView};
|
||||
use servo::{RenderingContext, Servo, TouchEventAction, WebView, WindowRenderingContext};
|
||||
use servo_geometry::DeviceIndependentPixel;
|
||||
use surfman::{Connection, SurfaceType};
|
||||
use tracing::warn;
|
||||
use url::Url;
|
||||
use webrender_api::units::{DeviceIntPoint, DeviceIntRect, DevicePixel, LayoutVector2D};
|
||||
use webrender_api::ScrollLocation;
|
||||
use webrender_traits::SurfmanRenderingContext;
|
||||
use winit::application::ApplicationHandler;
|
||||
use winit::dpi::{PhysicalPosition, PhysicalSize};
|
||||
use winit::event::{MouseScrollDelta, WindowEvent};
|
||||
|
@ -62,7 +60,7 @@ impl ::servo::WebViewDelegate for AppState {
|
|||
}
|
||||
|
||||
fn notify_new_frame_ready(&self, _: WebView) {
|
||||
self.servo.present();
|
||||
self.window_delegate.window.request_redraw();
|
||||
}
|
||||
|
||||
fn request_open_auxiliary_webview(&self, parent_webview: WebView) -> Option<WebView> {
|
||||
|
@ -87,38 +85,21 @@ impl App {
|
|||
impl ApplicationHandler<WakerEvent> for App {
|
||||
fn resumed(&mut self, event_loop: &winit::event_loop::ActiveEventLoop) {
|
||||
if let Self::Initial(waker) = self {
|
||||
let window = event_loop
|
||||
.create_window(Window::default_attributes())
|
||||
.expect("Failed to create winit Window");
|
||||
let display_handle = event_loop
|
||||
.display_handle()
|
||||
.expect("Failed to get display handle");
|
||||
let connection = Connection::from_display_handle(display_handle)
|
||||
.expect("Failed to create connection");
|
||||
let adapter = connection
|
||||
.create_adapter()
|
||||
.expect("Failed to create adapter");
|
||||
let rendering_context = SurfmanRenderingContext::create(&connection, &adapter, None)
|
||||
.expect("Failed to create rendering context");
|
||||
let native_widget = rendering_context
|
||||
.connection()
|
||||
.create_native_widget_from_window_handle(
|
||||
window.window_handle().expect("Failed to get window handle"),
|
||||
winit_size_to_euclid_size(window.inner_size())
|
||||
.to_i32()
|
||||
.to_untyped(),
|
||||
)
|
||||
.expect("Failed to create native widget");
|
||||
let surface = rendering_context
|
||||
.create_surface(SurfaceType::Widget { native_widget })
|
||||
.expect("Failed to create surface");
|
||||
rendering_context
|
||||
.bind_surface(surface)
|
||||
.expect("Failed to bind surface");
|
||||
rendering_context
|
||||
.make_gl_context_current()
|
||||
.expect("Failed to make context current");
|
||||
let window = event_loop
|
||||
.create_window(Window::default_attributes())
|
||||
.expect("Failed to create winit Window");
|
||||
let window_handle = window.window_handle().expect("Failed to get window handle");
|
||||
|
||||
let rendering_context =
|
||||
WindowRenderingContext::new(display_handle, window_handle, &window.inner_size())
|
||||
.expect("Could not create RenderingContext for window.");
|
||||
let window_delegate = Rc::new(WindowDelegate::new(window));
|
||||
|
||||
let _ = rendering_context.make_current();
|
||||
|
||||
let servo = Servo::new(
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
|
@ -139,7 +120,8 @@ impl ApplicationHandler<WakerEvent> for App {
|
|||
});
|
||||
|
||||
// Make a new WebView and assign the `AppState` as the delegate.
|
||||
let url = Url::parse("https://servo.org").expect("Guaranteed by argument");
|
||||
let url = Url::parse("https://demo.servo.org/experiments/twgl-tunnel/")
|
||||
.expect("Guaranteed by argument");
|
||||
let webview = app_state.servo.new_webview(url);
|
||||
webview.set_delegate(app_state.clone());
|
||||
app_state.webviews.borrow_mut().push(webview);
|
||||
|
@ -170,7 +152,7 @@ impl ApplicationHandler<WakerEvent> for App {
|
|||
},
|
||||
WindowEvent::RedrawRequested => {
|
||||
if let Self::Running(state) = self {
|
||||
state.webviews.borrow().last().unwrap().composite();
|
||||
state.webviews.borrow().last().unwrap().paint_immediately();
|
||||
state.servo.present();
|
||||
}
|
||||
},
|
||||
|
@ -188,7 +170,7 @@ impl ApplicationHandler<WakerEvent> for App {
|
|||
webview.notify_scroll_event(
|
||||
ScrollLocation::Delta(moved_by),
|
||||
DeviceIntPoint::new(10, 10),
|
||||
TouchEventType::Down,
|
||||
TouchEventAction::Down,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -101,7 +101,11 @@ pub use webgpu;
|
|||
use webgpu::swapchain::WGPUImageMap;
|
||||
use webrender::{RenderApiSender, ShaderPrecacheFlags, UploadMethod, ONE_TIME_USAGE_HINT};
|
||||
use webrender_api::{ColorF, DocumentId, FramePublishId};
|
||||
use webrender_traits::rendering_context::{GLVersion, RenderingContext};
|
||||
use webrender_traits::rendering_context::GLVersion;
|
||||
pub use webrender_traits::rendering_context::{
|
||||
OffscreenRenderingContext, RenderingContext, SoftwareRenderingContext, SurfmanRenderingContext,
|
||||
WindowRenderingContext,
|
||||
};
|
||||
use webrender_traits::{
|
||||
CrossProcessCompositorApi, WebrenderExternalImageHandlers, WebrenderExternalImageRegistry,
|
||||
WebrenderImageHandlerType,
|
||||
|
@ -113,7 +117,7 @@ pub use {
|
|||
background_hang_monitor, base, canvas, canvas_traits, compositing, devtools, devtools_traits,
|
||||
euclid, fonts, ipc_channel, layout_thread_2020, media, net, net_traits, profile,
|
||||
profile_traits, script, script_layout_interface, script_traits, servo_config as config,
|
||||
servo_config, servo_geometry, servo_url, style, style_traits, webrender_api, webrender_traits,
|
||||
servo_config, servo_geometry, servo_url, style, style_traits, webrender_api,
|
||||
};
|
||||
#[cfg(feature = "bluetooth")]
|
||||
pub use {bluetooth, bluetooth_traits};
|
||||
|
|
|
@ -414,4 +414,8 @@ impl WebView {
|
|||
.constellation_proxy
|
||||
.send(ConstellationMsg::SendError(Some(self.id()), message));
|
||||
}
|
||||
|
||||
pub fn paint_immediately(&self) {
|
||||
self.inner().compositor.borrow_mut().composite();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,3 +31,5 @@ servo_geometry = { path = "../../geometry" }
|
|||
servo-media = { workspace = true }
|
||||
style = { workspace = true }
|
||||
surfman = { workspace = true, features = ["sm-x11"] }
|
||||
raw-window-handle = { version = "0.6" }
|
||||
dpi = { version = "0.1" }
|
||||
|
|
|
@ -28,8 +28,6 @@ use webrender_api::{
|
|||
ImageKey, NativeFontHandle, PipelineId as WebRenderPipelineId,
|
||||
};
|
||||
|
||||
pub use crate::rendering_context::SurfmanRenderingContext;
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub enum CrossProcessCompositorMessage {
|
||||
/// Inform WebRender of the existence of this pipeline.
|
||||
|
|
|
@ -9,12 +9,14 @@ use std::ffi::c_void;
|
|||
use std::num::NonZeroU32;
|
||||
use std::rc::Rc;
|
||||
|
||||
use dpi::PhysicalSize;
|
||||
use euclid::default::{Rect, Size2D};
|
||||
use euclid::Point2D;
|
||||
use gleam::gl::{self, Gl};
|
||||
use glow::NativeFramebuffer;
|
||||
use image::RgbaImage;
|
||||
use log::{debug, trace, warn};
|
||||
use raw_window_handle::{DisplayHandle, WindowHandle};
|
||||
use servo_media::player::context::{GlContext, NativeDisplay};
|
||||
use surfman::chains::{PreserveBuffer, SwapChain};
|
||||
#[cfg(all(target_os = "linux", not(target_env = "ohos")))]
|
||||
|
@ -24,8 +26,7 @@ use surfman::platform::generic::multi::context::NativeContext as LinuxNativeCont
|
|||
pub use surfman::Error;
|
||||
use surfman::{
|
||||
Adapter, Connection, Context, ContextAttributeFlags, ContextAttributes, Device, GLApi,
|
||||
NativeContext, NativeDevice, NativeWidget, Surface, SurfaceAccess, SurfaceInfo, SurfaceTexture,
|
||||
SurfaceType,
|
||||
NativeContext, NativeWidget, Surface, SurfaceAccess, SurfaceInfo, SurfaceTexture, SurfaceType,
|
||||
};
|
||||
|
||||
/// Describes the OpenGL version that is requested when a context is created.
|
||||
|
@ -81,7 +82,6 @@ pub trait RenderingContext {
|
|||
fn destroy_texture(&self, _surface_texture: SurfaceTexture) -> Option<Surface> {
|
||||
None
|
||||
}
|
||||
|
||||
/// The connection to the display server for WebGL. Default to `None`.
|
||||
fn connection(&self) -> Option<Connection> {
|
||||
None
|
||||
|
@ -96,28 +96,124 @@ pub trait RenderingContext {
|
|||
/// The `SurfmanRenderingContext` struct encapsulates the necessary data and methods
|
||||
/// to interact with the Surfman library, including creating surfaces, binding surfaces,
|
||||
/// resizing surfaces, presenting rendered frames, and managing the OpenGL context state.
|
||||
#[derive(Clone)]
|
||||
pub struct SurfmanRenderingContext(Rc<RenderingContextData>);
|
||||
|
||||
struct RenderingContextData {
|
||||
pub struct SurfmanRenderingContext {
|
||||
gl: Rc<dyn Gl>,
|
||||
device: RefCell<Device>,
|
||||
context: RefCell<Context>,
|
||||
// We either render to a swap buffer or to a native widget
|
||||
swap_chain: Option<SwapChain<Device>>,
|
||||
}
|
||||
|
||||
impl Drop for RenderingContextData {
|
||||
impl Drop for SurfmanRenderingContext {
|
||||
fn drop(&mut self) {
|
||||
let device = &mut self.device.borrow_mut();
|
||||
let context = &mut self.context.borrow_mut();
|
||||
if let Some(ref swap_chain) = self.swap_chain {
|
||||
let _ = swap_chain.destroy(device, context);
|
||||
}
|
||||
let _ = device.destroy_context(context);
|
||||
}
|
||||
}
|
||||
|
||||
impl SurfmanRenderingContext {
|
||||
fn new(connection: &Connection, adapter: &Adapter) -> Result<Self, Error> {
|
||||
let mut device = connection.create_device(adapter)?;
|
||||
|
||||
let flags = ContextAttributeFlags::ALPHA |
|
||||
ContextAttributeFlags::DEPTH |
|
||||
ContextAttributeFlags::STENCIL;
|
||||
let gl_api = connection.gl_api();
|
||||
let version = match &gl_api {
|
||||
GLApi::GLES => surfman::GLVersion { major: 3, minor: 0 },
|
||||
GLApi::GL => surfman::GLVersion { major: 3, minor: 2 },
|
||||
};
|
||||
let context_descriptor =
|
||||
device.create_context_descriptor(&ContextAttributes { flags, version })?;
|
||||
let context = device.create_context(&context_descriptor, None)?;
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
let gl = {
|
||||
match gl_api {
|
||||
GLApi::GL => unsafe {
|
||||
gl::GlFns::load_with(|func_name| device.get_proc_address(&context, func_name))
|
||||
},
|
||||
GLApi::GLES => unsafe {
|
||||
gl::GlesFns::load_with(|func_name| device.get_proc_address(&context, func_name))
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
Ok(SurfmanRenderingContext {
|
||||
gl,
|
||||
device: RefCell::new(device),
|
||||
context: RefCell::new(context),
|
||||
})
|
||||
}
|
||||
|
||||
fn create_surface(&self, surface_type: SurfaceType<NativeWidget>) -> Result<Surface, Error> {
|
||||
let device = &mut self.device.borrow_mut();
|
||||
let context = &self.context.borrow();
|
||||
device.create_surface(context, SurfaceAccess::GPUOnly, surface_type)
|
||||
}
|
||||
|
||||
fn bind_surface(&self, surface: Surface) -> Result<(), Error> {
|
||||
let device = &self.device.borrow();
|
||||
let context = &mut self.context.borrow_mut();
|
||||
device
|
||||
.bind_surface_to_context(context, surface)
|
||||
.map_err(|(err, mut surface)| {
|
||||
let _ = device.destroy_surface(context, &mut surface);
|
||||
err
|
||||
})?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn create_attached_swap_chain(&self) -> Result<SwapChain<Device>, Error> {
|
||||
let device = &mut self.device.borrow_mut();
|
||||
let context = &mut self.context.borrow_mut();
|
||||
SwapChain::create_attached(device, context, SurfaceAccess::GPUOnly)
|
||||
}
|
||||
|
||||
fn resize_surface(&self, size: Size2D<i32>) -> Result<(), Error> {
|
||||
let device = &mut self.device.borrow_mut();
|
||||
let context = &mut self.context.borrow_mut();
|
||||
|
||||
let mut surface = device.unbind_surface_from_context(context)?.unwrap();
|
||||
device.resize_surface(context, &mut surface, size)?;
|
||||
device
|
||||
.bind_surface_to_context(context, surface)
|
||||
.map_err(|(err, mut surface)| {
|
||||
let _ = device.destroy_surface(context, &mut surface);
|
||||
err
|
||||
})
|
||||
}
|
||||
|
||||
fn present_bound_surface(&self) -> Result<(), Error> {
|
||||
let device = &self.device.borrow();
|
||||
let context = &mut self.context.borrow_mut();
|
||||
|
||||
let mut surface = device.unbind_surface_from_context(context)?.unwrap();
|
||||
device.present_surface(context, &mut surface)?;
|
||||
device
|
||||
.bind_surface_to_context(context, surface)
|
||||
.map_err(|(err, mut surface)| {
|
||||
let _ = device.destroy_surface(context, &mut surface);
|
||||
err
|
||||
})
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn native_context(&self) -> NativeContext {
|
||||
let device = &self.device.borrow();
|
||||
let context = &self.context.borrow();
|
||||
device.native_context(context)
|
||||
}
|
||||
|
||||
fn framebuffer(&self) -> Option<NativeFramebuffer> {
|
||||
let device = &self.device.borrow();
|
||||
let context = &self.context.borrow();
|
||||
device
|
||||
.context_surface_info(context)
|
||||
.unwrap_or(None)
|
||||
.and_then(|info| info.framebuffer_object)
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderingContext for SurfmanRenderingContext {
|
||||
fn gl_context(&self) -> GlContext {
|
||||
#[cfg(all(target_os = "linux", not(target_env = "ohos")))]
|
||||
|
@ -149,10 +245,11 @@ impl RenderingContext for SurfmanRenderingContext {
|
|||
GlContext::Unknown
|
||||
}
|
||||
}
|
||||
|
||||
fn gl_display(&self) -> NativeDisplay {
|
||||
#[cfg(all(target_os = "linux", not(target_env = "ohos")))]
|
||||
{
|
||||
match self.connection().native_connection() {
|
||||
match self.device.borrow().connection().native_connection() {
|
||||
surfman::NativeConnection::Default(LinuxNativeConnection::Default(connection)) => {
|
||||
NativeDisplay::Egl(connection.0 as usize)
|
||||
},
|
||||
|
@ -166,7 +263,8 @@ impl RenderingContext for SurfmanRenderingContext {
|
|||
{
|
||||
#[cfg(feature = "no-wgl")]
|
||||
{
|
||||
NativeDisplay::Egl(self.native_device().egl_display as usize)
|
||||
let device = &self.device.borrow();
|
||||
NativeDisplay::Egl(device.native_device().egl_display as usize)
|
||||
}
|
||||
#[cfg(not(feature = "no-wgl"))]
|
||||
NativeDisplay::Unknown
|
||||
|
@ -180,55 +278,59 @@ impl RenderingContext for SurfmanRenderingContext {
|
|||
}
|
||||
}
|
||||
|
||||
fn prepare_for_rendering(&self) {
|
||||
self.0.gl.bind_framebuffer(
|
||||
gleam::gl::FRAMEBUFFER,
|
||||
self.framebuffer()
|
||||
.map_or(0, |framebuffer| framebuffer.0.into()),
|
||||
);
|
||||
}
|
||||
|
||||
fn read_to_image(&self, source_rectangle: Rect<u32>) -> Option<RgbaImage> {
|
||||
let framebuffer_id = self
|
||||
.framebuffer()
|
||||
.map(|framebuffer| framebuffer.0.into())
|
||||
.unwrap_or(0);
|
||||
Framebuffer::read_framebuffer_to_image(self.gl_api(), framebuffer_id, source_rectangle)
|
||||
}
|
||||
|
||||
fn resize(&self, size: Size2D<i32>) {
|
||||
if let Err(err) = self.resize(size) {
|
||||
warn!("Failed to resize surface: {:?}", err);
|
||||
}
|
||||
}
|
||||
fn present(&self) {
|
||||
if let Err(err) = self.present() {
|
||||
warn!("Failed to present surface: {:?}", err);
|
||||
}
|
||||
}
|
||||
fn make_current(&self) -> Result<(), Error> {
|
||||
self.make_gl_context_current()
|
||||
}
|
||||
#[allow(unsafe_code)]
|
||||
fn gl_api(&self) -> Rc<dyn gleam::gl::Gl> {
|
||||
self.0.gl.clone()
|
||||
}
|
||||
fn gl_version(&self) -> GLVersion {
|
||||
let device = self.0.device.borrow();
|
||||
let context = self.0.context.borrow();
|
||||
let device = self.device.borrow();
|
||||
let context = self.context.borrow();
|
||||
let descriptor = device.context_descriptor(&context);
|
||||
let attributes = device.context_descriptor_attributes(&descriptor);
|
||||
let major = attributes.version.major;
|
||||
let minor = attributes.version.minor;
|
||||
match self.connection().gl_api() {
|
||||
match device.connection().gl_api() {
|
||||
GLApi::GL => GLVersion::GL(major, minor),
|
||||
GLApi::GLES => GLVersion::GLES(major, minor),
|
||||
}
|
||||
}
|
||||
|
||||
fn gl_api(&self) -> Rc<dyn gleam::gl::Gl> {
|
||||
self.gl.clone()
|
||||
}
|
||||
|
||||
fn prepare_for_rendering(&self) {
|
||||
let framebuffer_id = self
|
||||
.framebuffer()
|
||||
.map_or(0, |framebuffer| framebuffer.0.into());
|
||||
self.gl
|
||||
.bind_framebuffer(gleam::gl::FRAMEBUFFER, framebuffer_id);
|
||||
}
|
||||
|
||||
fn read_to_image(&self, source_rectangle: Rect<u32>) -> Option<RgbaImage> {
|
||||
let framebuffer_id = self
|
||||
.framebuffer()
|
||||
.map_or(0, |framebuffer| framebuffer.0.into());
|
||||
Framebuffer::read_framebuffer_to_image(&self.gl, framebuffer_id, source_rectangle)
|
||||
}
|
||||
|
||||
fn resize(&self, size: Size2D<i32>) {
|
||||
if let Err(error) = self.resize_surface(size) {
|
||||
warn!("Error resizing surface: {error:?}");
|
||||
}
|
||||
}
|
||||
|
||||
fn present(&self) {
|
||||
if let Err(error) = self.present_bound_surface() {
|
||||
warn!("Error presenting surface: {error:?}");
|
||||
}
|
||||
}
|
||||
|
||||
fn make_current(&self) -> Result<(), Error> {
|
||||
let device = &self.device.borrow();
|
||||
let context = &mut self.context.borrow();
|
||||
device.make_context_current(context)
|
||||
}
|
||||
|
||||
fn create_texture(&self, surface: Surface) -> Option<(SurfaceTexture, u32, Size2D<i32>)> {
|
||||
let device = &self.0.device.borrow();
|
||||
let context = &mut self.0.context.borrow_mut();
|
||||
let device = &self.device.borrow();
|
||||
let context = &mut self.context.borrow_mut();
|
||||
let SurfaceInfo {
|
||||
id: front_buffer_id,
|
||||
size,
|
||||
|
@ -244,236 +346,164 @@ impl RenderingContext for SurfmanRenderingContext {
|
|||
}
|
||||
|
||||
fn destroy_texture(&self, surface_texture: SurfaceTexture) -> Option<Surface> {
|
||||
self.destroy_surface_texture(surface_texture).ok()
|
||||
}
|
||||
|
||||
fn connection(&self) -> Option<Connection> {
|
||||
Some(self.connection())
|
||||
}
|
||||
}
|
||||
|
||||
impl SurfmanRenderingContext {
|
||||
pub fn create(
|
||||
connection: &Connection,
|
||||
adapter: &Adapter,
|
||||
headless: Option<Size2D<i32>>,
|
||||
) -> Result<Self, Error> {
|
||||
let mut device = connection.create_device(adapter)?;
|
||||
let flags = ContextAttributeFlags::ALPHA |
|
||||
ContextAttributeFlags::DEPTH |
|
||||
ContextAttributeFlags::STENCIL;
|
||||
let version = match connection.gl_api() {
|
||||
GLApi::GLES => surfman::GLVersion { major: 3, minor: 0 },
|
||||
GLApi::GL => surfman::GLVersion { major: 3, minor: 2 },
|
||||
};
|
||||
let context_attributes = ContextAttributes { flags, version };
|
||||
let context_descriptor = device.create_context_descriptor(&context_attributes)?;
|
||||
let mut context = device.create_context(&context_descriptor, None)?;
|
||||
let surface_access = SurfaceAccess::GPUOnly;
|
||||
let swap_chain = if let Some(size) = headless {
|
||||
let surface_type = SurfaceType::Generic { size };
|
||||
let surface = device.create_surface(&context, surface_access, surface_type)?;
|
||||
device
|
||||
.bind_surface_to_context(&mut context, surface)
|
||||
.map_err(|(err, mut surface)| {
|
||||
let _ = device.destroy_surface(&mut context, &mut surface);
|
||||
err
|
||||
})?;
|
||||
device.make_context_current(&context)?;
|
||||
Some(SwapChain::create_attached(
|
||||
&mut device,
|
||||
&mut context,
|
||||
surface_access,
|
||||
)?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
let gl = {
|
||||
match connection.gl_api() {
|
||||
GLApi::GL => unsafe {
|
||||
gl::GlFns::load_with(|s| device.get_proc_address(&context, s))
|
||||
},
|
||||
GLApi::GLES => unsafe {
|
||||
gl::GlesFns::load_with(|s| device.get_proc_address(&context, s))
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
let device = RefCell::new(device);
|
||||
let context = RefCell::new(context);
|
||||
let data = RenderingContextData {
|
||||
gl,
|
||||
device,
|
||||
context,
|
||||
swap_chain,
|
||||
};
|
||||
Ok(SurfmanRenderingContext(Rc::new(data)))
|
||||
}
|
||||
|
||||
pub fn create_surface(
|
||||
&self,
|
||||
surface_type: SurfaceType<NativeWidget>,
|
||||
) -> Result<Surface, Error> {
|
||||
let device = &mut self.0.device.borrow_mut();
|
||||
let context = &self.0.context.borrow();
|
||||
let surface_access = SurfaceAccess::GPUOnly;
|
||||
device.create_surface(context, surface_access, surface_type)
|
||||
}
|
||||
|
||||
pub fn bind_surface(&self, surface: Surface) -> Result<(), Error> {
|
||||
let device = &self.0.device.borrow();
|
||||
let context = &mut self.0.context.borrow_mut();
|
||||
device
|
||||
.bind_surface_to_context(context, surface)
|
||||
.map_err(|(err, mut surface)| {
|
||||
let _ = device.destroy_surface(context, &mut surface);
|
||||
err
|
||||
})?;
|
||||
|
||||
device.make_context_current(context)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn destroy_surface(&self, mut surface: Surface) -> Result<(), Error> {
|
||||
let device = &self.0.device.borrow();
|
||||
let context = &mut self.0.context.borrow_mut();
|
||||
device.destroy_surface(context, &mut surface)
|
||||
}
|
||||
|
||||
pub fn create_surface_texture(&self, surface: Surface) -> Result<SurfaceTexture, Error> {
|
||||
let device = &self.0.device.borrow();
|
||||
let context = &mut self.0.context.borrow_mut();
|
||||
device
|
||||
.create_surface_texture(context, surface)
|
||||
.map_err(|(error, _)| error)
|
||||
}
|
||||
|
||||
pub fn destroy_surface_texture(
|
||||
&self,
|
||||
surface_texture: SurfaceTexture,
|
||||
) -> Result<Surface, Error> {
|
||||
let device = &self.0.device.borrow();
|
||||
let context = &mut self.0.context.borrow_mut();
|
||||
let device = &self.device.borrow();
|
||||
let context = &mut self.context.borrow_mut();
|
||||
device
|
||||
.destroy_surface_texture(context, surface_texture)
|
||||
.map_err(|(error, _)| error)
|
||||
.ok()
|
||||
}
|
||||
|
||||
pub fn make_gl_context_current(&self) -> Result<(), Error> {
|
||||
let device = &self.0.device.borrow();
|
||||
let context = &self.0.context.borrow();
|
||||
device.make_context_current(context)
|
||||
fn connection(&self) -> Option<Connection> {
|
||||
Some(self.device.borrow().connection())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn swap_chain(&self) -> Result<&SwapChain<Device>, Error> {
|
||||
self.0.swap_chain.as_ref().ok_or(Error::WidgetAttached)
|
||||
}
|
||||
/// A software rendering context that uses a software OpenGL implementation to render
|
||||
/// Servo. This will generally have bad performance, but can be used in situations where
|
||||
/// it is more convenient to have consistent, but slower display output.
|
||||
///
|
||||
/// The results of the render can be accessed via [`RenderingContext::read_to_image`].
|
||||
pub struct SoftwareRenderingContext {
|
||||
surfman_rendering_info: SurfmanRenderingContext,
|
||||
swap_chain: SwapChain<Device>,
|
||||
}
|
||||
|
||||
pub fn resize(&self, size: Size2D<i32>) -> Result<(), Error> {
|
||||
let device = &mut self.0.device.borrow_mut();
|
||||
let context = &mut self.0.context.borrow_mut();
|
||||
if let Some(swap_chain) = self.0.swap_chain.as_ref() {
|
||||
return swap_chain.resize(device, context, size);
|
||||
}
|
||||
let mut surface = device.unbind_surface_from_context(context)?.unwrap();
|
||||
device.resize_surface(context, &mut surface, size)?;
|
||||
device
|
||||
.bind_surface_to_context(context, surface)
|
||||
.map_err(|(err, mut surface)| {
|
||||
let _ = device.destroy_surface(context, &mut surface);
|
||||
err
|
||||
impl SoftwareRenderingContext {
|
||||
pub fn new(size: PhysicalSize<u32>) -> Result<Self, Error> {
|
||||
let connection = Connection::new()?;
|
||||
let adapter = connection.create_software_adapter()?;
|
||||
let surfman_rendering_info = SurfmanRenderingContext::new(&connection, &adapter)?;
|
||||
|
||||
let size = Size2D::new(size.width as i32, size.height as i32);
|
||||
let surface = surfman_rendering_info.create_surface(SurfaceType::Generic { size })?;
|
||||
surfman_rendering_info.bind_surface(surface)?;
|
||||
surfman_rendering_info.make_current()?;
|
||||
|
||||
let swap_chain = surfman_rendering_info.create_attached_swap_chain()?;
|
||||
Ok(SoftwareRenderingContext {
|
||||
surfman_rendering_info,
|
||||
swap_chain,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn present(&self) -> Result<(), Error> {
|
||||
let device = &mut self.0.device.borrow_mut();
|
||||
let context = &mut self.0.context.borrow_mut();
|
||||
if let Some(ref swap_chain) = self.0.swap_chain {
|
||||
return swap_chain.swap_buffers(device, context, PreserveBuffer::No);
|
||||
impl Drop for SoftwareRenderingContext {
|
||||
fn drop(&mut self) {
|
||||
let device = &mut self.surfman_rendering_info.device.borrow_mut();
|
||||
let context = &mut self.surfman_rendering_info.context.borrow_mut();
|
||||
let _ = self.swap_chain.destroy(device, context);
|
||||
}
|
||||
let mut surface = device.unbind_surface_from_context(context)?.unwrap();
|
||||
device.present_surface(context, &mut surface)?;
|
||||
device
|
||||
.bind_surface_to_context(context, surface)
|
||||
.map_err(|(err, mut surface)| {
|
||||
let _ = device.destroy_surface(context, &mut surface);
|
||||
err
|
||||
})
|
||||
}
|
||||
|
||||
impl RenderingContext for SoftwareRenderingContext {
|
||||
fn gl_context(&self) -> GlContext {
|
||||
self.surfman_rendering_info.gl_context()
|
||||
}
|
||||
|
||||
/// 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: FnOnce(&Device, Surface) -> Surface>(&self, f: F) {
|
||||
let device = &mut self.0.device.borrow_mut();
|
||||
let context = &mut 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();
|
||||
fn gl_display(&self) -> NativeDisplay {
|
||||
self.surfman_rendering_info.gl_display()
|
||||
}
|
||||
|
||||
pub fn device(&self) -> std::cell::Ref<Device> {
|
||||
self.0.device.borrow()
|
||||
fn prepare_for_rendering(&self) {
|
||||
self.surfman_rendering_info.prepare_for_rendering();
|
||||
}
|
||||
|
||||
pub fn connection(&self) -> Connection {
|
||||
let device = &self.0.device.borrow();
|
||||
device.connection()
|
||||
fn read_to_image(&self, source_rectangle: Rect<u32>) -> Option<RgbaImage> {
|
||||
self.surfman_rendering_info.read_to_image(source_rectangle)
|
||||
}
|
||||
|
||||
pub fn adapter(&self) -> Adapter {
|
||||
let device = &self.0.device.borrow();
|
||||
device.adapter()
|
||||
fn resize(&self, size: Size2D<i32>) {
|
||||
let device = &mut self.surfman_rendering_info.device.borrow_mut();
|
||||
let context = &mut self.surfman_rendering_info.context.borrow_mut();
|
||||
let _ = self.swap_chain.resize(device, context, size);
|
||||
}
|
||||
|
||||
pub fn native_context(&self) -> NativeContext {
|
||||
let device = &self.0.device.borrow();
|
||||
let context = &self.0.context.borrow();
|
||||
device.native_context(context)
|
||||
fn present(&self) {
|
||||
let device = &mut self.surfman_rendering_info.device.borrow_mut();
|
||||
let context = &mut self.surfman_rendering_info.context.borrow_mut();
|
||||
let _ = self
|
||||
.swap_chain
|
||||
.swap_buffers(device, context, PreserveBuffer::No);
|
||||
}
|
||||
|
||||
pub fn native_device(&self) -> NativeDevice {
|
||||
let device = &self.0.device.borrow();
|
||||
device.native_device()
|
||||
fn make_current(&self) -> Result<(), Error> {
|
||||
self.surfman_rendering_info.make_current()
|
||||
}
|
||||
|
||||
pub fn context_attributes(&self) -> ContextAttributes {
|
||||
let device = &self.0.device.borrow();
|
||||
let context = &self.0.context.borrow();
|
||||
let descriptor = &device.context_descriptor(context);
|
||||
device.context_descriptor_attributes(descriptor)
|
||||
#[allow(unsafe_code)]
|
||||
fn gl_api(&self) -> Rc<dyn gleam::gl::Gl> {
|
||||
self.surfman_rendering_info.gl.clone()
|
||||
}
|
||||
|
||||
pub fn context_surface_info(&self) -> Result<Option<SurfaceInfo>, Error> {
|
||||
let device = &self.0.device.borrow();
|
||||
let context = &self.0.context.borrow();
|
||||
device.context_surface_info(context)
|
||||
fn gl_version(&self) -> GLVersion {
|
||||
self.surfman_rendering_info.gl_version()
|
||||
}
|
||||
|
||||
pub fn surface_info(&self, surface: &Surface) -> SurfaceInfo {
|
||||
let device = &self.0.device.borrow();
|
||||
device.surface_info(surface)
|
||||
fn create_texture(&self, surface: Surface) -> Option<(SurfaceTexture, u32, Size2D<i32>)> {
|
||||
self.surfman_rendering_info.create_texture(surface)
|
||||
}
|
||||
|
||||
pub fn surface_texture_object(&self, surface: &SurfaceTexture) -> u32 {
|
||||
let device = &self.0.device.borrow();
|
||||
device
|
||||
.surface_texture_object(surface)
|
||||
.map(|t| t.0.get())
|
||||
.unwrap_or_default()
|
||||
fn destroy_texture(&self, surface_texture: SurfaceTexture) -> Option<Surface> {
|
||||
self.surfman_rendering_info.destroy_texture(surface_texture)
|
||||
}
|
||||
|
||||
fn connection(&self) -> Option<Connection> {
|
||||
self.surfman_rendering_info.connection()
|
||||
}
|
||||
}
|
||||
|
||||
/// A [`RenderingContext`] that uses the `surfman` library to render to a
|
||||
/// `raw-window-handle` identified window. `surfman` will attempt to create an
|
||||
/// OpenGL context and surface for this window. This is a simple implementation
|
||||
/// of the [`RenderingContext`] crate, but by default it paints to the entire window
|
||||
/// surface.
|
||||
///
|
||||
/// If you would like to paint to only a portion of the window, consider using
|
||||
/// [`OffscreenRenderingContext`] by calling [`WindowRenderingContext::offscreen_context`].
|
||||
pub struct WindowRenderingContext(SurfmanRenderingContext);
|
||||
|
||||
impl WindowRenderingContext {
|
||||
pub fn new(
|
||||
display_handle: DisplayHandle,
|
||||
window_handle: WindowHandle,
|
||||
size: &PhysicalSize<u32>,
|
||||
) -> Result<Self, Error> {
|
||||
let connection = Connection::from_display_handle(display_handle)?;
|
||||
let adapter = connection.create_adapter()?;
|
||||
let surfman_rendering_info = SurfmanRenderingContext::new(&connection, &adapter)?;
|
||||
|
||||
let native_widget = connection
|
||||
.create_native_widget_from_window_handle(
|
||||
window_handle,
|
||||
Size2D::new(size.width as i32, size.height as i32),
|
||||
)
|
||||
.expect("Failed to create native widget");
|
||||
|
||||
let surface =
|
||||
surfman_rendering_info.create_surface(SurfaceType::Widget { native_widget })?;
|
||||
surfman_rendering_info.bind_surface(surface)?;
|
||||
surfman_rendering_info.make_current()?;
|
||||
|
||||
Ok(Self(surfman_rendering_info))
|
||||
}
|
||||
|
||||
pub fn offscreen_context(self: &Rc<Self>, size: Size2D<u32>) -> OffscreenRenderingContext {
|
||||
OffscreenRenderingContext::new(self.clone(), size)
|
||||
}
|
||||
|
||||
/// TODO: This can be removed when Servo switches fully to `glow.`
|
||||
pub fn get_proc_address(&self, name: &str) -> *const c_void {
|
||||
let device = &self.0.device.borrow();
|
||||
let context = &self.0.context.borrow();
|
||||
device.get_proc_address(context, name)
|
||||
}
|
||||
|
||||
pub fn unbind_native_surface_from_context(&self) -> Result<(), Error> {
|
||||
/// Stop rendering to the window that was used to create this `WindowRenderingContext`
|
||||
/// or last set with [`Self::set_window`].
|
||||
///
|
||||
/// TODO: This should be removed once `WebView`s can replace their `RenderingContext`s.
|
||||
pub fn take_window(&self) -> Result<(), Error> {
|
||||
let device = self.0.device.borrow_mut();
|
||||
let mut context = self.0.context.borrow_mut();
|
||||
let mut surface = device.unbind_surface_from_context(&mut context)?.unwrap();
|
||||
|
@ -481,12 +511,30 @@ impl SurfmanRenderingContext {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn bind_native_surface_to_context(&self, native_widget: NativeWidget) -> Result<(), Error> {
|
||||
/// Replace the window that this [`WindowRenderingContext`] renders to and give it a new
|
||||
/// size.
|
||||
///
|
||||
/// TODO: This should be removed once `WebView`s can replace their `RenderingContext`s.
|
||||
pub fn set_window(
|
||||
&self,
|
||||
window_handle: WindowHandle,
|
||||
size: &PhysicalSize<u32>,
|
||||
) -> Result<(), Error> {
|
||||
let mut device = self.0.device.borrow_mut();
|
||||
let mut context = self.0.context.borrow_mut();
|
||||
|
||||
let native_widget = device
|
||||
.connection()
|
||||
.create_native_widget_from_window_handle(
|
||||
window_handle,
|
||||
Size2D::new(size.width as i32, size.height as i32),
|
||||
)
|
||||
.expect("Failed to create native widget");
|
||||
|
||||
let surface_access = SurfaceAccess::GPUOnly;
|
||||
let surface_type = SurfaceType::Widget { native_widget };
|
||||
let surface = device.create_surface(&context, surface_access, surface_type)?;
|
||||
|
||||
device
|
||||
.bind_surface_to_context(&mut context, surface)
|
||||
.map_err(|(err, mut surface)| {
|
||||
|
@ -496,18 +544,60 @@ impl SurfmanRenderingContext {
|
|||
device.make_context_current(&context)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn framebuffer(&self) -> Option<NativeFramebuffer> {
|
||||
self.context_surface_info()
|
||||
.unwrap_or(None)
|
||||
.and_then(|info| info.framebuffer_object)
|
||||
impl RenderingContext for WindowRenderingContext {
|
||||
fn gl_context(&self) -> GlContext {
|
||||
self.0.gl_context()
|
||||
}
|
||||
|
||||
/// Create a new offscreen context that is compatible with this [`SurfmanRenderingContext`].
|
||||
/// The contents of the resulting [`OffscreenRenderingContext`] are guaranteed to be blit
|
||||
/// compatible with the this context.
|
||||
pub fn offscreen_context(&self, size: Size2D<u32>) -> OffscreenRenderingContext {
|
||||
OffscreenRenderingContext::new(SurfmanRenderingContext(self.0.clone()), size)
|
||||
fn gl_display(&self) -> NativeDisplay {
|
||||
self.0.gl_display()
|
||||
}
|
||||
|
||||
fn prepare_for_rendering(&self) {
|
||||
self.0.prepare_for_rendering();
|
||||
}
|
||||
|
||||
fn read_to_image(&self, source_rectangle: Rect<u32>) -> Option<RgbaImage> {
|
||||
self.0.read_to_image(source_rectangle)
|
||||
}
|
||||
|
||||
fn resize(&self, size: Size2D<i32>) {
|
||||
if let Err(error) = self.0.resize_surface(size) {
|
||||
warn!("Error resizing surface: {error:?}");
|
||||
}
|
||||
}
|
||||
|
||||
fn present(&self) {
|
||||
if let Err(error) = self.0.present_bound_surface() {
|
||||
warn!("Error presenting surface: {error:?}");
|
||||
}
|
||||
}
|
||||
|
||||
fn make_current(&self) -> Result<(), Error> {
|
||||
self.0.make_current()
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
fn gl_api(&self) -> Rc<dyn gleam::gl::Gl> {
|
||||
self.0.gl.clone()
|
||||
}
|
||||
|
||||
fn gl_version(&self) -> GLVersion {
|
||||
self.0.gl_version()
|
||||
}
|
||||
|
||||
fn create_texture(&self, surface: Surface) -> Option<(SurfaceTexture, u32, Size2D<i32>)> {
|
||||
self.0.create_texture(surface)
|
||||
}
|
||||
|
||||
fn destroy_texture(&self, surface_texture: SurfaceTexture) -> Option<Surface> {
|
||||
self.0.destroy_texture(surface_texture)
|
||||
}
|
||||
|
||||
fn connection(&self) -> Option<Connection> {
|
||||
self.0.connection()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -605,11 +695,11 @@ impl Framebuffer {
|
|||
}
|
||||
|
||||
fn read_to_image(&self, source_rectangle: Rect<u32>) -> Option<RgbaImage> {
|
||||
Self::read_framebuffer_to_image(self.gl.clone(), self.framebuffer_id, source_rectangle)
|
||||
Self::read_framebuffer_to_image(&self.gl, self.framebuffer_id, source_rectangle)
|
||||
}
|
||||
|
||||
fn read_framebuffer_to_image(
|
||||
gl: Rc<dyn Gl>,
|
||||
gl: &Rc<dyn Gl>,
|
||||
framebuffer_id: u32,
|
||||
source_rectangle: Rect<u32>,
|
||||
) -> Option<RgbaImage> {
|
||||
|
@ -656,7 +746,7 @@ impl Framebuffer {
|
|||
}
|
||||
|
||||
pub struct OffscreenRenderingContext {
|
||||
parent_context: SurfmanRenderingContext,
|
||||
parent_context: Rc<WindowRenderingContext>,
|
||||
size: Cell<Size2D<u32>>,
|
||||
back_framebuffer: RefCell<Framebuffer>,
|
||||
front_framebuffer: RefCell<Option<Framebuffer>>,
|
||||
|
@ -665,7 +755,7 @@ pub struct OffscreenRenderingContext {
|
|||
type RenderToParentCallback = Box<dyn Fn(&glow::Context, Rect<i32>) + Send + Sync>;
|
||||
|
||||
impl OffscreenRenderingContext {
|
||||
fn new(parent_context: SurfmanRenderingContext, size: Size2D<u32>) -> Self {
|
||||
fn new(parent_context: Rc<WindowRenderingContext>, size: Size2D<u32>) -> Self {
|
||||
let next_framebuffer = Framebuffer::new(parent_context.gl_api(), size);
|
||||
Self {
|
||||
parent_context,
|
||||
|
@ -675,7 +765,7 @@ impl OffscreenRenderingContext {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn parent_context(&self) -> &SurfmanRenderingContext {
|
||||
pub fn parent_context(&self) -> &WindowRenderingContext {
|
||||
&self.parent_context
|
||||
}
|
||||
|
||||
|
@ -690,7 +780,7 @@ impl OffscreenRenderingContext {
|
|||
// Don't accept a `None` context for the read framebuffer.
|
||||
let front_framebuffer_id =
|
||||
NonZeroU32::new(self.front_framebuffer_id()?).map(NativeFramebuffer)?;
|
||||
let parent_context_framebuffer_id = self.parent_context.framebuffer();
|
||||
let parent_context_framebuffer_id = self.parent_context.0.framebuffer();
|
||||
let size = self.size.get();
|
||||
Some(Box::new(move |gl, target_rect| {
|
||||
Self::render_framebuffer_to_parent_context(
|
||||
|
@ -776,7 +866,7 @@ impl RenderingContext for OffscreenRenderingContext {
|
|||
}
|
||||
|
||||
fn make_current(&self) -> Result<(), surfman::Error> {
|
||||
self.parent_context.make_gl_context_current()
|
||||
self.parent_context.make_current()
|
||||
}
|
||||
|
||||
fn gl_api(&self) -> Rc<dyn gleam::gl::Gl> {
|
||||
|
@ -796,7 +886,7 @@ impl RenderingContext for OffscreenRenderingContext {
|
|||
}
|
||||
|
||||
fn connection(&self) -> Option<Connection> {
|
||||
Some(self.parent_context.connection())
|
||||
self.parent_context.connection()
|
||||
}
|
||||
|
||||
fn read_to_image(&self, source_rectangle: Rect<u32>) -> Option<RgbaImage> {
|
||||
|
|
|
@ -57,6 +57,7 @@ webxr = ["libservo/webxr"]
|
|||
webgpu = ["libservo/webgpu"]
|
||||
|
||||
[dependencies]
|
||||
dpi = { workspace = true }
|
||||
euclid = { workspace = true }
|
||||
libc = { workspace = true }
|
||||
libservo = { path = "../../components/servo", features = ["background_hang_monitor", "bluetooth"] }
|
||||
|
@ -67,6 +68,7 @@ getopts = { workspace = true }
|
|||
hitrace = { workspace = true, optional = true }
|
||||
mime_guess = { workspace = true }
|
||||
url = { workspace = true }
|
||||
raw-window-handle = { workspace = true }
|
||||
rustls = { workspace = true, features = ["aws-lc-rs"] }
|
||||
tokio = { workspace = true }
|
||||
tracing = { workspace = true, optional = true }
|
||||
|
@ -116,7 +118,6 @@ headers = { workspace = true }
|
|||
http = { workspace = true }
|
||||
net = { path = "../../components/net" }
|
||||
net_traits = { workspace = true }
|
||||
raw-window-handle = "0.6"
|
||||
serde_json = { workspace = true }
|
||||
shellwords = "1.0.0"
|
||||
surfman = { workspace = true, features = ["sm-x11", "sm-raw-window-handle-06"] }
|
||||
|
|
|
@ -12,7 +12,7 @@ use std::time::Duration;
|
|||
|
||||
use euclid::{Angle, Length, Point2D, Rotation3D, Scale, Size2D, UnknownUnit, Vector2D, Vector3D};
|
||||
use keyboard_types::{Modifiers, ShortcutMatcher};
|
||||
use log::{debug, info, warn};
|
||||
use log::{debug, info};
|
||||
use raw_window_handle::{HasDisplayHandle, HasWindowHandle};
|
||||
use servo::compositing::windowing::{
|
||||
AnimationState, EmbedderCoordinates, WebRenderDebugOption, WindowMethods,
|
||||
|
@ -22,14 +22,13 @@ use servo::servo_config::pref;
|
|||
use servo::servo_geometry::DeviceIndependentPixel;
|
||||
use servo::webrender_api::units::{DeviceIntPoint, DeviceIntRect, DeviceIntSize, DevicePixel};
|
||||
use servo::webrender_api::ScrollLocation;
|
||||
use servo::webrender_traits::rendering_context::{OffscreenRenderingContext, RenderingContext};
|
||||
use servo::webrender_traits::SurfmanRenderingContext;
|
||||
use servo::{
|
||||
Cursor, InputEvent, Key, KeyState, KeyboardEvent, MouseButton as ServoMouseButton,
|
||||
MouseButtonAction, MouseButtonEvent, MouseMoveEvent, Theme, TouchAction, TouchEvent,
|
||||
TouchEventType, TouchId, WebView, WheelDelta, WheelEvent, WheelMode,
|
||||
MouseButtonAction, MouseButtonEvent, MouseMoveEvent, OffscreenRenderingContext,
|
||||
RenderingContext, Theme, TouchAction, TouchEvent, TouchEventType, TouchId, WebView, WheelDelta,
|
||||
WheelEvent, WheelMode, WindowRenderingContext,
|
||||
};
|
||||
use surfman::{Connection, Context, Device, SurfaceType};
|
||||
use surfman::{Context, Device};
|
||||
use url::Url;
|
||||
use winit::dpi::{LogicalSize, PhysicalPosition, PhysicalSize};
|
||||
use winit::event::{
|
||||
|
@ -69,7 +68,7 @@ pub struct Window {
|
|||
/// The RenderingContext that renders directly onto the Window. This is used as
|
||||
/// the target of egui rendering and also where Servo rendering results are finally
|
||||
/// blitted.
|
||||
window_rendering_context: SurfmanRenderingContext,
|
||||
window_rendering_context: Rc<WindowRenderingContext>,
|
||||
|
||||
/// The `RenderingContext` of Servo itself. This is used to render Servo results
|
||||
/// temporarily until they can be blitted into the egui scene.
|
||||
|
@ -125,32 +124,16 @@ impl Window {
|
|||
let display_handle = event_loop
|
||||
.display_handle()
|
||||
.expect("could not get display handle from window");
|
||||
let connection =
|
||||
Connection::from_display_handle(display_handle).expect("Failed to create connection");
|
||||
let adapter = connection
|
||||
.create_adapter()
|
||||
.expect("Failed to create adapter");
|
||||
let window_handle = winit_window
|
||||
.window_handle()
|
||||
.expect("could not get window handle from window");
|
||||
let native_widget = connection
|
||||
.create_native_widget_from_window_handle(
|
||||
window_handle,
|
||||
winit_size_to_euclid_size(inner_size).to_i32().to_untyped(),
|
||||
)
|
||||
.expect("Failed to create native widget");
|
||||
|
||||
let window_rendering_context = SurfmanRenderingContext::create(&connection, &adapter, None)
|
||||
.expect("Failed to create window RenderingContext");
|
||||
let surface = window_rendering_context
|
||||
.create_surface(SurfaceType::Widget { native_widget })
|
||||
.expect("Failed to create surface");
|
||||
window_rendering_context
|
||||
.bind_surface(surface)
|
||||
.expect("Failed to bind surface");
|
||||
let window_rendering_context = Rc::new(
|
||||
WindowRenderingContext::new(display_handle, window_handle, &inner_size)
|
||||
.expect("Could not create RenderingContext for Window"),
|
||||
);
|
||||
|
||||
// Make sure the gl context is made current.
|
||||
window_rendering_context.make_gl_context_current().unwrap();
|
||||
window_rendering_context.make_current().unwrap();
|
||||
|
||||
let rendering_context_size = Size2D::new(inner_size.width, inner_size.height);
|
||||
let rendering_context =
|
||||
|
@ -633,13 +616,8 @@ impl WindowPortsMethods for Window {
|
|||
WindowEvent::Resized(new_size) => {
|
||||
if self.inner_size.get() != new_size {
|
||||
let rendering_context_size = Size2D::new(new_size.width, new_size.height);
|
||||
if let Err(error) = self
|
||||
.window_rendering_context
|
||||
.resize(rendering_context_size.to_i32())
|
||||
{
|
||||
warn!("Could not resize window RenderingContext: {error:?}");
|
||||
}
|
||||
|
||||
self.window_rendering_context
|
||||
.resize(rendering_context_size.to_i32());
|
||||
self.inner_size.set(new_size);
|
||||
webview.notify_rendering_context_resized();
|
||||
}
|
||||
|
|
|
@ -12,9 +12,8 @@ use euclid::{Box2D, Length, Point2D, Scale, Size2D};
|
|||
use servo::compositing::windowing::{AnimationState, EmbedderCoordinates, WindowMethods};
|
||||
use servo::servo_geometry::DeviceIndependentPixel;
|
||||
use servo::webrender_api::units::{DeviceIntSize, DevicePixel};
|
||||
use servo::webrender_traits::rendering_context::RenderingContext;
|
||||
use servo::webrender_traits::SurfmanRenderingContext;
|
||||
use surfman::Connection;
|
||||
use servo::{RenderingContext, SoftwareRenderingContext};
|
||||
use winit::dpi::PhysicalSize;
|
||||
|
||||
use super::app_state::RunningAppState;
|
||||
use crate::desktop::window_trait::WindowPortsMethods;
|
||||
|
@ -27,30 +26,24 @@ pub struct Window {
|
|||
inner_size: Cell<DeviceIntSize>,
|
||||
screen_size: Size2D<i32, DeviceIndependentPixel>,
|
||||
window_rect: Box2D<i32, DeviceIndependentPixel>,
|
||||
rendering_context: SurfmanRenderingContext,
|
||||
rendering_context: Rc<SoftwareRenderingContext>,
|
||||
}
|
||||
|
||||
impl Window {
|
||||
#[allow(clippy::new_ret_no_self)]
|
||||
pub fn new(servoshell_preferences: &ServoShellPreferences) -> Rc<dyn WindowPortsMethods> {
|
||||
let size = servoshell_preferences.initial_window_size;
|
||||
let connection = Connection::new().expect("Failed to create connection");
|
||||
let adapter = connection
|
||||
.create_software_adapter()
|
||||
.expect("Failed to create adapter");
|
||||
let rendering_context = SurfmanRenderingContext::create(
|
||||
&connection,
|
||||
&adapter,
|
||||
Some(size.to_untyped().to_i32()),
|
||||
)
|
||||
.expect("Failed to create WR surfman");
|
||||
|
||||
let device_pixel_ratio_override = servoshell_preferences.device_pixel_ratio_override;
|
||||
let device_pixel_ratio_override: Option<Scale<f32, DeviceIndependentPixel, DevicePixel>> =
|
||||
device_pixel_ratio_override.map(Scale::new);
|
||||
let hidpi_factor = device_pixel_ratio_override.unwrap_or_else(Scale::identity);
|
||||
|
||||
let inner_size = Cell::new((size.to_f32() * hidpi_factor).to_i32());
|
||||
let inner_size = (size.to_f32() * hidpi_factor).to_i32();
|
||||
let physical_size = PhysicalSize::new(inner_size.width as u32, inner_size.height as u32);
|
||||
let rendering_context =
|
||||
SoftwareRenderingContext::new(physical_size).expect("Failed to create WR surfman");
|
||||
|
||||
let window_rect = Box2D::from_origin_and_size(Point2D::zero(), size.to_i32());
|
||||
|
||||
let screen_size = servoshell_preferences.screen_size_override.map_or_else(
|
||||
|
@ -62,10 +55,10 @@ impl Window {
|
|||
animation_state: Cell::new(AnimationState::Idle),
|
||||
fullscreen: Cell::new(false),
|
||||
device_pixel_ratio_override,
|
||||
inner_size,
|
||||
inner_size: Cell::new(inner_size),
|
||||
screen_size,
|
||||
window_rect,
|
||||
rendering_context,
|
||||
rendering_context: Rc::new(rendering_context),
|
||||
};
|
||||
|
||||
Rc::new(window)
|
||||
|
@ -150,9 +143,7 @@ impl WindowPortsMethods for Window {
|
|||
}
|
||||
|
||||
fn rendering_context(&self) -> Rc<dyn RenderingContext> {
|
||||
// `SurfmanRenderingContext` uses shared ownership internally so cloning it here does
|
||||
// not create a new one really.
|
||||
Rc::new(self.rendering_context.clone())
|
||||
self.rendering_context.clone()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,8 +21,7 @@ use servo::base::id::WebViewId;
|
|||
use servo::servo_geometry::DeviceIndependentPixel;
|
||||
use servo::servo_url::ServoUrl;
|
||||
use servo::webrender_api::units::DevicePixel;
|
||||
use servo::webrender_traits::rendering_context::{OffscreenRenderingContext, RenderingContext};
|
||||
use servo::{LoadStatus, WebView};
|
||||
use servo::{LoadStatus, OffscreenRenderingContext, RenderingContext, WebView};
|
||||
use winit::event::{ElementState, MouseButton, WindowEvent};
|
||||
use winit::event_loop::ActiveEventLoop;
|
||||
use winit::window::Window;
|
||||
|
@ -429,7 +428,7 @@ impl Minibrowser {
|
|||
.parent_context()
|
||||
.prepare_for_rendering();
|
||||
self.context.paint(window);
|
||||
let _ = self.rendering_context.parent_context().present();
|
||||
self.rendering_context.parent_context().present();
|
||||
}
|
||||
|
||||
/// Updates the location field from the given [WebViewManager], unless the user has started
|
||||
|
|
|
@ -11,8 +11,7 @@ use euclid::{Length, Scale};
|
|||
use servo::compositing::windowing::WindowMethods;
|
||||
use servo::servo_geometry::DeviceIndependentPixel;
|
||||
use servo::webrender_api::units::{DeviceIntPoint, DeviceIntSize, DevicePixel};
|
||||
use servo::webrender_traits::rendering_context::RenderingContext;
|
||||
use servo::{Cursor, WebView};
|
||||
use servo::{Cursor, RenderingContext, WebView};
|
||||
|
||||
use super::app_state::RunningAppState;
|
||||
|
||||
|
|
|
@ -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(),
|
||||
let (display_handle, window_handle) = unsafe {
|
||||
(
|
||||
DisplayHandle::borrow_raw(init_opts.display_handle),
|
||||
WindowHandle::borrow_raw(init_opts.window_handle),
|
||||
)
|
||||
};
|
||||
SurfaceType::Widget { native_widget }
|
||||
},
|
||||
};
|
||||
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