1
1
mirror of https://github.com/wez/wezterm.git synced 2024-11-27 02:25:28 +03:00

window: enable egl support for wayland

This commit is contained in:
Wez Furlong 2019-11-29 18:05:09 -08:00
parent c03eda1279
commit 2475969eca
5 changed files with 186 additions and 66 deletions

View File

@ -8,6 +8,9 @@ description = "Cross platform window setup and render"
license = "MIT"
build = "build.rs"
[dev-dependencies]
pretty_env_logger = "0.3"
[build-dependencies]
gl_generator = {version="0.13", optional=true}
@ -28,7 +31,7 @@ glium = { version = "0.26.0-alpha3", optional=true, default-features = false}
[features]
async_await = []
opengl = ["cgl", "glium", "gl_generator", "libloading"]
wayland = ["smithay-client-toolkit", "memmap"]
wayland = ["smithay-client-toolkit", "memmap", "wayland-client"]
[target."cfg(windows)".dependencies]
winapi = { version = "0.3", features = [
@ -53,6 +56,7 @@ mio-extras = "2.0"
libc = "0.2"
smithay-client-toolkit = {version = "0.6", optional = true}
memmap = {version="0.7", optional=true}
wayland-client = {version="0.23", optional=true, features=["egl"]}
[target.'cfg(target_os="macos")'.dependencies]
cocoa = "0.20"

View File

@ -69,6 +69,7 @@ fn spawn_window() -> Fallible<()> {
}
fn main() -> Fallible<()> {
pretty_env_logger::init();
let conn = Connection::init()?;
spawn_window()?;
conn.run_message_loop()

View File

@ -199,10 +199,7 @@ impl EglWrapper {
}
impl GlState {
pub fn create(
display: Option<ffi::EGLNativeDisplayType>,
window: ffi::EGLNativeWindowType,
) -> Fallible<Self> {
fn with_egl_lib<F: FnMut(EglWrapper) -> Fallible<Self>>(mut func: F) -> Fallible<Self> {
let paths = [
// While EGL is cross platform, it isn't available on macOS nor is it
// available on my nvidia based system
@ -216,61 +213,137 @@ impl GlState {
"libEGL.so",
];
for path in &paths {
eprintln!("trying {}", path);
if let Ok(lib) = libloading::Library::new(path) {
if let Ok(egl) = EglWrapper::load_egl(lib) {
let egl_display = egl.get_display(display)?;
let (major, minor) = egl.initialize_and_get_version(egl_display)?;
eprintln!("initialized EGL version {}.{}", major, minor);
let configs = egl.choose_config(
egl_display,
&[
ffi::ALPHA_SIZE,
8,
ffi::RED_SIZE,
8,
ffi::GREEN_SIZE,
8,
ffi::BLUE_SIZE,
8,
ffi::DEPTH_SIZE,
24,
ffi::CONFORMANT,
ffi::OPENGL_ES3_BIT,
ffi::RENDERABLE_TYPE,
ffi::OPENGL_ES3_BIT,
ffi::SURFACE_TYPE,
ffi::WINDOW_BIT | ffi::PBUFFER_BIT | ffi::PIXMAP_BIT,
ffi::NONE,
],
)?;
let first_config = *configs.first().ok_or_else(|| {
failure::err_msg("no compatible EGL configuration was found")
})?;
let surface = egl.create_window_surface(egl_display, first_config, window)?;
let context = egl.create_context(
egl_display,
first_config,
std::ptr::null(),
&[ffi::CONTEXT_MAJOR_VERSION, 3, ffi::NONE],
)?;
return Ok(Self {
egl,
display: egl_display,
context,
surface,
});
match EglWrapper::load_egl(lib) {
Ok(egl) => match func(egl) {
Ok(result) => {
log::error!("initialized {}", path);
return Ok(result);
}
Err(e) => {
log::error!("with_egl_lib failed: {}", e);
}
},
Err(e) => {
log::error!("load_egl failed: {}", e);
}
}
}
}
failure::bail!("EGL library not found")
}
#[cfg(all(unix, feature = "wayland", not(target_os = "macos")))]
pub fn create_wayland(
display: Option<ffi::EGLNativeDisplayType>,
wegl_surface: &wayland_client::egl::WlEglSurface,
) -> Fallible<Self> {
Self::with_egl_lib(move |egl| {
let egl_display = egl.get_display(display)?;
let (major, minor) = egl.initialize_and_get_version(egl_display)?;
log::error!("initialized EGL version {}.{}", major, minor);
let configs = egl.choose_config(
egl_display,
&[
ffi::ALPHA_SIZE,
8,
ffi::RED_SIZE,
8,
ffi::GREEN_SIZE,
8,
ffi::BLUE_SIZE,
8,
ffi::DEPTH_SIZE,
24,
ffi::CONFORMANT,
ffi::OPENGL_ES3_BIT,
ffi::RENDERABLE_TYPE,
ffi::OPENGL_ES3_BIT,
ffi::SURFACE_TYPE,
ffi::WINDOW_BIT, // | ffi::PBUFFER_BIT | ffi::PIXMAP_BIT,
ffi::NONE,
],
)?;
let first_config = *configs
.first()
.ok_or_else(|| failure::err_msg("no compatible EGL configuration was found"))?;
let window = wegl_surface.ptr();
let surface = egl.create_window_surface(egl_display, first_config, window)?;
let context = egl.create_context(
egl_display,
first_config,
std::ptr::null(),
&[ffi::CONTEXT_MAJOR_VERSION, 3, ffi::NONE],
)?;
return Ok(Self {
egl,
display: egl_display,
context,
surface,
});
})
}
pub fn create(
display: Option<ffi::EGLNativeDisplayType>,
window: ffi::EGLNativeWindowType,
) -> Fallible<Self> {
Self::with_egl_lib(|egl| {
let egl_display = egl.get_display(display)?;
let (major, minor) = egl.initialize_and_get_version(egl_display)?;
log::error!("initialized EGL version {}.{}", major, minor);
let configs = egl.choose_config(
egl_display,
&[
ffi::ALPHA_SIZE,
8,
ffi::RED_SIZE,
8,
ffi::GREEN_SIZE,
8,
ffi::BLUE_SIZE,
8,
ffi::DEPTH_SIZE,
24,
ffi::CONFORMANT,
ffi::OPENGL_ES3_BIT,
ffi::RENDERABLE_TYPE,
ffi::OPENGL_ES3_BIT,
ffi::SURFACE_TYPE,
ffi::WINDOW_BIT | ffi::PBUFFER_BIT | ffi::PIXMAP_BIT,
ffi::NONE,
],
)?;
let first_config = *configs
.first()
.ok_or_else(|| failure::err_msg("no compatible EGL configuration was found"))?;
let surface = egl.create_window_surface(egl_display, first_config, window)?;
let context = egl.create_context(
egl_display,
first_config,
std::ptr::null(),
&[ffi::CONTEXT_MAJOR_VERSION, 3, ffi::NONE],
)?;
return Ok(Self {
egl,
display: egl_display,
context,
surface,
});
})
}
}
unsafe impl glium::backend::Backend for GlState {

View File

@ -19,7 +19,7 @@ use toolkit::reexports::client::{Display, EventQueue};
use toolkit::Environment;
pub struct WaylandConnection {
display: RefCell<Display>,
pub(crate) display: RefCell<Display>,
event_q: RefCell<EventQueue>,
pub(crate) environment: RefCell<Environment>,
should_terminate: RefCell<bool>,

View File

@ -36,6 +36,7 @@ use toolkit::reexports::client::protocol::wl_seat::{Event as SeatEvent, WlSeat};
use toolkit::reexports::client::protocol::wl_surface::WlSurface;
use toolkit::utils::MemPool;
use toolkit::window::Event;
use wayland_client::egl::{is_available as egl_is_available, WlEglSurface};
fn modifier_keys(state: ModifiersState) -> Modifiers {
let mut mods = Modifiers::NONE;
@ -294,6 +295,13 @@ pub struct WaylandWindowInner {
last_mouse_coords: Point,
mouse_buttons: MouseButtons,
modifiers: Modifiers,
// wegl_surface is listed before gl_state because it
// must be dropped before gl_state otherwise the underlying
// libraries will segfault on shutdown
#[cfg(feature = "opengl")]
wegl_surface: Option<WlEglSurface>,
#[cfg(feature = "opengl")]
gl_state: Option<Rc<glium::backend::Context>>,
}
#[derive(Clone, Debug)]
@ -504,6 +512,10 @@ impl WaylandWindow {
last_mouse_coords: Point::new(0, 0),
mouse_buttons: MouseButtons::NONE,
modifiers: Modifiers::NONE,
#[cfg(feature = "opengl")]
gl_state: None,
#[cfg(feature = "opengl")]
wegl_surface: None,
}));
let window_handle = Window::Wayland(WaylandWindow(window_id));
@ -681,6 +693,12 @@ impl WaylandWindowInner {
let w = w * factor as u32;
let h = h * factor as u32;
self.dimensions = (w, h);
#[cfg(feature = "opengl")]
{
if let Some(wegl_surface) = self.wegl_surface.as_mut() {
wegl_surface.resize(w as i32, h as i32, 0, 0);
}
}
self.callbacks.resize(Dimensions {
pixel_width: w as usize,
pixel_height: h as usize,
@ -700,6 +718,24 @@ impl WaylandWindowInner {
}
fn do_paint(&mut self) -> Fallible<()> {
#[cfg(feature = "opengl")]
{
if let Some(gl_context) = self.gl_state.as_ref() {
let mut frame = glium::Frame::new(
Rc::clone(&gl_context),
(u32::from(self.dimensions.0), u32::from(self.dimensions.1)),
);
self.callbacks.paint_opengl(&mut frame);
frame.finish()?;
// self.damage();
self.surface.commit();
self.refresh_frame();
self.need_paint = false;
return Ok(());
}
}
if self.pool.is_used() {
// Buffer still in use by server; retry later
return Ok(());
@ -901,12 +937,23 @@ impl WindowOps for WaylandWindow {
{
WaylandConnection::with_window_inner(self.0, move |inner| {
let window = Window::Wayland(WaylandWindow(inner.window_id));
let wayland_conn = Connection::get().unwrap().wayland();
let mut wegl_surface = None;
/*
let gl_state = crate::egl::GlState::create(
Some(inner.conn.display as *const _),
inner.window_id as *mut _,
)
let gl_state = if !egl_is_available() {
Err(failure::err_msg("!egl_is_available"))
} else {
wegl_surface = Some(WlEglSurface::new(
&inner.surface,
inner.dimensions.0 as i32,
inner.dimensions.1 as i32,
));
crate::egl::GlState::create_wayland(
Some(wayland_conn.display.borrow().get_display_ptr() as *const _),
wegl_surface.as_ref().unwrap(),
)
}
.map(Rc::new)
.and_then(|state| unsafe {
Ok(glium::backend::Context::new(
@ -921,14 +968,9 @@ impl WindowOps for WaylandWindow {
});
inner.gl_state = gl_state.as_ref().map(Rc::clone).ok();
inner.wegl_surface = wegl_surface;
func(inner.callbacks.as_any(), &window, gl_state)
*/
func(
inner.callbacks.as_any(),
&window,
Err(failure::err_msg("no opengl")),
)
})
}