Auto merge of #25853 - asajeffrey:surfmanup, r=jdm

Replace glutin by winit + surfman 0.2

<!-- Please describe your changes on the following line: -->

This PR updates surfman to 0.2, and replaces glutin with winit+surfman.

---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `___` with appropriate data: -->
- [x] `./mach build -d` does not report any errors
- [x] `./mach test-tidy` does not report any errors
- [x] These changes do not require tests because this should all be invisible

<!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.-->

<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->
This commit is contained in:
bors-servo 2020-04-18 21:03:25 -04:00 committed by GitHub
commit 306e8ac5f9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
94 changed files with 2265 additions and 1513 deletions

View file

@ -53,7 +53,6 @@ clipboard = "0.5"
euclid = "0.20"
getopts = "0.2.11"
gleam = "0.9"
glutin = "0.21.0"
keyboard-types = "0.4.3"
lazy_static = "1"
libservo = {path = "../../components/servo"}
@ -61,19 +60,17 @@ libc = "0.2"
log = "0.4"
servo-media = {git = "https://github.com/servo/media"}
shellwords = "1.0.0"
surfman = { version = "0.2", features = ["sm-winit", "sm-x11"] }
tinyfiledialogs = "3.0"
webxr-api = { git = "https://github.com/servo/webxr", features = ["ipc"] }
webxr = { git = "https://github.com/servo/webxr", features = ["ipc", "glwindow", "headless"] }
winit = "0.19"
[target.'cfg(any(target_os = "linux", target_os = "windows"))'.dependencies]
image = "0.23"
[target.'cfg(any(target_os = "linux", target_os = "macos"))'.dependencies]
osmesa-sys = "0.1.2"
sig = "1.0"
[target.'cfg(target_os = "windows")'.dependencies]
winapi = { version = "0.3", features = ["wingdi", "winuser", "winnt", "winbase", "processenv", "namedpipeapi", "ntdef", "minwindef", "handleapi", "debugapi"] }
[target.'cfg(any(target_os = "macos", all(target_arch = "x86_64", target_os = "linux")))'.dependencies]
osmesa-src = {git = "https://github.com/servo/osmesa-src"}

View file

@ -9,7 +9,7 @@ use crate::embedder::EmbedderCallbacks;
use crate::events_loop::EventsLoop;
use crate::window_trait::WindowPortsMethods;
use crate::{headed_window, headless_window};
use glutin::WindowId;
use winit::WindowId;
use servo::compositing::windowing::WindowEvent;
use servo::config::opts::{self, parse_url_or_filename};
use servo::servo_config::pref;
@ -20,6 +20,7 @@ use std::collections::HashMap;
use std::env;
use std::mem;
use std::rc::Rc;
use webxr::glwindow::GlWindowDiscovery;
thread_local! {
pub static WINDOWS: RefCell<HashMap<WindowId, Rc<dyn WindowPortsMethods>>> = RefCell::new(HashMap::new());
@ -35,9 +36,6 @@ pub struct App {
impl App {
pub fn run(
angle: bool,
enable_vsync: bool,
use_msaa: bool,
no_native_titlebar: bool,
device_pixels_per_px: Option<f32>,
user_agent: Option<String>,
@ -50,21 +48,31 @@ impl App {
} else {
Rc::new(headed_window::Window::new(
opts::get().initial_window_size,
None,
events_loop.clone(),
angle,
enable_vsync,
use_msaa,
no_native_titlebar,
device_pixels_per_px,
))
};
let xr_discovery = if pref!(dom.webxr.glwindow) {
let window = window.clone();
let surfman = window.webrender_surfman();
let events_loop = events_loop.clone();
let factory = Box::new(move || Ok(window.new_glwindow(&*events_loop.borrow())));
Some(GlWindowDiscovery::new(
surfman.connection(),
surfman.adapter(),
surfman.context_attributes(),
factory,
))
} else {
None
};
// Implements embedder methods, used by libservo and constellation.
let embedder = Box::new(EmbedderCallbacks::new(
window.clone(),
events_loop.clone(),
window.gl(),
xr_discovery,
));
// Handle browser state.
@ -93,36 +101,36 @@ impl App {
}
// This function decides whether the event should be handled during `run_forever`.
fn winit_event_to_servo_event(&self, event: glutin::Event) -> glutin::ControlFlow {
fn winit_event_to_servo_event(&self, event: winit::Event) -> winit::ControlFlow {
match event {
// App level events
glutin::Event::Suspended(suspended) => {
winit::Event::Suspended(suspended) => {
self.suspended.set(suspended);
if !suspended {
self.event_queue.borrow_mut().push(WindowEvent::Idle);
}
},
glutin::Event::Awakened => {
winit::Event::Awakened => {
self.event_queue.borrow_mut().push(WindowEvent::Idle);
},
glutin::Event::DeviceEvent { .. } => {},
winit::Event::DeviceEvent { .. } => {},
// Window level events
glutin::Event::WindowEvent {
winit::Event::WindowEvent {
window_id, event, ..
} => {
return WINDOWS.with(|windows| {
match windows.borrow().get(&window_id) {
None => {
warn!("Got an event from unknown window");
glutin::ControlFlow::Break
winit::ControlFlow::Break
},
Some(window) => {
// Resize events need to be handled during run_forever
let cont = if let glutin::WindowEvent::Resized(_) = event {
glutin::ControlFlow::Continue
let cont = if let winit::WindowEvent::Resized(_) = event {
winit::ControlFlow::Continue
} else {
glutin::ControlFlow::Break
winit::ControlFlow::Break
};
window.winit_event_to_servo_event(event);
return cont;
@ -131,7 +139,7 @@ impl App {
});
},
}
glutin::ControlFlow::Break
winit::ControlFlow::Break
}
fn run_loop(self) {
@ -146,7 +154,7 @@ impl App {
// If there's no animations running then we block on the window event loop.
self.events_loop.borrow_mut().run_forever(|e| {
let cont = self.winit_event_to_servo_event(e);
if cont == glutin::ControlFlow::Continue {
if cont == winit::ControlFlow::Continue {
// Note we need to be careful to make sure that any events
// that are handled during run_forever aren't re-entrant,
// since we are handling them while holding onto a mutable borrow
@ -237,14 +245,3 @@ pub fn register_window(window: Rc<dyn WindowPortsMethods>) {
w.borrow_mut().insert(window.id(), window);
});
}
pub fn gl_version(angle: bool) -> glutin::GlRequest {
if angle {
glutin::GlRequest::Specific(glutin::Api::OpenGlEs, (3, 0))
} else {
glutin::GlRequest::GlThenGles {
opengl_version: (3, 2),
opengles_version: (3, 0),
}
}
}

View file

@ -1,172 +0,0 @@
/* 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::os::ContextTraitExt;
use glutin::{ContextBuilder, CreationError, EventsLoop, NotCurrent, PossiblyCurrent, WindowedContext, WindowBuilder};
use servo_media::player::context::GlContext as RawContext;
use std::os::raw;
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 resize(&mut self, size: glutin::dpi::PhysicalSize) {
if let GlContext::NotCurrent(_) = self {
self.make_current();
}
match self {
GlContext::Current(c) => c.resize(size),
_ => 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");
// Servo thinks that that this window is current,
// but it might be wrong, since other code may have
// changed the current GL context. Just to be on
// the safe side, we make it current anyway.
let c = unsafe {
c.make_current().expect("Couldn't make window 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!(),
};
}
#[allow(unreachable_code, unused_variables)]
pub fn raw_context(&self) -> RawContext {
match self {
GlContext::Current(c) => {
#[cfg(target_os = "linux")]
{
use glutin::os::unix::RawHandle;
let raw_handle = unsafe { c.raw_handle() };
return match raw_handle {
RawHandle::Egl(handle) => RawContext::Egl(handle as usize),
RawHandle::Glx(handle) => RawContext::Glx(handle as usize),
};
}
#[cfg(target_os = "windows")]
{
use glutin::os::windows::RawHandle;
let raw_handle = unsafe { c.raw_handle() };
return match raw_handle {
RawHandle::Egl(handle) => RawContext::Egl(handle as usize),
// @TODO(victor): RawContext::Wgl in servo-media
RawHandle::Wgl(_) => unimplemented!(),
}
}
// @TODO(victor): https://github.com/rust-windowing/glutin/pull/1221
// https://github.com/servo/media/pull/315
#[cfg(target_os = "macos")]
return unimplemented!();
#[cfg(not(any(
target_os = "linux",
target_os = "windows",
target_os = "macos",
)))]
unimplemented!()
}
GlContext::NotCurrent(_) => {
error!("Context is not current.");
RawContext::Unknown
}
GlContext::None => unreachable!(),
}
}
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 {
GlContext::Current(c) => unsafe { c.get_egl_display() },
GlContext::NotCurrent(_) => {
error!("Context is not current.");
None
},
GlContext::None => unreachable!(),
}
}
pub fn get_api(&self) -> glutin::Api {
match self {
GlContext::Current(c) => c.get_api(),
GlContext::NotCurrent(c) => c.get_api(),
GlContext::None => unreachable!(),
}
}
}

View file

@ -5,31 +5,27 @@
//! Implements the global methods required by Servo (not window/gl/compositor related).
use crate::events_loop::EventsLoop;
use crate::window_trait::WindowPortsMethods;
use gleam::gl;
use servo::canvas::{SurfaceProviders, WebGlExecutor};
use servo::compositing::windowing::EmbedderMethods;
use servo::embedder_traits::{EmbedderProxy, EventLoopWaker};
use servo::servo_config::{opts, pref};
use servo::servo_config::pref;
use std::cell::RefCell;
use std::rc::Rc;
use webxr::glwindow::GlWindowDiscovery;
pub struct EmbedderCallbacks {
window: Rc<dyn WindowPortsMethods>,
events_loop: Rc<RefCell<EventsLoop>>,
gl: Rc<dyn gl::Gl>,
xr_discovery: Option<GlWindowDiscovery>,
}
impl EmbedderCallbacks {
pub fn new(
window: Rc<dyn WindowPortsMethods>,
events_loop: Rc<RefCell<EventsLoop>>,
gl: Rc<dyn gl::Gl>,
xr_discovery: Option<GlWindowDiscovery>,
) -> EmbedderCallbacks {
EmbedderCallbacks {
window,
events_loop,
gl,
xr_discovery,
}
}
}
@ -48,13 +44,8 @@ impl EmbedderMethods for EmbedderCallbacks {
) {
if pref!(dom.webxr.test) {
xr.register_mock(webxr::headless::HeadlessMockDiscovery::new());
} else if !opts::get().headless && pref!(dom.webxr.glwindow) {
warn!("Creating test XR device");
let gl = self.gl.clone();
let window = self.window.clone();
let factory = Box::new(move || window.new_window());
let discovery = webxr::glwindow::GlWindowDiscovery::new(gl, factory);
xr.register(discovery);
} else if let Some(xr_discovery) = self.xr_discovery.take() {
xr.register(xr_discovery);
}
}
}

View file

@ -5,7 +5,7 @@
//! An event loop implementation that works in headless mode.
use glutin;
use winit;
use servo::embedder_traits::EventLoopWaker;
use std::sync::{Arc, Condvar, Mutex};
use std::rc::Rc;
@ -14,8 +14,8 @@ use std::time;
#[allow(dead_code)]
enum EventLoop {
/// A real Glutin windowing event loop.
Glutin(Option<glutin::EventsLoop>),
/// A real Winit windowing event loop.
Winit(Option<winit::EventsLoop>),
/// A fake event loop which contains a signalling flag used to ensure
/// that pending events get processed in a timely fashion, and a condition
/// variable to allow waiting on that flag changing state.
@ -29,14 +29,14 @@ impl EventsLoop {
// but on Linux, the event loop requires a X11 server.
#[cfg(not(target_os = "linux"))]
pub fn new(_headless: bool) -> Rc<RefCell<EventsLoop>> {
Rc::new(RefCell::new(EventsLoop(EventLoop::Glutin(Some(glutin::EventsLoop::new())))))
Rc::new(RefCell::new(EventsLoop(EventLoop::Winit(Some(winit::EventsLoop::new())))))
}
#[cfg(target_os = "linux")]
pub fn new(headless: bool) -> Rc<RefCell<EventsLoop>> {
let events_loop = if headless {
EventLoop::Headless(Arc::new((Mutex::new(false), Condvar::new())))
} else {
EventLoop::Glutin(Some(glutin::EventsLoop::new()))
EventLoop::Winit(Some(winit::EventsLoop::new()))
};
Rc::new(RefCell::new(EventsLoop(events_loop)))
}
@ -45,7 +45,7 @@ impl EventsLoop {
impl EventsLoop {
pub fn create_event_loop_waker(&self) -> Box<dyn EventLoopWaker> {
match self.0 {
EventLoop::Glutin(ref events_loop) => {
EventLoop::Winit(ref events_loop) => {
let events_loop = events_loop
.as_ref()
.expect("Can't create waker for unavailable event loop.");
@ -55,17 +55,18 @@ impl EventsLoop {
Box::new(HeadlessEventLoopWaker(data.clone())),
}
}
pub fn as_winit(&self) -> &glutin::EventsLoop {
pub fn as_winit(&self) -> &winit::EventsLoop {
match self.0 {
EventLoop::Glutin(Some(ref event_loop)) => event_loop,
EventLoop::Glutin(None) | EventLoop::Headless(..) =>
EventLoop::Winit(Some(ref event_loop)) => event_loop,
EventLoop::Winit(None) | EventLoop::Headless(..) =>
panic!("Can't access winit event loop while using the fake headless event loop"),
}
}
pub fn poll_events<F>(&mut self, callback: F) where F: FnMut(glutin::Event) {
pub fn poll_events<F>(&mut self, callback: F) where F: FnMut(winit::Event) {
match self.0 {
EventLoop::Glutin(Some(ref mut events_loop)) => events_loop.poll_events(callback),
EventLoop::Glutin(None) => (),
EventLoop::Winit(Some(ref mut events_loop)) => events_loop.poll_events(callback),
EventLoop::Winit(None) => (),
EventLoop::Headless(ref data) => {
// This is subtle - the use of the event loop in App::run_loop
// optionally calls run_forever, then always calls poll_events.
@ -80,9 +81,9 @@ impl EventsLoop {
}
}
}
pub fn run_forever<F>(&mut self, mut callback: F) where F: FnMut(glutin::Event) -> glutin::ControlFlow {
pub fn run_forever<F>(&mut self, mut callback: F) where F: FnMut(winit::Event) -> winit::ControlFlow {
match self.0 {
EventLoop::Glutin(ref mut events_loop) => {
EventLoop::Winit(ref mut events_loop) => {
let events_loop = events_loop
.as_mut()
.expect("Can't run an unavailable event loop.");
@ -92,7 +93,7 @@ impl EventsLoop {
let &(ref flag, ref condvar) = &**data;
while !*flag.lock().unwrap() {
self.sleep(flag, condvar);
if callback(glutin::Event::Awakened) == glutin::ControlFlow::Break {
if callback(winit::Event::Awakened) == winit::ControlFlow::Break {
break;
}
}
@ -115,10 +116,10 @@ impl EventsLoop {
}
struct HeadedEventLoopWaker {
proxy: Arc<glutin::EventsLoopProxy>,
proxy: Arc<winit::EventsLoopProxy>,
}
impl HeadedEventLoopWaker {
fn new(events_loop: &glutin::EventsLoop) -> HeadedEventLoopWaker {
fn new(events_loop: &winit::EventsLoop) -> HeadedEventLoopWaker {
let proxy = Arc::new(events_loop.create_proxy());
HeadedEventLoopWaker { proxy }
}

View file

@ -2,27 +2,21 @@
* 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/. */
//! A glutin window implementation.
//! A winit window implementation.
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::{
Angle, default::Size2D as UntypedSize2D, Point2D, Rotation3D, Scale, Size2D, UnknownUnit,
Angle, Point2D, Rotation3D, Scale, Size2D, UnknownUnit,
Vector2D, Vector3D,
};
use gleam::gl;
use glutin::dpi::{LogicalPosition, LogicalSize, PhysicalSize};
use winit::dpi::{LogicalPosition, LogicalSize, PhysicalSize};
#[cfg(target_os = "macos")]
use glutin::os::macos::{ActivationPolicy, WindowBuilderExt};
#[cfg(target_os = "linux")]
use glutin::os::unix::WindowExt;
use glutin::Api;
use winit::os::macos::{ActivationPolicy, WindowBuilderExt};
#[cfg(any(target_os = "linux", target_os = "windows"))]
use glutin::Icon;
use glutin::{ElementState, KeyboardInput, MouseButton, MouseScrollDelta, TouchPhase, VirtualKeyCode};
use winit::Icon;
use winit::{ElementState, KeyboardInput, MouseButton, MouseScrollDelta, TouchPhase, VirtualKeyCode};
#[cfg(any(target_os = "linux", target_os = "windows"))]
use image;
use keyboard_types::{Key, KeyState, KeyboardEvent};
@ -30,22 +24,32 @@ use servo::compositing::windowing::{AnimationState, MouseWindowEvent, WindowEven
use servo::compositing::windowing::{EmbedderCoordinates, WindowMethods};
use servo::embedder_traits::Cursor;
use servo::script_traits::{TouchEventType, WheelMode, WheelDelta};
use servo::servo_config::{opts, pref};
use servo::servo_config::opts;
use servo::servo_config::pref;
use servo::servo_geometry::DeviceIndependentPixel;
use servo::style_traits::DevicePixel;
use servo::webrender_api::ScrollLocation;
use servo::webrender_api::units::{DeviceIntPoint, DeviceIntRect, DeviceIntSize};
use servo::webrender_surfman::WebrenderSurfman;
use servo_media::player::context::{GlApi, GlContext as PlayerGLContext, NativeDisplay};
use std::cell::{Cell, RefCell};
use std::mem;
use std::rc::Rc;
#[cfg(target_os = "linux")]
use surfman::platform::generic::multi::connection::NativeConnection;
#[cfg(target_os = "linux")]
use surfman::platform::generic::multi::context::NativeContext;
use surfman::Connection;
use surfman::Device;
use surfman::GLApi;
use surfman::GLVersion;
use surfman::NativeWidget;
use surfman::SurfaceType;
#[cfg(target_os = "windows")]
use winapi;
const MULTISAMPLES: u16 = 16;
#[cfg(target_os = "macos")]
fn builder_with_platform_options(mut builder: glutin::WindowBuilder) -> glutin::WindowBuilder {
fn builder_with_platform_options(mut builder: winit::WindowBuilder) -> winit::WindowBuilder {
if opts::get().output_file.is_some() {
// Prevent the window from showing in Dock.app, stealing focus,
// when generating an output file.
@ -55,31 +59,25 @@ fn builder_with_platform_options(mut builder: glutin::WindowBuilder) -> glutin::
}
#[cfg(not(target_os = "macos"))]
fn builder_with_platform_options(builder: glutin::WindowBuilder) -> glutin::WindowBuilder {
fn builder_with_platform_options(builder: winit::WindowBuilder) -> winit::WindowBuilder {
builder
}
pub struct Window {
gl_context: RefCell<GlContext>,
events_loop: Rc<RefCell<EventsLoop>>,
winit_window: winit::Window,
webrender_surfman: WebrenderSurfman,
screen_size: Size2D<u32, DeviceIndependentPixel>,
inner_size: Cell<Size2D<u32, DeviceIndependentPixel>>,
mouse_down_button: Cell<Option<glutin::MouseButton>>,
mouse_down_button: Cell<Option<winit::MouseButton>>,
mouse_down_point: Cell<Point2D<i32, DevicePixel>>,
primary_monitor: glutin::MonitorId,
primary_monitor: winit::MonitorId,
event_queue: RefCell<Vec<WindowEvent>>,
mouse_pos: Cell<Point2D<i32, DevicePixel>>,
last_pressed: Cell<Option<KeyboardEvent>>,
animation_state: Cell<AnimationState>,
fullscreen: Cell<bool>,
gl: Rc<dyn gl::Gl>,
xr_rotation: Cell<Rotation3D<f32, UnknownUnit, UnknownUnit>>,
xr_translation: Cell<Vector3D<f32, UnknownUnit>>,
angle: bool,
enable_vsync: bool,
use_msaa: bool,
no_native_titlebar: bool,
device_pixels_per_px: Option<f32>,
xr_window_poses: RefCell<Vec<Rc<XRWindowPose>>>,
}
#[cfg(not(target_os = "windows"))]
@ -97,11 +95,7 @@ fn window_creation_scale_factor() -> Scale<f32, DeviceIndependentPixel, DevicePi
impl Window {
pub fn new(
win_size: Size2D<u32, DeviceIndependentPixel>,
sharing: Option<&Window>,
events_loop: Rc<RefCell<EventsLoop>>,
angle: bool,
enable_vsync: bool,
use_msaa: bool,
no_native_titlebar: bool,
device_pixels_per_px: Option<f32>,
) -> Window {
@ -117,7 +111,7 @@ impl Window {
let width = win_size.to_untyped().width;
let height = win_size.to_untyped().height;
let mut window_builder = glutin::WindowBuilder::new()
let mut window_builder = winit::WindowBuilder::new()
.with_title("Servo".to_string())
.with_decorations(!no_native_titlebar)
.with_transparency(no_native_titlebar)
@ -127,39 +121,14 @@ impl Window {
window_builder = builder_with_platform_options(window_builder);
let mut context_builder = glutin::ContextBuilder::new()
.with_gl(app::gl_version(angle))
.with_vsync(enable_vsync);
if use_msaa {
context_builder = context_builder.with_multisampling(MULTISAMPLES)
}
let context = match sharing {
Some(sharing) => sharing.gl_context.borrow().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.");
let winit_window = window_builder.build(events_loop.borrow().as_winit()).expect("Failed to create window.");
#[cfg(any(target_os = "linux", target_os = "windows"))]
{
let icon_bytes = include_bytes!("../../resources/servo64.png");
context.window().set_window_icon(Some(load_icon(icon_bytes)));
winit_window.set_window_icon(Some(load_icon(icon_bytes)));
}
if let Some(sharing) = sharing {
debug!("Making window {:?} not current", sharing.gl_context.borrow().window().id());
sharing.gl_context.borrow_mut().make_not_current();
}
let context = unsafe {
debug!("Making window {:?} current", context.window().id());
context.make_current().expect("Couldn't make window current")
};
let primary_monitor = events_loop.borrow().as_winit().get_primary_monitor();
let PhysicalSize {
@ -168,59 +137,43 @@ impl Window {
} = primary_monitor.get_dimensions();
let screen_size = Size2D::new(screen_width as u32, screen_height as u32);
// TODO(ajeffrey): can this fail?
let LogicalSize { width, height } = context
.window()
let LogicalSize { width, height } = winit_window
.get_inner_size()
.expect("Failed to get window inner size.");
let inner_size = Size2D::new(width as u32, height as u32);
context.window().show();
winit_window.show();
let gl = if let Some(sharing) = sharing {
sharing.gl.clone()
} else { match context.get_api() {
Api::OpenGl => unsafe {
gl::GlFns::load_with(|s| context.get_proc_address(s) as *const _)
},
Api::OpenGlEs => unsafe {
gl::GlesFns::load_with(|s| context.get_proc_address(s) as *const _)
},
Api::WebGl => unreachable!("webgl is unsupported"),
} };
// Initialize surfman
let connection = Connection::from_winit_window(&winit_window).expect("Failed to create connection");
let adapter = connection.create_adapter().expect("Failed to create adapter");
let native_widget = connection
.create_native_widget_from_winit_window(&winit_window)
.expect("Failed to create native widget");
let surface_type = SurfaceType::Widget { native_widget };
let webrender_surfman = WebrenderSurfman::create(
&connection,
&adapter,
surface_type,
).expect("Failed to create WR surfman");
gl.clear_color(0.6, 0.6, 0.6, 1.0);
gl.clear(gl::COLOR_BUFFER_BIT);
gl.finish();
let context = GlContext::Current(context);
debug!("Created window {:?}", context.window().id());
let window = Window {
gl_context: RefCell::new(context),
events_loop,
debug!("Created window {:?}", winit_window.id());
Window {
winit_window,
webrender_surfman,
event_queue: RefCell::new(vec![]),
mouse_down_button: Cell::new(None),
mouse_down_point: Cell::new(Point2D::new(0, 0)),
mouse_pos: Cell::new(Point2D::new(0, 0)),
last_pressed: Cell::new(None),
gl: gl.clone(),
animation_state: Cell::new(AnimationState::Idle),
fullscreen: Cell::new(false),
inner_size: Cell::new(inner_size),
primary_monitor,
screen_size,
xr_rotation: Cell::new(Rotation3D::identity()),
xr_translation: Cell::new(Vector3D::zero()),
angle,
enable_vsync,
use_msaa,
no_native_titlebar,
device_pixels_per_px,
};
window.present();
window
xr_window_poses: RefCell::new(vec![]),
}
}
fn handle_received_character(&self, mut ch: char) {
@ -245,7 +198,10 @@ impl Window {
KeyboardEvent::default()
};
event.key = Key::Character(ch.to_string());
self.handle_xr_translation(&event);
let xr_poses = self.xr_window_poses.borrow();
for xr_window_pose in &*xr_poses {
xr_window_pose.handle_xr_translation(&event);
}
self.event_queue
.borrow_mut()
.push(WindowEvent::Keyboard(event));
@ -258,68 +214,21 @@ impl Window {
self.last_pressed.set(Some(event));
} else if event.key != Key::Unidentified {
self.last_pressed.set(None);
self.handle_xr_rotation(&input);
let xr_poses = self.xr_window_poses.borrow();
for xr_window_pose in &*xr_poses {
xr_window_pose.handle_xr_rotation(&input);
}
self.event_queue
.borrow_mut()
.push(WindowEvent::Keyboard(event));
}
}
fn handle_xr_translation(&self, input: &KeyboardEvent) {
if input.state != KeyState::Down {
return;
}
const NORMAL_TRANSLATE: f32 = 0.1;
const QUICK_TRANSLATE: f32 = 1.0;
let mut x = 0.0;
let mut z = 0.0;
match input.key {
Key::Character(ref k) => match &**k {
"w" => z = -NORMAL_TRANSLATE,
"W" => z = -QUICK_TRANSLATE,
"s" => z = NORMAL_TRANSLATE,
"S" => z = QUICK_TRANSLATE,
"a" => x = -NORMAL_TRANSLATE,
"A" => x = -QUICK_TRANSLATE,
"d" => x = NORMAL_TRANSLATE,
"D" => x = QUICK_TRANSLATE,
_ => return,
},
_ => return,
};
let (old_x, old_y, old_z) = self.xr_translation.get().to_tuple();
let vec = Vector3D::new(x + old_x, old_y, z + old_z);
self.xr_translation.set(vec);
}
fn handle_xr_rotation(&self, input: &KeyboardInput) {
if input.state != glutin::ElementState::Pressed {
return;
}
let mut x = 0.0;
let mut y = 0.0;
match input.virtual_keycode {
Some(VirtualKeyCode::Up) => x = 1.0,
Some(VirtualKeyCode::Down) => x = -1.0,
Some(VirtualKeyCode::Left) => y = 1.0,
Some(VirtualKeyCode::Right) => y = -1.0,
_ => return,
};
if input.modifiers.shift {
x = 10.0 * x;
y = 10.0 * y;
}
let x: Rotation3D<_, UnknownUnit, UnknownUnit> = Rotation3D::around_x(Angle::degrees(x));
let y: Rotation3D<_, UnknownUnit, UnknownUnit> = Rotation3D::around_y(Angle::degrees(y));
let rotation = self.xr_rotation.get().post_rotate(&x).post_rotate(&y);
self.xr_rotation.set(rotation);
}
/// Helper function to handle a click
fn handle_mouse(
&self,
button: glutin::MouseButton,
action: glutin::ElementState,
button: winit::MouseButton,
action: winit::ElementState,
coords: Point2D<i32, DevicePixel>,
) {
use servo::script_traits::MouseButton;
@ -359,7 +268,7 @@ impl Window {
}
fn device_hidpi_factor(&self) -> Scale<f32, DeviceIndependentPixel, DevicePixel> {
Scale::new(self.gl_context.borrow().window().get_hidpi_factor() as f32)
Scale::new(self.winit_window.get_hidpi_factor() as f32)
}
fn servo_hidpi_factor(&self) -> Scale<f32, DeviceIndependentPixel, DevicePixel> {
@ -385,33 +294,31 @@ impl WindowPortsMethods for Window {
fn page_height(&self) -> f32 {
let dpr = self.servo_hidpi_factor();
let size = self
.gl_context
.borrow()
.window()
.winit_window
.get_inner_size()
.expect("Failed to get window inner size.");
size.height as f32 * dpr.get()
}
fn set_title(&self, title: &str) {
self.gl_context.borrow().window().set_title(title);
self.winit_window.set_title(title);
}
fn set_inner_size(&self, size: DeviceIntSize) {
let size = size.to_f32() / self.device_hidpi_factor();
self.gl_context.borrow_mut().window()
self.winit_window
.set_inner_size(LogicalSize::new(size.width.into(), size.height.into()))
}
fn set_position(&self, point: DeviceIntPoint) {
let point = point.to_f32() / self.device_hidpi_factor();
self.gl_context.borrow_mut().window()
self.winit_window
.set_position(LogicalPosition::new(point.x.into(), point.y.into()))
}
fn set_fullscreen(&self, state: bool) {
if self.fullscreen.get() != state {
self.gl_context.borrow_mut().window()
self.winit_window
.set_fullscreen(if state { Some(self.primary_monitor.clone()) } else { None });
}
self.fullscreen.set(state);
@ -422,7 +329,7 @@ impl WindowPortsMethods for Window {
}
fn set_cursor(&self, cursor: Cursor) {
use glutin::MouseCursor;
use winit::MouseCursor;
let winit_cursor = match cursor {
Cursor::Default => MouseCursor::Default,
@ -461,27 +368,27 @@ impl WindowPortsMethods for Window {
Cursor::ZoomOut => MouseCursor::ZoomOut,
_ => MouseCursor::Default,
};
self.gl_context.borrow_mut().window().set_cursor(winit_cursor);
self.winit_window.set_cursor(winit_cursor);
}
fn is_animating(&self) -> bool {
self.animation_state.get() == AnimationState::Animating
}
fn id(&self) -> glutin::WindowId {
self.gl_context.borrow().window().id()
fn id(&self) -> winit::WindowId {
self.winit_window.id()
}
fn winit_event_to_servo_event(&self, event: glutin::WindowEvent) {
fn winit_event_to_servo_event(&self, event: winit::WindowEvent) {
match event {
glutin::WindowEvent::ReceivedCharacter(ch) => self.handle_received_character(ch),
glutin::WindowEvent::KeyboardInput { input, .. } => self.handle_keyboard_input(input),
glutin::WindowEvent::MouseInput { state, button, .. } => {
winit::WindowEvent::ReceivedCharacter(ch) => self.handle_received_character(ch),
winit::WindowEvent::KeyboardInput { input, .. } => self.handle_keyboard_input(input),
winit::WindowEvent::MouseInput { state, button, .. } => {
if button == MouseButton::Left || button == MouseButton::Right {
self.handle_mouse(button, state, self.mouse_pos.get());
}
},
glutin::WindowEvent::CursorMoved { position, .. } => {
winit::WindowEvent::CursorMoved { position, .. } => {
let pos = position.to_physical(self.device_hidpi_factor().get() as f64);
let (x, y): (i32, i32) = pos.into();
self.mouse_pos.set(Point2D::new(x, y));
@ -491,7 +398,7 @@ impl WindowPortsMethods for Window {
x as f32, y as f32,
)));
},
glutin::WindowEvent::MouseWheel { delta, phase, .. } => {
winit::WindowEvent::MouseWheel { delta, phase, .. } => {
let (mut dx, mut dy, mode) = match delta {
MouseScrollDelta::LineDelta(dx, dy) => (dx as f64, (dy * LINE_HEIGHT) as f64,
WheelMode::DeltaLine),
@ -524,7 +431,7 @@ impl WindowPortsMethods for Window {
self.event_queue.borrow_mut().push(wheel_event);
self.event_queue.borrow_mut().push(scroll_event);
},
glutin::WindowEvent::Touch(touch) => {
winit::WindowEvent::Touch(touch) => {
use servo::script_traits::TouchId;
let phase = winit_phase_to_touch_event_type(touch.phase);
@ -537,19 +444,19 @@ impl WindowPortsMethods for Window {
.borrow_mut()
.push(WindowEvent::Touch(phase, id, point));
},
glutin::WindowEvent::Refresh => {
winit::WindowEvent::Refresh => {
self.event_queue.borrow_mut().push(WindowEvent::Refresh);
},
glutin::WindowEvent::CloseRequested => {
winit::WindowEvent::CloseRequested => {
self.event_queue.borrow_mut().push(WindowEvent::Quit);
},
glutin::WindowEvent::Resized(size) => {
let physical_size = size.to_physical(self.device_hidpi_factor().get() as f64);
self.gl_context.borrow_mut().resize(physical_size);
// window.set_inner_size() takes DeviceIndependentPixel.
winit::WindowEvent::Resized(size) => {
let (width, height) = size.into();
let new_size = Size2D::new(width, height);
if self.inner_size.get() != new_size {
let physical_size = size.to_physical(self.device_hidpi_factor().get() as f64);
let physical_size = Size2D::new(physical_size.width, physical_size.height);
self.webrender_surfman.resize(physical_size.to_i32()).expect("Failed to resize");
self.inner_size.set(new_size);
self.event_queue.borrow_mut().push(WindowEvent::Resize);
}
@ -557,75 +464,40 @@ impl WindowPortsMethods for Window {
_ => {},
}
}
}
impl webxr::glwindow::GlWindow for Window {
fn make_current(&self) {
debug!("Making window {:?} current", self.gl_context.borrow().window().id());
self.gl_context.borrow_mut().make_current();
}
fn new_glwindow(&self, events_loop: &EventsLoop) -> Box<dyn webxr::glwindow::GlWindow> {
let size = self.winit_window.get_outer_size()
.expect("Failed to get window outer size");
fn swap_buffers(&self) {
debug!("Swapping buffers on window {:?}", self.gl_context.borrow().window().id());
self.gl_context.borrow().swap_buffers();
self.gl_context.borrow_mut().make_not_current();
}
let mut window_builder = winit::WindowBuilder::new()
.with_title("Servo XR".to_string())
.with_dimensions(size)
.with_visibility(true);
fn size(&self) -> UntypedSize2D<gl::GLsizei> {
let dpr = self.device_hidpi_factor().get() as f64;
let size = self
.gl_context
.borrow()
.window()
.get_inner_size()
.expect("Failed to get window inner size.");
let size = size.to_physical(dpr);
let (w, h): (u32, u32) = size.into();
Size2D::new(w as i32, h as i32)
}
window_builder = builder_with_platform_options(window_builder);
fn get_rotation(&self) -> Rotation3D<f32, UnknownUnit, UnknownUnit> {
self.xr_rotation.get().clone()
}
let winit_window = window_builder.build(events_loop.as_winit())
.expect("Failed to create window.");
fn get_translation(&self) -> Vector3D<f32, UnknownUnit> {
self.xr_translation.get().clone()
}
fn new_window(&self) -> Result<Rc<dyn webxr::glwindow::GlWindow>, ()> {
let window = Rc::new(Window::new(
self.inner_size.get(),
Some(self),
self.events_loop.clone(),
self.angle,
self.enable_vsync,
self.use_msaa,
self.no_native_titlebar,
self.device_pixels_per_px,
));
app::register_window(window.clone());
Ok(window)
let pose = Rc::new(XRWindowPose {
xr_rotation: Cell::new(Rotation3D::identity()),
xr_translation: Cell::new(Vector3D::zero()),
});
self.xr_window_poses.borrow_mut().push(pose.clone());
Box::new(XRWindow { winit_window, pose })
}
}
impl WindowMethods for Window {
fn gl(&self) -> Rc<dyn gl::Gl> {
self.gl.clone()
}
fn get_coordinates(&self) -> EmbedderCoordinates {
// TODO(ajeffrey): can this fail?
let dpr = self.device_hidpi_factor();
let LogicalSize { width, height } = self
.gl_context
.borrow()
.window()
.winit_window
.get_outer_size()
.expect("Failed to get window outer size.");
let LogicalPosition { x, y } = self
.gl_context
.borrow()
.window()
.winit_window
.get_position()
.unwrap_or(LogicalPosition::new(0., 0.));
let win_size = (Size2D::new(width as f32, height as f32) * dpr).to_i32();
@ -633,45 +505,58 @@ impl WindowMethods for Window {
let screen = (self.screen_size.to_f32() * dpr).to_i32();
let LogicalSize { width, height } = self
.gl_context
.borrow()
.window()
.winit_window
.get_inner_size()
.expect("Failed to get window inner size.");
let inner_size = (Size2D::new(width as f32, height as f32) * dpr).to_i32();
let viewport = DeviceIntRect::new(Point2D::zero(), inner_size);
let framebuffer = DeviceIntSize::from_untyped(viewport.size.to_untyped());
EmbedderCoordinates {
viewport,
framebuffer,
window: (win_size, win_origin),
screen: screen,
// FIXME: Glutin doesn't have API for available size. Fallback to screen size
// FIXME: Winit doesn't have API for available size. Fallback to screen size
screen_avail: screen,
hidpi_factor: self.servo_hidpi_factor(),
}
}
fn present(&self) {
self.gl_context.borrow().swap_buffers();
self.gl_context.borrow_mut().make_not_current();
}
fn set_animation_state(&self, state: AnimationState) {
self.animation_state.set(state);
}
fn make_gl_context_current(&self) {
self.gl_context.borrow_mut().make_current();
fn webrender_surfman(&self) -> WebrenderSurfman {
self.webrender_surfman.clone()
}
fn get_gl_context(&self) -> PlayerGLContext {
if pref!(media.glvideo.enabled) {
return self.gl_context.borrow().raw_context();
if !pref!(media.glvideo.enabled) {
return PlayerGLContext::Unknown;
}
return PlayerGLContext::Unknown;
#[allow(unused_variables)]
let native_context = self.webrender_surfman.native_context();
#[cfg(target_os = "windows")]
return PlayerGLContext::Egl(native_context.egl_context as usize);
#[cfg(target_os = "linux")]
return match native_context {
NativeContext::Default(NativeContext::Default(native_context)) =>
PlayerGLContext::Egl(native_context.egl_context as usize),
NativeContext::Default(NativeContext::Alternate(native_context)) =>
PlayerGLContext::Egl(native_context.egl_context as usize),
NativeContext::Alternate(_) => unimplemented!(),
};
// @TODO(victor): https://github.com/servo/media/pull/315
#[cfg(target_os = "macos")]
#[allow(unreachable_code)]
return unimplemented!();
#[cfg(not(any(target_os = "linux", target_os = "windows", target_os = "macos")))]
return unimplemented!();
}
fn get_native_display(&self) -> NativeDisplay {
@ -679,48 +564,41 @@ impl WindowMethods for Window {
return NativeDisplay::Unknown;
}
#[allow(unused_variables)]
let native_connection = self.webrender_surfman.connection().native_connection();
#[allow(unused_variables)]
let native_device = self.webrender_surfman.native_device();
#[cfg(target_os = "windows")]
return NativeDisplay::Egl(native_device.egl_display as usize);
#[cfg(target_os = "linux")]
{
if let Some(display) = self.gl_context.borrow().window().get_wayland_display() {
return NativeDisplay::Wayland(display as usize);
} else if let Some(display) =
self.gl_context.borrow().window().get_xlib_display()
{
return NativeDisplay::X11(display as usize);
}
}
return match native_connection {
NativeConnection::Default(NativeConnection::Default(conn)) =>
NativeDisplay::Egl(conn.0 as usize),
NativeConnection::Default(NativeConnection::Alternate(conn)) =>
NativeDisplay::X11(conn.x11_display as usize),
NativeConnection::Alternate(_) => unimplemented!(),
};
#[cfg(any(target_os = "linux", target_os = "windows"))]
{
if let Some(display) = self.gl_context.borrow().egl_display() {
return NativeDisplay::Egl(display as usize);
}
}
// @TODO(victor): https://github.com/servo/media/pull/315
#[cfg(target_os = "macos")]
#[allow(unreachable_code)]
return unimplemented!();
NativeDisplay::Unknown
#[cfg(not(any(target_os = "linux", target_os = "windows", target_os = "macos")))]
return unimplemented!();
}
fn get_gl_api(&self) -> GlApi {
let api = self.gl_context.borrow().get_api();
let version = self.gl.get_string(gl::VERSION);
let version = version.trim_start_matches("OpenGL ES ");
let mut values = version.split(&['.', ' '][..]);
let major = values
.next()
.and_then(|v| v.parse::<u32>().ok())
.unwrap_or(1);
let minor = values
.next()
.and_then(|v| v.parse::<u32>().ok())
.unwrap_or(20);
let api = self.webrender_surfman.connection().gl_api();
let attributes = self.webrender_surfman.context_attributes();
let GLVersion { major, minor } = attributes.version;
match api {
glutin::Api::OpenGl if major >= 3 && minor >= 2 => GlApi::OpenGL3,
glutin::Api::OpenGl => GlApi::OpenGL,
glutin::Api::OpenGlEs if major > 1 => GlApi::Gles2,
glutin::Api::OpenGlEs => GlApi::Gles1,
_ => GlApi::None,
GLApi::GL if major >= 3 && minor >= 2 => GlApi::OpenGL3,
GLApi::GL => GlApi::OpenGL,
GLApi::GLES if major > 1 => GlApi::Gles2,
GLApi::GLES => GlApi::Gles1,
}
}
}
@ -748,3 +626,81 @@ fn load_icon(icon_bytes: &[u8]) -> Icon {
};
Icon::from_rgba(icon_rgba, icon_width, icon_height).expect("Failed to load icon")
}
struct XRWindow {
winit_window: winit::Window,
pose: Rc<XRWindowPose>,
}
struct XRWindowPose {
xr_rotation: Cell<Rotation3D<f32, UnknownUnit, UnknownUnit>>,
xr_translation: Cell<Vector3D<f32, UnknownUnit>>,
}
impl webxr::glwindow::GlWindow for XRWindow {
fn get_native_widget(&self, device: &Device) -> NativeWidget {
device.connection()
.create_native_widget_from_winit_window(&self.winit_window)
.expect("Failed to create native widget")
}
fn get_rotation(&self) -> Rotation3D<f32, UnknownUnit, UnknownUnit> {
self.pose.xr_rotation.get().clone()
}
fn get_translation(&self) -> Vector3D<f32, UnknownUnit> {
self.pose.xr_translation.get().clone()
}
}
impl XRWindowPose {
fn handle_xr_translation(&self, input: &KeyboardEvent) {
if input.state != KeyState::Down {
return;
}
const NORMAL_TRANSLATE: f32 = 0.1;
const QUICK_TRANSLATE: f32 = 1.0;
let mut x = 0.0;
let mut z = 0.0;
match input.key {
Key::Character(ref k) => match &**k {
"w" => z = -NORMAL_TRANSLATE,
"W" => z = -QUICK_TRANSLATE,
"s" => z = NORMAL_TRANSLATE,
"S" => z = QUICK_TRANSLATE,
"a" => x = -NORMAL_TRANSLATE,
"A" => x = -QUICK_TRANSLATE,
"d" => x = NORMAL_TRANSLATE,
"D" => x = QUICK_TRANSLATE,
_ => return,
},
_ => return,
};
let (old_x, old_y, old_z) = self.xr_translation.get().to_tuple();
let vec = Vector3D::new(x + old_x, old_y, z + old_z);
self.xr_translation.set(vec);
}
fn handle_xr_rotation(&self, input: &KeyboardInput) {
if input.state != winit::ElementState::Pressed {
return;
}
let mut x = 0.0;
let mut y = 0.0;
match input.virtual_keycode {
Some(VirtualKeyCode::Up) => x = 1.0,
Some(VirtualKeyCode::Down) => x = -1.0,
Some(VirtualKeyCode::Left) => y = 1.0,
Some(VirtualKeyCode::Right) => y = -1.0,
_ => return,
};
if input.modifiers.shift {
x = 10.0 * x;
y = 10.0 * y;
}
let x: Rotation3D<_, UnknownUnit, UnknownUnit> = Rotation3D::around_x(Angle::degrees(x));
let y: Rotation3D<_, UnknownUnit, UnknownUnit> = Rotation3D::around_y(Angle::degrees(y));
let rotation = self.xr_rotation.get().post_rotate(&x).post_rotate(&y);
self.xr_rotation.set(rotation);
}
}

View file

@ -4,93 +4,28 @@
//! A headless window implementation.
use crate::events_loop::EventsLoop;
use crate::window_trait::WindowPortsMethods;
use euclid::{default::Size2D as UntypedSize2D, Point2D, Rotation3D, Scale, Size2D, UnknownUnit, Vector3D};
use gleam::gl;
use glutin;
use euclid::{Point2D, Rotation3D, Scale, Size2D, UnknownUnit, Vector3D};
use winit;
use servo::compositing::windowing::{AnimationState, WindowEvent};
use servo::compositing::windowing::{EmbedderCoordinates, WindowMethods};
use servo::servo_geometry::DeviceIndependentPixel;
use servo::style_traits::DevicePixel;
use servo::webrender_api::units::{DeviceIntRect, DeviceIntSize};
use servo::webrender_api::units::DeviceIntRect;
use servo_media::player::context as MediaPlayerCtxt;
use servo::webrender_surfman::WebrenderSurfman;
use std::cell::Cell;
#[cfg(any(target_os = "linux", target_os = "macos"))]
use std::cell::RefCell;
#[cfg(any(target_os = "linux", target_os = "macos"))]
use std::ffi::CString;
#[cfg(any(target_os = "linux", target_os = "macos"))]
use std::mem;
use std::os::raw::c_void;
use std::ptr;
use std::rc::Rc;
#[cfg(any(target_os = "linux", target_os = "macos"))]
struct HeadlessContext {
width: u32,
height: u32,
context: osmesa_sys::OSMesaContext,
buffer: RefCell<Vec<u32>>,
}
#[cfg(not(any(target_os = "linux", target_os = "macos")))]
struct HeadlessContext {
width: u32,
height: u32,
}
impl HeadlessContext {
#[cfg(any(target_os = "linux", target_os = "macos"))]
fn new(width: u32, height: u32, share: Option<&HeadlessContext>) -> HeadlessContext {
let mut attribs = Vec::new();
attribs.push(osmesa_sys::OSMESA_PROFILE);
attribs.push(osmesa_sys::OSMESA_CORE_PROFILE);
attribs.push(osmesa_sys::OSMESA_CONTEXT_MAJOR_VERSION);
attribs.push(3);
attribs.push(osmesa_sys::OSMESA_CONTEXT_MINOR_VERSION);
attribs.push(3);
attribs.push(0);
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());
HeadlessContext {
width: width,
height: height,
context: context,
buffer: RefCell::new(vec![0; (width * height) as usize]),
}
}
#[cfg(not(any(target_os = "linux", target_os = "macos")))]
fn new(width: u32, height: u32, _share: Option<&HeadlessContext>) -> HeadlessContext {
HeadlessContext {
width: width,
height: height,
}
}
#[cfg(any(target_os = "linux", target_os = "macos"))]
fn get_proc_address(s: &str) -> *const c_void {
let c_str = CString::new(s).expect("Unable to create CString");
unsafe { mem::transmute(osmesa_sys::OSMesaGetProcAddress(c_str.as_ptr())) }
}
#[cfg(not(any(target_os = "linux", target_os = "macos")))]
fn get_proc_address(_: &str) -> *const c_void {
ptr::null() as *const _
}
}
use surfman::Connection;
use surfman::Device;
use surfman::NativeWidget;
use surfman::SurfaceType;
pub struct Window {
context: HeadlessContext,
webrender_surfman: WebrenderSurfman,
animation_state: Cell<AnimationState>,
fullscreen: Cell<bool>,
gl: Rc<dyn gl::Gl>,
device_pixels_per_px: Option<f32>,
}
@ -99,18 +34,19 @@ impl Window {
size: Size2D<u32, DeviceIndependentPixel>,
device_pixels_per_px: Option<f32>,
) -> Rc<dyn WindowPortsMethods> {
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
// can be useful in diagnosing CI failures on build machines.
println!("{}", gl.get_string(gl::VENDOR));
println!("{}", gl.get_string(gl::RENDERER));
println!("{}", gl.get_string(gl::VERSION));
// Initialize surfman
let connection = Connection::new().expect("Failed to create connection");
let adapter = connection.create_software_adapter().expect("Failed to create adapter");
let size = size.to_untyped().to_i32();
let surface_type = SurfaceType::Generic { size };
let webrender_surfman = WebrenderSurfman::create(
&connection,
&adapter,
surface_type,
).expect("Failed to create WR surfman");
let window = Window {
context,
gl,
webrender_surfman,
animation_state: Cell::new(AnimationState::Idle),
fullscreen: Cell::new(false),
device_pixels_per_px,
@ -136,13 +72,18 @@ impl WindowPortsMethods for Window {
false
}
fn id(&self) -> glutin::WindowId {
unsafe { glutin::WindowId::dummy() }
fn id(&self) -> winit::WindowId {
unsafe { winit::WindowId::dummy() }
}
fn page_height(&self) -> f32 {
let height = self.webrender_surfman
.context_surface_info()
.unwrap_or(None)
.map(|info| info.size.height)
.unwrap_or(0);
let dpr = self.servo_hidpi_factor();
self.context.height as f32 * dpr.get()
height as f32 * dpr.get()
}
fn set_fullscreen(&self, state: bool) {
@ -157,24 +98,27 @@ impl WindowPortsMethods for Window {
self.animation_state.get() == AnimationState::Animating
}
fn winit_event_to_servo_event(&self, _event: glutin::WindowEvent) {
fn winit_event_to_servo_event(&self, _event: winit::WindowEvent) {
// Not expecting any winit events.
}
fn new_glwindow(&self, _events_loop: &EventsLoop) -> Box<dyn webxr::glwindow::GlWindow> {
unimplemented!()
}
}
impl WindowMethods for Window {
fn gl(&self) -> Rc<dyn gl::Gl> {
self.gl.clone()
}
fn get_coordinates(&self) -> EmbedderCoordinates {
fn get_coordinates(&self) -> EmbedderCoordinates {
let dpr = self.servo_hidpi_factor();
let size = (Size2D::new(self.context.width, self.context.height).to_f32() * dpr).to_i32();
let size = self.webrender_surfman
.context_surface_info()
.unwrap_or(None)
.map(|info| Size2D::from_untyped(info.size))
.unwrap_or(Size2D::new(0, 0));
let viewport = DeviceIntRect::new(Point2D::zero(), size);
let framebuffer = DeviceIntSize::from_untyped(size.to_untyped());
EmbedderCoordinates {
viewport,
framebuffer,
framebuffer: size,
window: (size, Point2D::zero()),
screen: size,
screen_avail: size,
@ -182,31 +126,11 @@ impl WindowMethods for Window {
}
}
fn present(&self) {}
fn set_animation_state(&self, state: AnimationState) {
fn set_animation_state(&self, state: AnimationState) {
self.animation_state.set(state);
}
#[cfg(any(target_os = "linux", target_os = "macos"))]
fn make_gl_context_current(&self) {
unsafe {
let mut buffer = self.context.buffer.borrow_mut();
let ret = osmesa_sys::OSMesaMakeCurrent(
self.context.context,
buffer.as_mut_ptr() as *mut _,
gl::UNSIGNED_BYTE,
self.context.width as i32,
self.context.height as i32,
);
assert_ne!(ret, 0);
};
}
#[cfg(not(any(target_os = "linux", target_os = "macos")))]
fn make_gl_context_current(&self) {}
fn get_gl_context(&self) -> MediaPlayerCtxt::GlContext {
fn get_gl_context(&self) -> MediaPlayerCtxt::GlContext {
MediaPlayerCtxt::GlContext::Unknown
}
@ -217,32 +141,17 @@ impl WindowMethods for Window {
fn get_gl_api(&self) -> MediaPlayerCtxt::GlApi {
MediaPlayerCtxt::GlApi::None
}
fn webrender_surfman(&self) -> WebrenderSurfman {
self.webrender_surfman.clone()
}
}
impl webxr::glwindow::GlWindow for Window {
fn make_current(&self) {}
fn swap_buffers(&self) {}
fn size(&self) -> UntypedSize2D<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<Rc<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(Rc::new(Window {
context,
gl,
animation_state: Cell::new(AnimationState::Idle),
fullscreen: Cell::new(false),
device_pixels_per_px: self.device_pixels_per_px,
}))
fn get_native_widget(&self, _device: &Device) -> NativeWidget {
unimplemented!()
}
fn get_rotation(&self) -> Rotation3D<f32, UnknownUnit, UnknownUnit> {
Rotation3D::identity()
}

View file

@ -2,7 +2,7 @@
* 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::{ElementState, KeyboardInput, ModifiersState, VirtualKeyCode};
use winit::{ElementState, KeyboardInput, ModifiersState, VirtualKeyCode};
use keyboard_types::{Code, Key, KeyState, KeyboardEvent, Location, Modifiers};
// Some shortcuts use Cmd on Mac and Control on other systems.
@ -18,7 +18,7 @@ pub const CMD_OR_ALT: Modifiers = Modifiers::META;
pub const CMD_OR_ALT: Modifiers = Modifiers::ALT;
fn get_servo_key_from_winit_key(key: Option<VirtualKeyCode>) -> Key {
use glutin::VirtualKeyCode::*;
use winit::VirtualKeyCode::*;
// TODO: figure out how to map NavigateForward, NavigateBackward
// TODO: map the remaining keys if possible
let key = if let Some(key) = key {
@ -127,7 +127,7 @@ fn get_servo_key_from_winit_key(key: Option<VirtualKeyCode>) -> Key {
}
fn get_servo_location_from_winit_key(key: Option<VirtualKeyCode>) -> Location {
use glutin::VirtualKeyCode::*;
use winit::VirtualKeyCode::*;
// TODO: add more numpad keys
let key = if let Some(key) = key {
key

View file

@ -13,7 +13,6 @@ extern crate sig;
mod app;
mod backtrace;
mod browser;
mod context;
mod embedder;
mod events_loop;
mod headed_window;
@ -95,12 +94,6 @@ pub fn main() {
"clean-shutdown",
"Do not shutdown until all threads have finished (macos only)",
);
opts.optflag(
"",
"disable-vsync",
"Disable vsync mode in the compositor to allow profiling at more than monitor refresh rate",
);
opts.optflag("", "msaa", "Use multisample antialiasing in WebRender.");
opts.optflag("b", "no-native-titlebar", "Do not use native titlebar");
opts.optopt("", "device-pixel-ratio", "Device pixels per px", "");
opts.optopt(
@ -170,28 +163,19 @@ pub fn main() {
process::exit(0);
}
let angle = opts_matches.opt_present("angle");
let clean_shutdown = opts_matches.opt_present("clean-shutdown");
let do_not_use_native_titlebar =
opts_matches.opt_present("no-native-titlebar") || !(pref!(shell.native_titlebar.enabled));
let enable_vsync = !opts_matches.opt_present("disable-vsync");
let use_msaa = opts_matches.opt_present("msaa");
let device_pixels_per_px = opts_matches.opt_str("device-pixel-ratio").map(|dppx_str| {
dppx_str.parse().unwrap_or_else(|err| {
error!("Error parsing option: --device-pixel-ratio ({})", err);
process::exit(1);
})
});
let user_agent = opts_matches.opt_str("u");
App::run(
angle,
enable_vsync,
use_msaa,
do_not_use_native_titlebar,
device_pixels_per_px,
user_agent,
);
App::run(do_not_use_native_titlebar, device_pixels_per_px, user_agent);
platform::deinit(clean_shutdown)
}

View file

@ -5,7 +5,8 @@
//! Definition of Window.
//! Implemented by headless and headed windows.
use glutin;
use crate::events_loop::EventsLoop;
use winit;
use servo::compositing::windowing::{WindowEvent, WindowMethods};
use servo::embedder_traits::Cursor;
use servo::webrender_api::units::{DeviceIntPoint, DeviceIntSize};
@ -13,17 +14,18 @@ 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 + webxr::glwindow::GlWindow {
pub trait WindowPortsMethods: WindowMethods {
fn get_events(&self) -> Vec<WindowEvent>;
fn id(&self) -> glutin::WindowId;
fn id(&self) -> winit::WindowId;
fn has_events(&self) -> bool;
fn page_height(&self) -> f32;
fn get_fullscreen(&self) -> bool;
fn winit_event_to_servo_event(&self, event: glutin::WindowEvent);
fn winit_event_to_servo_event(&self, event: winit::WindowEvent);
fn is_animating(&self) -> bool;
fn set_title(&self, _title: &str) {}
fn set_inner_size(&self, _size: DeviceIntSize) {}
fn set_position(&self, _point: DeviceIntPoint) {}
fn set_fullscreen(&self, _state: bool) {}
fn set_cursor(&self, _cursor: Cursor) {}
fn new_glwindow(&self, events_loop: &EventsLoop) -> Box<dyn webxr::glwindow::GlWindow>;
}

View file

@ -30,9 +30,9 @@ lazy_static = "1.4"
libservo = {path = "../../components/servo"}
servo-media = {git = "https://github.com/servo/media"}
sparkle = "0.1"
surfman = { git = "https://github.com/pcwalton/surfman", branch = "multi" }
surfman = { git = "https://github.com/servo/surfman" }
surfman-chains-api = "0.2"
surfman-chains = { git = "https://github.com/asajeffrey/surfman-chains", branch = "multi" }
surfman-chains = { git = "https://github.com/asajeffrey/surfman-chains" }
[build-dependencies]
gst-plugin-version-helper = "0.1"

View file

@ -76,35 +76,20 @@ use servo::embedder_traits::EventLoopWaker;
use servo::msg::constellation_msg::TopLevelBrowsingContextId;
use servo::servo_url::ServoUrl;
use servo::webrender_api::units::DevicePixel;
use servo::webrender_surfman::WebrenderSurfman;
use servo::Servo;
use sparkle::gl;
use sparkle::gl::types::GLuint;
use sparkle::gl::Gl;
use surfman::connection::Connection as ConnectionAPI;
use surfman::device::Device as DeviceAPI;
use surfman::ContextAttributeFlags;
use surfman::ContextAttributes;
use surfman::GLApi;
use surfman::GLVersion;
use surfman::SurfaceAccess;
use surfman::Connection;
use surfman::Context;
use surfman::Device;
use surfman::SurfaceType;
use surfman_chains::SurfmanProvider;
use surfman_chains::SwapChain;
use surfman_chains_api::SwapChainAPI;
// For the moment, we only support wayland and cgl.
#[cfg(target_os = "macos")]
use surfman::platform::macos::cgl::device::Device;
#[cfg(all(unix, not(target_os = "macos")))]
use surfman::platform::unix::wayland::device::Device;
type Context = <Device as DeviceAPI>::Context;
type Connection = <Device as DeviceAPI>::Connection;
type NativeContext = <Device as DeviceAPI>::NativeContext;
type NativeConnection = <Connection as ConnectionAPI>::NativeConnection;
use std::cell::RefCell;
use std::collections::HashMap;
use std::convert::TryFrom;
@ -165,7 +150,7 @@ impl std::fmt::Debug for ConnectionWhichImplementsDebug {
#[derive(Debug)]
enum ServoWebSrcMsg {
Start(ConnectionWhichImplementsDebug, GLVersion, ServoUrl),
Start(ConnectionWhichImplementsDebug, ServoUrl),
GetSwapChain(Sender<SwapChain<Device>>),
Resize(Size2D<i32, DevicePixel>),
Heartbeat,
@ -180,41 +165,25 @@ const DEFAULT_FRAME_DURATION: Duration = Duration::from_micros(16_667);
struct ServoThread {
receiver: Receiver<ServoWebSrcMsg>,
swap_chain: SwapChain<Device>,
gfx: Rc<RefCell<ServoThreadGfx>>,
servo: Servo<ServoWebSrcWindow>,
}
struct ServoThreadGfx {
device: Device,
context: Context,
gl: Rc<Gl>,
}
impl ServoThread {
fn new(receiver: Receiver<ServoWebSrcMsg>) -> Self {
let (connection, version, url) = match receiver.recv() {
Ok(ServoWebSrcMsg::Start(connection, version, url)) => (connection.0, version, url),
let (connection, url) = match receiver.recv() {
Ok(ServoWebSrcMsg::Start(connection, url)) => (connection.0, url),
e => panic!("Failed to start ({:?})", e),
};
info!(
"Created new servo thread (GL v{}.{} for {})",
version.major, version.minor, url
);
info!("Created new servo thread for {}", url);
let embedder = Box::new(ServoWebSrcEmbedder);
let window = Rc::new(ServoWebSrcWindow::new(connection, version));
let swap_chain = window.swap_chain.clone();
let gfx = window.gfx.clone();
let window = Rc::new(ServoWebSrcWindow::new(connection));
let mut servo = Servo::new(embedder, window, None);
let id = TopLevelBrowsingContextId::new();
servo.handle_events(vec![WindowEvent::NewBrowser(url, id)]);
Self {
receiver,
swap_chain,
gfx,
servo,
}
Self { receiver, servo }
}
fn run(&mut self) {
@ -222,9 +191,7 @@ impl ServoThread {
debug!("Servo thread handling message {:?}", msg);
match msg {
ServoWebSrcMsg::Start(..) => error!("Already started"),
ServoWebSrcMsg::GetSwapChain(sender) => sender
.send(self.swap_chain.clone())
.expect("Failed to send swap chain"),
ServoWebSrcMsg::GetSwapChain(sender) => self.send_swap_chain(sender),
ServoWebSrcMsg::Resize(size) => self.resize(size),
ServoWebSrcMsg::Heartbeat => self.servo.handle_events(vec![]),
ServoWebSrcMsg::Stop => break,
@ -233,43 +200,24 @@ impl ServoThread {
self.servo.handle_events(vec![WindowEvent::Quit]);
}
fn resize(&mut self, size: Size2D<i32, DevicePixel>) {
{
let mut gfx = self.gfx.borrow_mut();
let gfx = &mut *gfx;
self.swap_chain
.resize(&mut gfx.device, &mut gfx.context, size.to_untyped())
.expect("Failed to resize");
gfx.gl.viewport(0, 0, size.width, size.height);
let fbo = gfx
.device
.context_surface_info(&gfx.context)
.expect("Failed to get context info")
.expect("Failed to get context info")
.framebuffer_object;
gfx.device
.make_context_current(&gfx.context)
.expect("Failed to make current");
gfx.gl.bind_framebuffer(gl::FRAMEBUFFER, fbo);
debug_assert_eq!(
(
gfx.gl.check_framebuffer_status(gl::FRAMEBUFFER),
gfx.gl.get_error()
),
(gl::FRAMEBUFFER_COMPLETE, gl::NO_ERROR)
);
}
self.servo.handle_events(vec![WindowEvent::Resize]);
fn send_swap_chain(&mut self, sender: Sender<SwapChain<Device>>) {
let swap_chain = self
.servo
.window()
.webrender_surfman
.swap_chain()
.expect("Failed to get swap chain")
.clone();
sender.send(swap_chain).expect("Failed to send swap chain");
}
}
impl Drop for ServoThread {
fn drop(&mut self) {
let mut gfx = self.gfx.borrow_mut();
let gfx = &mut *gfx;
self.swap_chain
.destroy(&mut gfx.device, &mut gfx.context)
.expect("Failed to destroy swap chain")
fn resize(&mut self, size: Size2D<i32, DevicePixel>) {
let _ = self
.servo
.window()
.webrender_surfman
.resize(size.to_untyped());
self.servo.handle_events(vec![WindowEvent::Resize]);
}
}
@ -290,154 +238,35 @@ impl EventLoopWaker for ServoWebSrcEmbedder {
}
struct ServoWebSrcWindow {
swap_chain: SwapChain<Device>,
gfx: Rc<RefCell<ServoThreadGfx>>,
gl: Rc<dyn gleam::gl::Gl>,
webrender_surfman: WebrenderSurfman,
}
impl ServoWebSrcWindow {
fn new(connection: Connection, version: GLVersion) -> Self {
let flags = ContextAttributeFlags::DEPTH |
ContextAttributeFlags::STENCIL |
ContextAttributeFlags::ALPHA;
let attributes = ContextAttributes { version, flags };
fn new(connection: Connection) -> Self {
let adapter = connection
.create_adapter()
.expect("Failed to create adapter");
let mut device = connection
.create_device(&adapter)
.expect("Failed to create device");
let descriptor = device
.create_context_descriptor(&attributes)
.expect("Failed to create descriptor");
let mut context = device
.create_context(&descriptor)
.expect("Failed to create context");
let (gleam, gl) = unsafe {
match device.gl_api() {
GLApi::GL => (
gleam::gl::GlFns::load_with(|s| device.get_proc_address(&context, s)),
Gl::gl_fns(gl::ffi_gl::Gl::load_with(|s| {
device.get_proc_address(&context, s)
})),
),
GLApi::GLES => (
gleam::gl::GlesFns::load_with(|s| device.get_proc_address(&context, s)),
Gl::gles_fns(gl::ffi_gles::Gles2::load_with(|s| {
device.get_proc_address(&context, s)
})),
),
}
};
device
.make_context_current(&mut context)
.expect("Failed to make context current");
debug_assert_eq!(gl.get_error(), gl::NO_ERROR);
let access = SurfaceAccess::GPUOnly;
let size = Size2D::new(512, 512);
let surface_type = SurfaceType::Generic { size };
let surface = device
.create_surface(&mut context, access, surface_type)
.expect("Failed to create surface");
let webrender_surfman = WebrenderSurfman::create(&connection, &adapter, surface_type)
.expect("Failed to create surfman");
device
.bind_surface_to_context(&mut context, surface)
.expect("Failed to bind surface");
let fbo = device
.context_surface_info(&context)
.expect("Failed to get context info")
.expect("Failed to get context info")
.framebuffer_object;
gl.viewport(0, 0, size.width, size.height);
gl.bind_framebuffer(gl::FRAMEBUFFER, fbo);
gl.clear_color(0.0, 0.0, 0.0, 1.0);
gl.clear(gl::COLOR_BUFFER_BIT);
debug_assert_eq!(
(gl.check_framebuffer_status(gl::FRAMEBUFFER), gl.get_error()),
(gl::FRAMEBUFFER_COMPLETE, gl::NO_ERROR)
);
let provider = Box::new(SurfmanProvider::new(access));
let swap_chain = SwapChain::create_attached(&mut device, &mut context, provider)
.expect("Failed to create swap chain");
device.make_no_context_current().unwrap();
let gfx = Rc::new(RefCell::new(ServoThreadGfx {
device,
context,
gl,
}));
Self {
swap_chain,
gfx,
gl: gleam,
}
Self { webrender_surfman }
}
}
impl WindowMethods for ServoWebSrcWindow {
fn present(&self) {
debug!("EMBEDDER present");
let mut gfx = self.gfx.borrow_mut();
let gfx = &mut *gfx;
gfx.device
.make_context_current(&mut gfx.context)
.expect("Failed to make context current");
debug_assert_eq!(
(
gfx.gl.check_framebuffer_status(gl::FRAMEBUFFER),
gfx.gl.get_error()
),
(gl::FRAMEBUFFER_COMPLETE, gl::NO_ERROR)
);
self.swap_chain
.swap_buffers(&mut gfx.device, &mut gfx.context)
.expect("Failed to swap buffers");
let fbo = gfx
.device
.context_surface_info(&gfx.context)
.expect("Failed to get context info")
.expect("Failed to get context info")
.framebuffer_object;
gfx.gl.bind_framebuffer(gl::FRAMEBUFFER, fbo);
debug_assert_eq!(
(
gfx.gl.check_framebuffer_status(gl::FRAMEBUFFER),
gfx.gl.get_error()
),
(gl::FRAMEBUFFER_COMPLETE, gl::NO_ERROR)
);
let _ = gfx.device.make_no_context_current();
}
fn make_gl_context_current(&self) {
debug!("EMBEDDER make_context_current");
let mut gfx = self.gfx.borrow_mut();
let gfx = &mut *gfx;
gfx.device
.make_context_current(&mut gfx.context)
.expect("Failed to make context current");
debug!("EMBEDDER done make_context_current");
debug_assert_eq!(
(
gfx.gl.check_framebuffer_status(gl::FRAMEBUFFER),
gfx.gl.get_error()
),
(gl::FRAMEBUFFER_COMPLETE, gl::NO_ERROR)
);
}
fn gl(&self) -> Rc<dyn gleam::gl::Gl> {
self.gl.clone()
fn webrender_surfman(&self) -> WebrenderSurfman {
self.webrender_surfman.clone()
}
fn get_coordinates(&self) -> EmbedderCoordinates {
let size = Size2D::from_untyped(self.swap_chain.size());
let size = self
.webrender_surfman
.context_surface_info()
.unwrap_or(None)
.map(|info| Size2D::from_untyped(info.size))
.unwrap_or(Size2D::new(0, 0));
info!("EMBEDDER coordinates {}", size);
let origin = Point2D::origin();
EmbedderCoordinates {
@ -658,11 +487,6 @@ impl BaseSrcImpl for ServoWebSrc {
));
}
let gl_context = unsafe { GLContext::from_glib_borrow(gst_gl_context) };
let gl_version = gl_context.get_gl_version();
let version = GLVersion {
major: gl_version.0 as u8,
minor: gl_version.1 as u8,
};
// Get the surfman connection on the GL thread
let mut task = BootstrapSurfmanOnGLThread {
@ -683,7 +507,6 @@ impl BaseSrcImpl for ServoWebSrc {
// Inform servo we're starting
let _ = self.sender.send(ServoWebSrcMsg::Start(
ConnectionWhichImplementsDebug(connection),
version,
url,
));
Ok(())
@ -784,11 +607,32 @@ impl ServoWebSrc {
gl_context
.activate(true)
.expect("Failed to activate GL context");
let native_connection =
NativeConnection::current().expect("Failed to bootstrap native connection");
let connection = unsafe { Connection::from_native_connection(native_connection) }
.expect("Failed to bootstrap surfman connection");
Some(connection)
// TODO: support other connections on linux?
#[cfg(target_os = "linux")]
{
use surfman::platform::generic::multi;
use surfman::platform::unix::wayland;
let native_connection = wayland::connection::NativeConnection::current()
.expect("Failed to bootstrap native connection");
let wayland_connection = unsafe {
wayland::connection::Connection::from_native_connection(native_connection)
.expect("Failed to bootstrap wayland connection")
};
let connection = multi::connection::Connection::Default(
multi::connection::Connection::Default(wayland_connection),
);
Some(connection)
}
#[cfg(not(target_os = "linux"))]
{
use surfman::connection::Connection as ConnectionAPI;
type NativeConnection = <Connection as ConnectionAPI>::NativeConnection;
let native_connection =
NativeConnection::current().expect("Failed to bootstrap native connection");
let connection = unsafe { Connection::from_native_connection(native_connection) }
.expect("Failed to bootstrap surfman connection");
Some(connection)
}
}
}
@ -840,8 +684,21 @@ impl ServoWebSrc {
let device = connection
.create_device(&adapter)
.expect("Failed to bootstrap surfman device");
let native_context =
NativeContext::current().expect("Failed to bootstrap native context");
#[cfg(target_os = "linux")]
let native_context = {
use surfman::platform::generic::multi;
use surfman::platform::unix::wayland;
multi::context::NativeContext::Default(multi::context::NativeContext::Default(
wayland::context::NativeContext::current()
.expect("Failed to bootstrap native context"),
))
};
#[cfg(not(target_os = "linux"))]
let native_context = {
use surfman::device::Device as DeviceAPI;
type NativeContext = <Device as DeviceAPI>::NativeContext;
NativeContext::current().expect("Failed to bootstrap native context")
};
let context = unsafe {
device
.create_context_from_native_context(native_context)
@ -995,5 +852,3 @@ impl ServoWebSrc {
Ok(())
}
}
// TODO: Implement that trait for more platforms

View file

@ -12,6 +12,7 @@ ipc-channel = "0.14"
libservo = { path = "../../../components/servo" }
log = "0.4"
servo-media = { git = "https://github.com/servo/media" }
surfman = { version = "0.2", features = ["sm-angle-default"] }
webxr-api = { git = "https://github.com/servo/webxr", features = ["ipc"] }
webxr = { git = "https://github.com/servo/webxr"}

View file

@ -32,6 +32,7 @@ use servo::servo_config::{pref, set_pref};
use servo::servo_url::ServoUrl;
use servo::webrender_api::units::DevicePixel;
use servo::webrender_api::ScrollLocation;
use servo::webrender_surfman::WebrenderSurfman;
use servo::{self, gl, BrowserId, Servo};
use servo_media::player::context as MediaPlayerContext;
use std::cell::RefCell;
@ -39,6 +40,8 @@ use std::mem;
use std::os::raw::c_void;
use std::path::PathBuf;
use std::rc::Rc;
use surfman::Connection;
use surfman::SurfaceType;
thread_local! {
pub static SERVO: RefCell<Option<ServoGlue>> = RefCell::new(None);
@ -58,6 +61,7 @@ pub struct InitOptions {
pub enable_subpixel_text_antialiasing: bool,
pub gl_context_pointer: Option<*const c_void>,
pub native_display_pointer: Option<*const c_void>,
pub native_widget: *mut c_void,
}
#[derive(Clone, Debug)]
@ -84,12 +88,6 @@ impl Coordinates {
/// Callbacks. Implemented by embedder. Called by Servo.
pub trait HostTrait {
/// Will be called from the thread used for the init call.
/// Will be called when the GL buffer has been updated.
fn flush(&self);
/// Will be called before drawing.
/// Time to make the targetted GL context current.
fn make_current(&self);
/// Show alert.
fn prompt_alert(&self, msg: String, trusted: bool);
/// Ask Yes/No question.
@ -211,13 +209,28 @@ pub fn init(
gl.clear(gl::COLOR_BUFFER_BIT);
gl.finish();
// Initialize surfman
let connection = Connection::new().or(Err("Failed to create connection"))?;
let adapter = connection
.create_adapter()
.or(Err("Failed to create adapter"))?;
let native_widget = unsafe {
connection.create_native_widget_from_ptr(
init_opts.native_widget,
init_opts.coordinates.framebuffer.to_untyped(),
)
};
let surface_type = SurfaceType::Widget { native_widget };
let webrender_surfman = WebrenderSurfman::create(&connection, &adapter, surface_type)
.or(Err("Failed to create surface manager"))?;
let window_callbacks = Rc::new(ServoWindowCallbacks {
host_callbacks: callbacks,
gl: gl.clone(),
coordinates: RefCell::new(init_opts.coordinates),
density: init_opts.density,
gl_context_pointer: init_opts.gl_context_pointer,
native_display_pointer: init_opts.native_display_pointer,
webrender_surfman,
});
let embedder_callbacks = Box::new(ServoEmbedderCallbacks {
@ -723,12 +736,12 @@ struct ServoEmbedderCallbacks {
}
struct ServoWindowCallbacks {
gl: Rc<dyn gl::Gl>,
host_callbacks: Box<dyn HostTrait>,
coordinates: RefCell<Coordinates>,
density: f32,
gl_context_pointer: Option<*const c_void>,
native_display_pointer: Option<*const c_void>,
webrender_surfman: WebrenderSurfman,
}
impl EmbedderMethods for ServoEmbedderCallbacks {
@ -798,7 +811,7 @@ impl EmbedderMethods for ServoEmbedderCallbacks {
struct GlThread(WebGlExecutor);
impl webxr::openxr::GlThread for GlThread {
fn execute(&self, runnable: Box<dyn FnOnce() + Send>) {
fn execute(&self, runnable: Box<dyn FnOnce(&surfman::Device) + Send>) {
let _ = self.0.send(runnable);
}
fn clone(&self) -> Box<dyn webxr::openxr::GlThread> {
@ -835,19 +848,8 @@ impl EmbedderMethods for ServoEmbedderCallbacks {
}
impl WindowMethods for ServoWindowCallbacks {
fn make_gl_context_current(&self) {
debug!("WindowMethods::prepare_for_composite");
self.host_callbacks.make_current();
}
fn present(&self) {
debug!("WindowMethods::present");
self.host_callbacks.flush();
}
fn gl(&self) -> Rc<dyn gl::Gl> {
debug!("WindowMethods::gl");
self.gl.clone()
fn webrender_surfman(&self) -> WebrenderSurfman {
self.webrender_surfman.clone()
}
fn set_animation_state(&self, state: AnimationState) {

View file

@ -18,6 +18,7 @@ log = "0.4"
lazy_static = "1"
env_logger = "0.7"
backtrace = "0.3"
surfman = "0.2"
[target.'cfg(target_os = "windows")'.dependencies]
libc = "0.2"

View file

@ -201,8 +201,6 @@ where
/// Callback used by Servo internals
#[repr(C)]
pub struct CHostCallbacks {
pub flush: extern "C" fn(),
pub make_current: extern "C" fn(),
pub on_load_started: extern "C" fn(),
pub on_load_ended: extern "C" fn(),
pub on_title_changed: extern "C" fn(title: *const c_char),
@ -244,6 +242,7 @@ pub struct CInitOptions {
pub enable_subpixel_text_antialiasing: bool,
pub vslogger_mod_list: *const *const c_char,
pub vslogger_mod_size: u32,
pub native_widget: *mut c_void,
}
#[repr(C)]
@ -442,6 +441,7 @@ unsafe fn init(
enable_subpixel_text_antialiasing: opts.enable_subpixel_text_antialiasing,
gl_context_pointer: gl_context,
native_display_pointer: display,
native_widget: opts.native_widget,
};
let wakeup = Box::new(WakeupCallback::new(wakeup));
@ -750,16 +750,6 @@ impl HostCallbacks {
}
impl HostTrait for HostCallbacks {
fn flush(&self) {
debug!("flush");
(self.0.flush)();
}
fn make_current(&self) {
debug!("make_current");
(self.0.make_current)();
}
fn on_load_started(&self) {
debug!("on_load_started");
(self.0.on_load_started)();