Glutin update: new Context API

This commit is contained in:
Paul Rouget 2019-04-29 14:11:46 +02:00 committed by Josh Matthews
parent 7f61160277
commit 53bb2e8743
4 changed files with 115 additions and 45 deletions

65
ports/glutin/context.rs Normal file
View file

@ -0,0 +1,65 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* 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 glutin::{WindowedContext, NotCurrent, PossiblyCurrent};
pub enum GlContext {
Current(WindowedContext<PossiblyCurrent>),
NotCurrent(WindowedContext<NotCurrent>),
// Used a temporary value as we switch from Current to NotCurrent.
None,
}
impl GlContext {
pub fn window(&self) -> &glutin::Window {
match self {
GlContext::Current(c) => c.window(),
GlContext::NotCurrent(c) => c.window(),
GlContext::None => unreachable!(),
}
}
pub fn make_current(&mut self) {
*self = match std::mem::replace(self, GlContext::None) {
GlContext::Current(c) => {
warn!("Making an already current context current");
GlContext::Current(c)
},
GlContext::NotCurrent(c) => {
let c = unsafe {
c.make_current().expect("Couldn't make window current")
};
GlContext::Current(c)
}
GlContext::None => unreachable!(),
}
}
pub fn make_not_current(&mut self) {
*self = match std::mem::replace(self, GlContext::None) {
GlContext::Current(c) => {
let c = unsafe {
c.make_not_current().expect("Couldn't make window not current")
};
GlContext::NotCurrent(c)
},
GlContext::NotCurrent(c) => {
warn!("Making an already not current context not current");
GlContext::NotCurrent(c)
}
GlContext::None => unreachable!(),
}
}
pub fn swap_buffers(&self) {
match self {
GlContext::Current(c) => {
if let Err(err) = c.swap_buffers() {
warn!("Failed to swap window buffers ({}).", err);
}
},
GlContext::NotCurrent(_) => {
error!("Context is not current. Forgot to call prepare_for_composite?");
},
GlContext::None => unreachable!(),
};
}
}

View file

@ -9,7 +9,6 @@ use crate::events_loop::EventsLoop;
use gleam::gl; use gleam::gl;
use glutin; use glutin;
use glutin::dpi::LogicalSize; use glutin::dpi::LogicalSize;
use glutin::{ContextBuilder, GlWindow};
use rust_webvr::GlWindowVRService; use rust_webvr::GlWindowVRService;
use servo::compositing::windowing::EmbedderMethods; use servo::compositing::windowing::EmbedderMethods;
use servo::embedder_traits::EventLoopWaker; use servo::embedder_traits::EventLoopWaker;
@ -52,14 +51,13 @@ impl EmbedderMethods for EmbedderCallbacks {
.with_dimensions(size) .with_dimensions(size)
.with_visibility(false) .with_visibility(false)
.with_multitouch(); .with_multitouch();
let context_builder = ContextBuilder::new() let context = glutin::ContextBuilder::new()
.with_gl(app::gl_version()) .with_gl(app::gl_version())
.with_vsync(false); // Assume the browser vsync is the same as the test VR window vsync .with_vsync(false) // Assume the browser vsync is the same as the test VR window vsync
let gl_window = .build_windowed(window_builder, &*self.events_loop.borrow().as_winit())
GlWindow::new(window_builder, context_builder, &*self.events_loop.borrow().as_winit()) .expect("Failed to create window.");
.expect("Failed to create window.");
let gl = self.gl.clone(); let gl = self.gl.clone();
let (service, heartbeat) = GlWindowVRService::new(name, gl_window, gl); let (service, heartbeat) = GlWindowVRService::new(name, context, gl);
services.register(Box::new(service)); services.register(Box::new(service));
heartbeats.push(Box::new(heartbeat)); heartbeats.push(Box::new(heartbeat));

View file

@ -5,6 +5,7 @@
//! A glutin window implementation. //! A glutin window implementation.
use crate::app; use crate::app;
use crate::context::GlContext;
use crate::keyutils::keyboard_event_from_winit; use crate::keyutils::keyboard_event_from_winit;
use crate::window_trait::{WindowPortsMethods, LINE_HEIGHT}; use crate::window_trait::{WindowPortsMethods, LINE_HEIGHT};
use euclid::{TypedPoint2D, TypedScale, TypedSize2D, TypedVector2D}; use euclid::{TypedPoint2D, TypedScale, TypedSize2D, TypedVector2D};
@ -14,7 +15,7 @@ use glutin::dpi::{LogicalPosition, LogicalSize, PhysicalSize};
use glutin::os::macos::{ActivationPolicy, WindowBuilderExt}; use glutin::os::macos::{ActivationPolicy, WindowBuilderExt};
#[cfg(any(target_os = "linux", target_os = "windows"))] #[cfg(any(target_os = "linux", target_os = "windows"))]
use glutin::Icon; use glutin::Icon;
use glutin::{Api, ContextBuilder, GlContext, GlWindow}; use glutin::Api;
use glutin::{ElementState, KeyboardInput, MouseButton, MouseScrollDelta, TouchPhase}; use glutin::{ElementState, KeyboardInput, MouseButton, MouseScrollDelta, TouchPhase};
#[cfg(any(target_os = "linux", target_os = "windows"))] #[cfg(any(target_os = "linux", target_os = "windows"))]
use image; use image;
@ -53,7 +54,7 @@ fn builder_with_platform_options(builder: glutin::WindowBuilder) -> glutin::Wind
} }
pub struct Window { pub struct Window {
gl_window: GlWindow, gl_context: RefCell<GlContext>,
screen_size: TypedSize2D<u32, DeviceIndependentPixel>, screen_size: TypedSize2D<u32, DeviceIndependentPixel>,
inner_size: Cell<TypedSize2D<u32, DeviceIndependentPixel>>, inner_size: Cell<TypedSize2D<u32, DeviceIndependentPixel>>,
mouse_down_button: Cell<Option<glutin::MouseButton>>, mouse_down_button: Cell<Option<glutin::MouseButton>>,
@ -106,7 +107,7 @@ impl Window {
window_builder = builder_with_platform_options(window_builder); window_builder = builder_with_platform_options(window_builder);
let mut context_builder = ContextBuilder::new() let mut context_builder = glutin::ContextBuilder::new()
.with_gl(app::gl_version()) .with_gl(app::gl_version())
.with_vsync(opts.enable_vsync); .with_vsync(opts.enable_vsync);
@ -114,21 +115,19 @@ impl Window {
context_builder = context_builder.with_multisampling(MULTISAMPLES) context_builder = context_builder.with_multisampling(MULTISAMPLES)
} }
let glutin_window = GlWindow::new(window_builder, context_builder, &events_loop) let context = context_builder
.build_windowed(window_builder, &events_loop)
.expect("Failed to create window."); .expect("Failed to create window.");
#[cfg(any(target_os = "linux", target_os = "windows"))] #[cfg(any(target_os = "linux", target_os = "windows"))]
{ {
let icon_bytes = include_bytes!("../../resources/servo64.png"); let icon_bytes = include_bytes!("../../resources/servo64.png");
glutin_window.set_window_icon(Some(load_icon(icon_bytes))); context.window().set_window_icon(Some(load_icon(icon_bytes)));
} }
unsafe { let context = unsafe {
glutin_window context.make_current().expect("Couldn't make window current")
.context() };
.make_current()
.expect("Couldn't make window current");
}
let primary_monitor = events_loop.get_primary_monitor(); let primary_monitor = events_loop.get_primary_monitor();
@ -138,19 +137,20 @@ impl Window {
} = primary_monitor.get_dimensions(); } = primary_monitor.get_dimensions();
let screen_size = TypedSize2D::new(screen_width as u32, screen_height as u32); let screen_size = TypedSize2D::new(screen_width as u32, screen_height as u32);
// TODO(ajeffrey): can this fail? // TODO(ajeffrey): can this fail?
let LogicalSize { width, height } = glutin_window let LogicalSize { width, height } = context
.window()
.get_inner_size() .get_inner_size()
.expect("Failed to get window inner size."); .expect("Failed to get window inner size.");
let inner_size = TypedSize2D::new(width as u32, height as u32); let inner_size = TypedSize2D::new(width as u32, height as u32);
glutin_window.show(); context.window().show();
let gl = match glutin_window.context().get_api() { let gl = match context.get_api() {
Api::OpenGl => unsafe { Api::OpenGl => unsafe {
gl::GlFns::load_with(|s| glutin_window.get_proc_address(s) as *const _) gl::GlFns::load_with(|s| context.get_proc_address(s) as *const _)
}, },
Api::OpenGlEs => unsafe { Api::OpenGlEs => unsafe {
gl::GlesFns::load_with(|s| glutin_window.get_proc_address(s) as *const _) gl::GlesFns::load_with(|s| context.get_proc_address(s) as *const _)
}, },
Api::WebGl => unreachable!("webgl is unsupported"), Api::WebGl => unreachable!("webgl is unsupported"),
}; };
@ -159,8 +159,12 @@ impl Window {
gl.clear(gl::COLOR_BUFFER_BIT); gl.clear(gl::COLOR_BUFFER_BIT);
gl.finish(); gl.finish();
let mut context = GlContext::Current(context);
context.make_not_current();
let window = Window { let window = Window {
gl_window: glutin_window, gl_context: RefCell::new(context),
event_queue: RefCell::new(vec![]), event_queue: RefCell::new(vec![]),
mouse_down_button: Cell::new(None), mouse_down_button: Cell::new(None),
mouse_down_point: Cell::new(TypedPoint2D::new(0, 0)), mouse_down_point: Cell::new(TypedPoint2D::new(0, 0)),
@ -263,7 +267,7 @@ impl Window {
} }
fn device_hidpi_factor(&self) -> TypedScale<f32, DeviceIndependentPixel, DevicePixel> { fn device_hidpi_factor(&self) -> TypedScale<f32, DeviceIndependentPixel, DevicePixel> {
TypedScale::new(self.gl_window.get_hidpi_factor() as f32) TypedScale::new(self.gl_context.borrow().window().get_hidpi_factor() as f32)
} }
fn servo_hidpi_factor(&self) -> TypedScale<f32, DeviceIndependentPixel, DevicePixel> { fn servo_hidpi_factor(&self) -> TypedScale<f32, DeviceIndependentPixel, DevicePixel> {
@ -289,31 +293,33 @@ impl WindowPortsMethods for Window {
fn page_height(&self) -> f32 { fn page_height(&self) -> f32 {
let dpr = self.servo_hidpi_factor(); let dpr = self.servo_hidpi_factor();
let size = self let size = self
.gl_window .gl_context
.borrow()
.window()
.get_inner_size() .get_inner_size()
.expect("Failed to get window inner size."); .expect("Failed to get window inner size.");
size.height as f32 * dpr.get() size.height as f32 * dpr.get()
} }
fn set_title(&self, title: &str) { fn set_title(&self, title: &str) {
self.gl_window.set_title(title); self.gl_context.borrow().window().set_title(title);
} }
fn set_inner_size(&self, size: DeviceIntSize) { fn set_inner_size(&self, size: DeviceIntSize) {
let size = size.to_f32() / self.device_hidpi_factor(); let size = size.to_f32() / self.device_hidpi_factor();
self.gl_window self.gl_context.borrow_mut().window()
.set_inner_size(LogicalSize::new(size.width.into(), size.height.into())) .set_inner_size(LogicalSize::new(size.width.into(), size.height.into()))
} }
fn set_position(&self, point: DeviceIntPoint) { fn set_position(&self, point: DeviceIntPoint) {
let point = point.to_f32() / self.device_hidpi_factor(); let point = point.to_f32() / self.device_hidpi_factor();
self.gl_window self.gl_context.borrow_mut().window()
.set_position(LogicalPosition::new(point.x.into(), point.y.into())) .set_position(LogicalPosition::new(point.x.into(), point.y.into()))
} }
fn set_fullscreen(&self, state: bool) { fn set_fullscreen(&self, state: bool) {
if self.fullscreen.get() != state { if self.fullscreen.get() != state {
self.gl_window self.gl_context.borrow_mut().window()
.set_fullscreen(Some(self.primary_monitor.clone())); .set_fullscreen(Some(self.primary_monitor.clone()));
} }
self.fullscreen.set(state); self.fullscreen.set(state);
@ -363,7 +369,7 @@ impl WindowPortsMethods for Window {
Cursor::ZoomOut => MouseCursor::ZoomOut, Cursor::ZoomOut => MouseCursor::ZoomOut,
_ => MouseCursor::Default, _ => MouseCursor::Default,
}; };
self.gl_window.set_cursor(winit_cursor); self.gl_context.borrow_mut().window().set_cursor(winit_cursor);
} }
fn is_animating(&self) -> bool { fn is_animating(&self) -> bool {
@ -371,7 +377,7 @@ impl WindowPortsMethods for Window {
} }
fn id(&self) -> Option<glutin::WindowId> { fn id(&self) -> Option<glutin::WindowId> {
Some(self.gl_window.id()) Some(self.gl_context.borrow().window().id())
} }
fn winit_event_to_servo_event(&self, event: glutin::WindowEvent) { fn winit_event_to_servo_event(&self, event: glutin::WindowEvent) {
@ -435,10 +441,7 @@ impl WindowPortsMethods for Window {
self.event_queue.borrow_mut().push(WindowEvent::Quit); self.event_queue.borrow_mut().push(WindowEvent::Quit);
}, },
glutin::WindowEvent::Resized(size) => { glutin::WindowEvent::Resized(size) => {
// size is DeviceIndependentPixel. self.gl_context.borrow_mut().window().set_inner_size(size);
// gl_window.resize() takes DevicePixel.
let size = size.to_physical(self.device_hidpi_factor().get() as f64);
self.gl_window.resize(size);
// window.set_inner_size() takes DeviceIndependentPixel. // window.set_inner_size() takes DeviceIndependentPixel.
let (width, height) = size.into(); let (width, height) = size.into();
let new_size = TypedSize2D::new(width, height); let new_size = TypedSize2D::new(width, height);
@ -461,11 +464,15 @@ impl WindowMethods for Window {
// TODO(ajeffrey): can this fail? // TODO(ajeffrey): can this fail?
let dpr = self.device_hidpi_factor(); let dpr = self.device_hidpi_factor();
let LogicalSize { width, height } = self let LogicalSize { width, height } = self
.gl_window .gl_context
.borrow()
.window()
.get_outer_size() .get_outer_size()
.expect("Failed to get window outer size."); .expect("Failed to get window outer size.");
let LogicalPosition { x, y } = self let LogicalPosition { x, y } = self
.gl_window .gl_context
.borrow()
.window()
.get_position() .get_position()
.unwrap_or(LogicalPosition::new(0., 0.)); .unwrap_or(LogicalPosition::new(0., 0.));
let win_size = (TypedSize2D::new(width as f32, height as f32) * dpr).to_i32(); let win_size = (TypedSize2D::new(width as f32, height as f32) * dpr).to_i32();
@ -473,7 +480,9 @@ impl WindowMethods for Window {
let screen = (self.screen_size.to_f32() * dpr).to_i32(); let screen = (self.screen_size.to_f32() * dpr).to_i32();
let LogicalSize { width, height } = self let LogicalSize { width, height } = self
.gl_window .gl_context
.borrow()
.window()
.get_inner_size() .get_inner_size()
.expect("Failed to get window inner size."); .expect("Failed to get window inner size.");
let inner_size = (TypedSize2D::new(width as f32, height as f32) * dpr).to_i32(); let inner_size = (TypedSize2D::new(width as f32, height as f32) * dpr).to_i32();
@ -492,9 +501,8 @@ impl WindowMethods for Window {
} }
fn present(&self) { fn present(&self) {
if let Err(err) = self.gl_window.swap_buffers() { self.gl_context.borrow().swap_buffers();
warn!("Failed to swap window buffers ({}).", err); self.gl_context.borrow_mut().make_not_current();
}
} }
fn set_animation_state(&self, state: AnimationState) { fn set_animation_state(&self, state: AnimationState) {
@ -502,9 +510,7 @@ impl WindowMethods for Window {
} }
fn prepare_for_composite(&self) -> bool { fn prepare_for_composite(&self) -> bool {
if let Err(err) = unsafe { self.gl_window.context().make_current() } { self.gl_context.borrow_mut().make_current();
warn!("Couldn't make window current: {}", err);
}
true true
} }
} }

View file

@ -12,6 +12,7 @@ extern crate sig;
mod app; mod app;
mod browser; mod browser;
mod context;
mod embedder; mod embedder;
mod events_loop; mod events_loop;
mod headed_window; mod headed_window;