diff --git a/Cargo.lock b/Cargo.lock index 28c73cbceda..4f4bdfdd198 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5504,18 +5504,19 @@ dependencies = [ [[package]] name = "webxr" version = "0.0.1" -source = "git+https://github.com/servo/webxr#3951634a06e2f9417f04e8ada969589f5b8a01d2" +source = "git+https://github.com/servo/webxr#abc779798259d287539347a5d2048ae745f1f2ac" dependencies = [ "euclid 0.19.8 (registry+https://github.com/rust-lang/crates.io-index)", "gleam 0.6.18 (registry+https://github.com/rust-lang/crates.io-index)", "glutin 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "webxr-api 0.0.1 (git+https://github.com/servo/webxr)", ] [[package]] name = "webxr-api" version = "0.0.1" -source = "git+https://github.com/servo/webxr#3951634a06e2f9417f04e8ada969589f5b8a01d2" +source = "git+https://github.com/servo/webxr#abc779798259d287539347a5d2048ae745f1f2ac" dependencies = [ "euclid 0.19.8 (registry+https://github.com/rust-lang/crates.io-index)", "gleam 0.6.18 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/ports/glutin/app.rs b/ports/glutin/app.rs index cc67033127c..991662808f2 100644 --- a/ports/glutin/app.rs +++ b/ports/glutin/app.rs @@ -36,11 +36,12 @@ impl App { let window = if opts::get().headless { headless_window::Window::new(opts::get().initial_window_size) } else { - headed_window::Window::new(opts::get().initial_window_size, events_loop.borrow().as_winit()) + Rc::new(headed_window::Window::new(opts::get().initial_window_size, None, events_loop.clone())) }; // Implements embedder methods, used by libservo and constellation. let embedder = Box::new(EmbedderCallbacks::new( + window.clone(), events_loop.clone(), window.gl(), )); diff --git a/ports/glutin/context.rs b/ports/glutin/context.rs index 39749f82b90..c26db664b94 100644 --- a/ports/glutin/context.rs +++ b/ports/glutin/context.rs @@ -3,7 +3,7 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ use glutin::os::ContextTraitExt; -use glutin::{NotCurrent, PossiblyCurrent, WindowedContext}; +use glutin::{ContextBuilder, CreationError, EventsLoop, NotCurrent, PossiblyCurrent, WindowedContext, WindowBuilder}; use servo_media::player::context::GlContext as RawContext; use std::os::raw; @@ -136,6 +136,28 @@ impl GlContext { } } + pub fn new_window( + &self, + cb: ContextBuilder, + wb: WindowBuilder, + el: &EventsLoop + ) -> Result, CreationError> + where + T: glutin::ContextCurrentState, + { + match self { + GlContext::Current(ref c) => { + cb.with_shared_lists(c).build_windowed(wb, el) + }, + GlContext::NotCurrent(ref c) => { + cb.with_shared_lists(c).build_windowed(wb, el) + }, + GlContext::None => { + cb.build_windowed(wb, el) + }, + } + } + #[allow(dead_code)] pub fn egl_display(&self) -> Option<*const raw::c_void> { match self { diff --git a/ports/glutin/embedder.rs b/ports/glutin/embedder.rs index 878b282fa6c..fcebdd4d859 100644 --- a/ports/glutin/embedder.rs +++ b/ports/glutin/embedder.rs @@ -6,6 +6,7 @@ use crate::app; use crate::events_loop::EventsLoop; +use crate::window_trait::WindowPortsMethods; use gleam::gl; use glutin; use glutin::EventsLoopClosed; @@ -20,13 +21,18 @@ use std::cell::RefCell; use std::rc::Rc; pub struct EmbedderCallbacks { + window: Rc, events_loop: Rc>, gl: Rc, } impl EmbedderCallbacks { - pub fn new(events_loop: Rc>, gl: Rc) -> EmbedderCallbacks { - EmbedderCallbacks { events_loop, gl } + pub fn new( + window: Rc, + events_loop: Rc>, + gl: Rc + ) -> EmbedderCallbacks { + EmbedderCallbacks { window, events_loop, gl } } } @@ -79,12 +85,9 @@ impl EmbedderMethods for EmbedderCallbacks { } else if !opts::get().headless && pref!(dom.webxr.glwindow) { warn!("Creating test XR device"); let gl = self.gl.clone(); - let events_loop_clone = self.events_loop.clone(); - let events_loop_factory = Box::new(move || { - events_loop_clone.borrow_mut().take().ok_or(EventsLoopClosed) - }); - let gl_version = app::gl_version(); - let discovery = webxr::glwindow::GlWindowDiscovery::new(gl, events_loop_factory, gl_version); + let window = self.window.clone(); + let factory = Box::new(move || window.new_window()); + let discovery = webxr::glwindow::GlWindowDiscovery::new(gl, factory); xr.register(discovery); } } diff --git a/ports/glutin/headed_window.rs b/ports/glutin/headed_window.rs index fa416cbcc61..4de73fdcf78 100644 --- a/ports/glutin/headed_window.rs +++ b/ports/glutin/headed_window.rs @@ -6,9 +6,10 @@ use crate::app; use crate::context::GlContext; +use crate::events_loop::EventsLoop; use crate::keyutils::keyboard_event_from_winit; use crate::window_trait::{WindowPortsMethods, LINE_HEIGHT}; -use euclid::{TypedPoint2D, TypedScale, TypedSize2D, TypedVector2D}; +use euclid::{Size2D, TypedPoint2D, TypedScale, TypedSize2D, TypedVector2D}; use gleam::gl; use glutin::dpi::{LogicalPosition, LogicalSize, PhysicalSize}; #[cfg(target_os = "macos")] @@ -55,6 +56,7 @@ fn builder_with_platform_options(builder: glutin::WindowBuilder) -> glutin::Wind pub struct Window { gl_context: RefCell, + events_loop: Rc>, screen_size: TypedSize2D, inner_size: Cell>, mouse_down_button: Cell>, @@ -83,8 +85,9 @@ fn window_creation_scale_factor() -> TypedScale, - events_loop: &glutin::EventsLoop, - ) -> Rc { + sharing: Option<&GlContext>, + events_loop: Rc>, + ) -> Window { let opts = opts::get(); // If there's no chrome, start off with the window invisible. It will be set to visible in @@ -115,9 +118,10 @@ impl Window { context_builder = context_builder.with_multisampling(MULTISAMPLES) } - let context = context_builder - .build_windowed(window_builder, &events_loop) - .expect("Failed to create window."); + let context = match sharing { + Some(sharing) => sharing.new_window(context_builder, window_builder, events_loop.borrow().as_winit()), + None => context_builder.build_windowed(window_builder, events_loop.borrow().as_winit()), + }.expect("Failed to create window."); #[cfg(any(target_os = "linux", target_os = "windows"))] { @@ -129,7 +133,7 @@ impl Window { context.make_current().expect("Couldn't make window current") }; - let primary_monitor = events_loop.get_primary_monitor(); + let primary_monitor = events_loop.borrow().as_winit().get_primary_monitor(); let PhysicalSize { width: screen_width, @@ -165,6 +169,7 @@ impl Window { let window = Window { gl_context: RefCell::new(context), + events_loop, event_queue: RefCell::new(vec![]), mouse_down_button: Cell::new(None), mouse_down_point: Cell::new(TypedPoint2D::new(0, 0)), @@ -180,7 +185,7 @@ impl Window { window.present(); - Rc::new(window) + window } fn handle_received_character(&self, mut ch: char) { @@ -467,6 +472,37 @@ impl WindowPortsMethods for Window { } } +impl webxr::glwindow::GlWindow for Window { + fn make_current(&mut self) { + self.gl_context.get_mut().make_current(); + } + + fn swap_buffers(&mut self) { + self.gl_context.get_mut().swap_buffers(); + self.gl_context.get_mut().make_not_current(); + } + + fn size(&self) -> Size2D { + let dpr = self.device_hidpi_factor().get() as f64; + let LogicalSize { width, height } = self + .gl_context + .borrow() + .window() + .get_inner_size() + .expect("Failed to get window inner size."); + Size2D::new(width * dpr, height *dpr).to_i32() + } + + fn new_window(&self) -> Result, ()> { + let gl_context = self.gl_context.borrow(); + Ok(Box::new(Window::new( + self.inner_size.get(), + Some(&*gl_context), + self.events_loop.clone(), + ))) + } +} + impl WindowMethods for Window { fn gl(&self) -> Rc { self.gl.clone() diff --git a/ports/glutin/headless_window.rs b/ports/glutin/headless_window.rs index a91e073ed1d..934f15b3bd2 100644 --- a/ports/glutin/headless_window.rs +++ b/ports/glutin/headless_window.rs @@ -6,7 +6,7 @@ use crate::window_trait::WindowPortsMethods; use glutin; -use euclid::{TypedPoint2D, TypedScale, TypedSize2D}; +use euclid::{Size2D, TypedPoint2D, TypedScale, TypedSize2D}; use gleam::gl; use servo::compositing::windowing::{AnimationState, WindowEvent}; use servo::compositing::windowing::{EmbedderCoordinates, WindowMethods}; @@ -40,7 +40,7 @@ struct HeadlessContext { impl HeadlessContext { #[cfg(any(target_os = "linux", target_os = "macos"))] - fn new(width: u32, height: u32) -> HeadlessContext { + fn new(width: u32, height: u32, share: Option<&HeadlessContext>) -> HeadlessContext { let mut attribs = Vec::new(); attribs.push(osmesa_sys::OSMESA_PROFILE); @@ -51,8 +51,9 @@ impl HeadlessContext { attribs.push(3); attribs.push(0); - let context = - unsafe { osmesa_sys::OSMesaCreateContextAttribs(attribs.as_ptr(), ptr::null_mut()) }; + let share = share.map_or(ptr::null_mut(), |share| share._context as *mut _); + + let context = unsafe { osmesa_sys::OSMesaCreateContextAttribs(attribs.as_ptr(), share) }; assert!(!context.is_null()); @@ -78,7 +79,7 @@ impl HeadlessContext { } #[cfg(not(any(target_os = "linux", target_os = "macos")))] - fn new(width: u32, height: u32) -> HeadlessContext { + fn new(width: u32, height: u32, _share: Option<&HeadlessContext>) -> HeadlessContext { HeadlessContext { width: width, height: height, @@ -106,7 +107,7 @@ pub struct Window { impl Window { pub fn new(size: TypedSize2D) -> Rc { - let context = HeadlessContext::new(size.width, size.height); + let context = HeadlessContext::new(size.width, size.height, None); let gl = unsafe { gl::GlFns::load_with(|s| HeadlessContext::get_proc_address(s)) }; // Print some information about the headless renderer that @@ -209,3 +210,25 @@ impl WindowMethods for Window { MediaPlayerCtxt::GlApi::None } } + +impl webxr::glwindow::GlWindow for Window { + fn make_current(&mut self) {} + fn swap_buffers(&mut self) {} + fn size(&self) -> Size2D { + let dpr = self.servo_hidpi_factor().get(); + Size2D::new((self.context.width as f32 * dpr) as gl::GLsizei, (self.context.height as f32 * dpr) as gl::GLsizei) + } + fn new_window(&self) -> Result, ()> { + let width = self.context.width; + let height = self.context.height; + let share = Some(&self.context); + let context = HeadlessContext::new(width, height, share); + let gl = self.gl.clone(); + Ok(Box::new(Window { + context, + gl, + animation_state: Cell::new(AnimationState::Idle), + fullscreen: Cell::new(false), + })) + } +} diff --git a/ports/glutin/window_trait.rs b/ports/glutin/window_trait.rs index 2f1fbebd973..eab5b86bf0f 100644 --- a/ports/glutin/window_trait.rs +++ b/ports/glutin/window_trait.rs @@ -13,7 +13,7 @@ use servo::webrender_api::units::{DeviceIntPoint, DeviceIntSize}; // This should vary by zoom level and maybe actual text size (focused or under cursor) pub const LINE_HEIGHT: f32 = 38.0; -pub trait WindowPortsMethods: WindowMethods { +pub trait WindowPortsMethods: WindowMethods + webxr::glwindow::GlWindow { fn get_events(&self) -> Vec; fn id(&self) -> Option; fn has_events(&self) -> bool;