Skip to content

Commit

Permalink
Get the glwindow test XR device to share a GL context with WebGL
Browse files Browse the repository at this point in the history
  • Loading branch information
Alan Jeffrey committed Jul 17, 2019
1 parent bd730e7 commit b19e7d1
Show file tree
Hide file tree
Showing 7 changed files with 113 additions and 27 deletions.
5 changes: 3 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion ports/glutin/app.rs
Expand Up @@ -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(),
));
Expand Down
24 changes: 23 additions & 1 deletion ports/glutin/context.rs
Expand Up @@ -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;

Expand Down Expand Up @@ -136,6 +136,28 @@ impl GlContext {
}
}

pub fn new_window<T>(
&self,
cb: ContextBuilder<T>,
wb: WindowBuilder,
el: &EventsLoop
) -> Result<WindowedContext<NotCurrent>, 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 {
Expand Down
19 changes: 11 additions & 8 deletions ports/glutin/embedder.rs
Expand Up @@ -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;
Expand All @@ -20,13 +21,18 @@ use std::cell::RefCell;
use std::rc::Rc;

pub struct EmbedderCallbacks {
window: Rc<dyn WindowPortsMethods>,
events_loop: Rc<RefCell<EventsLoop>>,
gl: Rc<dyn gl::Gl>,
}

impl EmbedderCallbacks {
pub fn new(events_loop: Rc<RefCell<EventsLoop>>, gl: Rc<dyn gl::Gl>) -> EmbedderCallbacks {
EmbedderCallbacks { events_loop, gl }
pub fn new(
window: Rc<dyn WindowPortsMethods>,
events_loop: Rc<RefCell<EventsLoop>>,
gl: Rc<dyn gl::Gl>
) -> EmbedderCallbacks {
EmbedderCallbacks { window, events_loop, gl }
}
}

Expand Down Expand Up @@ -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);
}
}
Expand Down
52 changes: 44 additions & 8 deletions ports/glutin/headed_window.rs
Expand Up @@ -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")]
Expand Down Expand Up @@ -55,6 +56,7 @@ fn builder_with_platform_options(builder: glutin::WindowBuilder) -> glutin::Wind

pub struct Window {
gl_context: RefCell<GlContext>,
events_loop: Rc<RefCell<EventsLoop>>,
screen_size: TypedSize2D<u32, DeviceIndependentPixel>,
inner_size: Cell<TypedSize2D<u32, DeviceIndependentPixel>>,
mouse_down_button: Cell<Option<glutin::MouseButton>>,
Expand Down Expand Up @@ -83,8 +85,9 @@ fn window_creation_scale_factor() -> TypedScale<f32, DeviceIndependentPixel, Dev
impl Window {
pub fn new(
win_size: TypedSize2D<u32, DeviceIndependentPixel>,
events_loop: &glutin::EventsLoop,
) -> Rc<dyn WindowPortsMethods> {
sharing: Option<&GlContext>,
events_loop: Rc<RefCell<EventsLoop>>,
) -> Window {
let opts = opts::get();

// If there's no chrome, start off with the window invisible. It will be set to visible in
Expand Down Expand Up @@ -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"))]
{
Expand All @@ -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,
Expand Down Expand Up @@ -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)),
Expand All @@ -180,7 +185,7 @@ impl Window {

window.present();

Rc::new(window)
window
}

fn handle_received_character(&self, mut ch: char) {
Expand Down Expand Up @@ -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<gl::GLsizei> {
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<Box<dyn webxr::glwindow::GlWindow>, ()> {
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<dyn gl::Gl> {
self.gl.clone()
Expand Down
35 changes: 29 additions & 6 deletions ports/glutin/headless_window.rs
Expand Up @@ -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};
Expand Down Expand Up @@ -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);
Expand All @@ -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());

Expand All @@ -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,
Expand Down Expand Up @@ -106,7 +107,7 @@ pub struct Window {

impl Window {
pub fn new(size: TypedSize2D<u32, DeviceIndependentPixel>) -> Rc<dyn WindowPortsMethods> {
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
Expand Down Expand Up @@ -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<gl::GLsizei> {
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<Box<dyn webxr::glwindow::GlWindow>, ()> {
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),
}))
}
}
2 changes: 1 addition & 1 deletion ports/glutin/window_trait.rs
Expand Up @@ -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<WindowEvent>;
fn id(&self) -> Option<glutin::WindowId>;
fn has_events(&self) -> bool;
Expand Down

0 comments on commit b19e7d1

Please sign in to comment.