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:
parent
c03eda1279
commit
2475969eca
@ -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"
|
||||
|
@ -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()
|
||||
|
@ -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 {
|
||||
|
@ -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>,
|
||||
|
@ -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")),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user