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:
parent
f57b5deb80
commit
6a96b7ddea
@ -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
45
window/build.rs
Normal 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
168
window/src/egl.rs
Normal 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!();
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user