1
1
mirror of https://github.com/wez/wezterm.git synced 2024-12-23 13:21:38 +03:00

window: take a stabe at EGL for linux/windows

This doesn't initialize it at all properly yet, but is groundwork
for completing that work in a later commit
This commit is contained in:
Wez Furlong 2019-10-24 15:54:41 -07:00
parent f57b5deb80
commit 6a96b7ddea
6 changed files with 233 additions and 1 deletions

View File

@ -6,6 +6,10 @@ edition = "2018"
repository = "https://github.com/wez/wezterm"
description = "Cross platform window setup and render"
license = "MIT"
build = "build.rs"
[build-dependencies]
gl_generator = {version="0.13", optional=true}
[dependencies]
bitflags = "1.0"
@ -13,6 +17,7 @@ euclid = "0.20"
failure = "0.1"
failure_derive = "0.1"
lazy_static = "1.3"
libloading = { version = "0.5", optional=true }
line_drawing = "0.8"
palette = "0.4"
promise = { path = "../promise" }
@ -21,7 +26,7 @@ glium = { version = "0.26.0-alpha3", optional=true, default-features = false}
[features]
async_await = []
opengl = ["cgl", "glium"]
opengl = ["cgl", "glium", "gl_generator", "libloading"]
[target."cfg(windows)".dependencies]
winapi = { version = "0.3", features = [

45
window/build.rs Normal file
View File

@ -0,0 +1,45 @@
fn main() {
println!("cargo:rerun-if-changed=build.rs");
#[cfg(feature = "opengl")]
{
use gl_generator::{Api, Fallbacks, Profile, Registry};
use std::env;
use std::fs::File;
use std::path::PathBuf;
let dest = PathBuf::from(&env::var("OUT_DIR").unwrap());
let target = env::var("TARGET").unwrap();
if !target.contains("macos") {
let mut file = File::create(&dest.join("egl_bindings.rs")).unwrap();
let reg = Registry::new(
Api::Egl,
(1, 5),
Profile::Core,
Fallbacks::All,
[
"EGL_KHR_create_context",
"EGL_EXT_create_context_robustness",
"EGL_KHR_create_context_no_error",
"EGL_KHR_platform_x11",
"EGL_KHR_platform_android",
"EGL_KHR_platform_wayland",
"EGL_KHR_platform_gbm",
"EGL_EXT_platform_base",
"EGL_EXT_platform_x11",
"EGL_MESA_platform_gbm",
"EGL_EXT_platform_wayland",
"EGL_EXT_platform_device",
"EGL_KHR_swap_buffers_with_damage",
],
);
if target.contains("android") || target.contains("ios") {
reg.write_bindings(gl_generator::StaticStructGenerator, &mut file)
} else {
reg.write_bindings(gl_generator::StructGenerator, &mut file)
}
.unwrap()
}
}
}

168
window/src/egl.rs Normal file
View File

@ -0,0 +1,168 @@
use failure::Fallible;
use std::ffi::c_void;
#[allow(non_camel_case_types)]
pub mod ffi {
// gl_generator emits these weird cyclical and redundant type references;
// the types appear to have to be in a module and need to reference super,
// with some of the types specified in both scopes :-/
pub mod generated {
pub type khronos_utime_nanoseconds_t = super::khronos_utime_nanoseconds_t;
pub type khronos_uint64_t = super::khronos_uint64_t;
pub type khronos_ssize_t = super::khronos_ssize_t;
pub type EGLNativeDisplayType = super::EGLNativeDisplayType;
pub type EGLNativePixmapType = super::EGLNativePixmapType;
pub type EGLNativeWindowType = super::EGLNativeWindowType;
pub type EGLint = super::EGLint;
pub type NativeDisplayType = super::EGLNativeDisplayType;
pub type NativePixmapType = super::EGLNativePixmapType;
pub type NativeWindowType = super::EGLNativeWindowType;
include!(concat!(env!("OUT_DIR"), "/egl_bindings.rs"));
}
pub use generated::*;
use std::os::raw;
pub type EGLint = i32;
pub type khronos_ssize_t = raw::c_long;
pub type khronos_utime_nanoseconds_t = khronos_uint64_t;
pub type khronos_uint64_t = u64;
pub type EGLNativeDisplayType = *const raw::c_void;
pub type EGLNativePixmapType = *const raw::c_void;
#[cfg(target_os = "windows")]
pub type EGLNativeWindowType = winapi::shared::windef::HWND;
#[cfg(not(target_os = "windows"))]
pub type EGLNativeWindowType = *const raw::c_void;
}
struct EglWrapper {
_lib: libloading::Library,
egl: ffi::Egl,
}
pub struct GlState {
egl: EglWrapper,
}
type GetProcAddressFunc =
unsafe extern "C" fn(*const std::os::raw::c_char) -> *const std::os::raw::c_void;
impl EglWrapper {
pub fn load_egl(lib: libloading::Library) -> Fallible<Self> {
let get_proc_address: libloading::Symbol<GetProcAddressFunc> =
unsafe { lib.get(b"eglGetProcAddress\0")? };
let egl = ffi::Egl::load_with(|s: &'static str| {
let sym_name = std::ffi::CString::new(s).expect("symbol to be cstring compatible");
if let Ok(sym) = unsafe { lib.get(sym_name.as_bytes_with_nul()) } {
return *sym;
}
unsafe { get_proc_address(sym_name.as_ptr()) }
});
Ok(Self { _lib: lib, egl })
}
pub fn get_display(
&self,
display: Option<ffi::EGLNativeDisplayType>,
) -> Fallible<ffi::types::EGLDisplay> {
let display = unsafe { self.egl.GetDisplay(display.unwrap_or(ffi::DEFAULT_DISPLAY)) };
if display.is_null() {
Err(self.error("egl GetDisplay"))
} else {
Ok(display)
}
}
pub fn error(&self, context: &str) -> failure::Error {
let label = match unsafe { self.egl.GetError() } as u32 {
ffi::NOT_INITIALIZED => "NOT_INITIALIZED".into(),
ffi::BAD_ACCESS => "BAD_ACCESS".into(),
ffi::BAD_ALLOC => "BAD_ALLOC".into(),
ffi::BAD_ATTRIBUTE => "BAD_ATTRIBUTE".into(),
ffi::BAD_CONTEXT => "BAD_CONTEXT".into(),
ffi::BAD_CURRENT_SURFACE => "BAD_CURRENT_SURFACE".into(),
ffi::BAD_DISPLAY => "BAD_DISPLAY".into(),
ffi::BAD_SURFACE => "BAD_SURFACE".into(),
ffi::BAD_MATCH => "BAD_MATCH".into(),
ffi::BAD_PARAMETER => "BAD_PARAMETER".into(),
ffi::BAD_NATIVE_PIXMAP => "BAD_NATIVE_PIXMAP".into(),
ffi::BAD_NATIVE_WINDOW => "BAD_NATIVE_WINDOW".into(),
ffi::CONTEXT_LOST => "CONTEXT_LOST".into(),
ffi::SUCCESS => "Failed but with error code: SUCCESS".into(),
err => format!("EGL Error code: {}", err),
};
failure::format_err!("{}: {}", context, label)
}
pub fn initialize_and_get_version(
&self,
display: ffi::types::EGLDisplay,
) -> Fallible<(ffi::EGLint, ffi::EGLint)> {
let mut major = 0;
let mut minor = 0;
unsafe {
if self.egl.Initialize(display, &mut major, &mut minor) != 0 {
Ok((major, minor))
} else {
Err(self.error("egl Initialize"))
}
}
}
}
impl GlState {
pub fn create(display: Option<ffi::EGLNativeDisplayType>) -> Fallible<Self> {
let paths = [
// While EGL is cross platform, it isn't available on macOS nor is it
// available on my nvidia based system
#[cfg(target_os = "windows")]
"libEGL.dll",
#[cfg(target_os = "windows")]
"atioglxx.dll",
#[cfg(not(target_os = "windows"))]
"libEGL.so.1",
#[cfg(not(target_os = "windows"))]
"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);
return Ok(Self { egl });
}
}
}
failure::bail!("EGL library not found")
}
}
unsafe impl glium::backend::Backend for GlState {
fn swap_buffers(&self) -> Result<(), glium::SwapBuffersError> {
unimplemented!();
}
unsafe fn get_proc_address(&self, symbol: &str) -> *const c_void {
let sym_name = std::ffi::CString::new(symbol).expect("symbol to be cstring compatible");
std::mem::transmute(self.egl.egl.GetProcAddress(sym_name.as_ptr()))
}
fn get_framebuffer_dimensions(&self) -> (u32, u32) {
unimplemented!();
}
fn is_current(&self) -> bool {
unimplemented!();
}
unsafe fn make_current(&self) {
unimplemented!();
}
}

View File

@ -7,6 +7,9 @@ pub mod os;
mod spawn;
mod tasks;
#[cfg(all(not(target_os = "macos"), feature = "opengl"))]
mod egl;
#[cfg(feature = "opengl")]
pub use glium;

View File

@ -290,6 +290,13 @@ impl WindowOps for Window {
{
Connection::with_window_inner(self.0, move |inner| {
let window = Window(inner.hwnd);
let dc = unsafe { GetDC(std::mem::transmute(inner.hwnd)) };
match crate::egl::GlState::create(Some(dc as *const _)) {
Ok(_) => eprintln!("EGL initialized!?"),
Err(err) => eprintln!("EGL: {}", err),
};
func(
inner.callbacks.borrow_mut().as_any(),
&window,

View File

@ -501,6 +501,10 @@ impl WindowOps for Window {
{
Connection::with_window_inner(self.0, move |inner| {
let window = Window(inner.window_id);
match crate::egl::GlState::create(Some(inner.conn.display as *const _)) {
Ok(_) => eprintln!("EGL initialized!?"),
Err(err) => eprintln!("EGL: {}", err),
};
func(
inner.callbacks.as_any(),
&window,