diff --git a/src/backend/gl/src/lib.rs b/src/backend/gl/src/lib.rs index df765a718cb..f5d9fe90e86 100644 --- a/src/backend/gl/src/lib.rs +++ b/src/backend/gl/src/lib.rs @@ -12,8 +12,10 @@ extern crate gfx_hal as hal; pub extern crate glutin; use std::cell::Cell; +use std::ffi::c_void; use std::fmt; use std::ops::Deref; +use std::os::raw::c_ulong; use std::sync::{Arc, Weak}; use std::thread::{self, ThreadId}; @@ -736,6 +738,83 @@ pub enum Instance { Surface(Surface), } +use glutin::platform::unix::RawContextExt; +impl Instance { + + pub fn create_surface_from_wayland( + &self, + display: *mut c_void, + surface: *mut c_void, + ) -> Surface { + log::trace!("Creating GL surface from wayland"); + let context = unsafe { + glutin::ContextBuilder::new() + .with_vsync(true) + .build_raw_wayland_context( + display as _, + surface, + /*TODO: do something with these dimensions*/ + 400, + 400, + ) + .expect("TODO: handle this error") + }; + let context = unsafe { context.make_current().expect("TODO: handle this error") }; + Surface::from_context(context) + } + + pub fn create_surface_from_xlib(&self, window: c_ulong, display: *mut c_void) -> Surface { + log::trace!("Creating GL surface from Xlib"); + let xconn = { + // This is taken from `glutin::platform::unix::x11::XConnection::new except with tweaks + // that allow us to create the connection with an existing display pointer + use glutin::platform::unix::x11::{XConnection, ffi}; + + // opening the libraries + let xlib = ffi::Xlib::open().expect("TODO: Handle error"); + let xcursor = ffi::Xcursor::open().expect("TODO: Handle error"); + let xrandr = ffi::Xrandr_2_2_0::open().expect("TODO: Handle error"); + let xrandr_1_5 = ffi::Xrandr::open().ok(); + let xinput2 = ffi::XInput2::open().expect("TODO: Handle error"); + let xlib_xcb = ffi::Xlib_xcb::open().expect("TODO: Handle error"); + let xrender = ffi::Xrender::open().expect("TODO: Handle error"); + + unsafe { (xlib.XInitThreads)() }; + // unsafe { (xlib.XSetErrorHandler)(error_handler) }; + + // Get X11 socket file descriptor + let fd = unsafe { (xlib.XConnectionNumber)(display as *mut ffi::_XDisplay) }; + + XConnection { + xlib, + xrandr, + xrandr_1_5, + xcursor, + xinput2, + xlib_xcb, + xrender, + display: display as _, + x11_fd: fd, + latest_error: parking_lot::Mutex::new(None), + cursor_cache: Default::default(), + } + }; + let xconn = Arc::new(xconn); + + let context = unsafe { + glutin::ContextBuilder::new() + .with_vsync(true) + .build_raw_x11_context( + xconn, + window + ) + .expect("TODO: handle this error") + }; + let context = unsafe { context.make_current().expect("TODO: handle this error") }; + Surface::from_context(context) + } +} + #[cfg(all(feature = "glutin", not(target_arch = "wasm32")))] impl hal::Instance for Instance { fn create(name: &str, version: u32) -> Result { @@ -751,9 +830,26 @@ impl hal::Instance for Instance { unsafe fn create_surface( &self, - _: &impl raw_window_handle::HasRawWindowHandle, + has_handle: &impl raw_window_handle::HasRawWindowHandle, ) -> Result { - unimplemented!() + use raw_window_handle::RawWindowHandle; + + match has_handle.raw_window_handle() { + #[cfg(all(unix, not(target_os = "android"), not(target_os = "macos")))] + RawWindowHandle::Wayland(handle) => { + Ok(self.create_surface_from_wayland(handle.display, handle.surface)) + } + #[cfg(all( + feature = "x11", + unix, + not(target_os = "android"), + not(target_os = "macos") + ))] + RawWindowHandle::Xlib(handle) => { + Ok(self.create_surface_from_xlib(handle.display as *mut _, handle.window)) + } + _ => Err(hal::window::InitError::UnsupportedWindowHandle), + } } unsafe fn destroy_surface(&self, _surface: Surface) {