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

window: use wgl for opengl on windows

This commit is contained in:
Wez Furlong 2019-10-24 19:12:18 -07:00
parent 5135c724e6
commit f2fce18586
5 changed files with 169 additions and 11 deletions

View File

@ -41,5 +41,13 @@ fn main() {
}
.unwrap()
}
if target.contains("windows") {
let mut file = File::create(&dest.join("wgl_bindings.rs")).unwrap();
let reg = Registry::new(Api::Wgl, (1, 0), Profile::Core, Fallbacks::All, []);
reg.write_bindings(gl_generator::StructGenerator, &mut file)
.unwrap()
}
}
}

View File

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

View File

@ -1,6 +1,7 @@
pub mod connection;
pub mod event;
pub mod gdi;
mod wgl;
pub mod window;
pub use connection::*;

View File

@ -0,0 +1,122 @@
#![cfg(feature = "opengl")]
use failure::Fallible;
use std::os::raw::c_void;
use winapi::shared::windef::*;
use winapi::um::wingdi::*;
use winapi::um::winuser::*;
pub mod ffi {
include!(concat!(env!("OUT_DIR"), "/wgl_bindings.rs"));
}
pub struct WglWrapper {
lib: libloading::Library,
wgl: ffi::Wgl,
}
type GetProcAddressFunc =
unsafe extern "system" fn(*const std::os::raw::c_char) -> *const std::os::raw::c_void;
impl WglWrapper {
pub fn create() -> Fallible<Self> {
let lib = libloading::Library::new("opengl32.dll")?;
let get_proc_address: libloading::Symbol<GetProcAddressFunc> =
unsafe { lib.get(b"wglGetProcAddress\0")? };
let wgl = ffi::Wgl::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, wgl })
}
}
pub struct GlState {
wgl: WglWrapper,
hdc: HDC,
rc: ffi::types::HGLRC,
}
impl GlState {
pub fn create(window: HWND) -> Fallible<Self> {
let wgl = WglWrapper::create()?;
let hdc = unsafe { GetDC(window) };
let pfd = PIXELFORMATDESCRIPTOR {
nSize: std::mem::size_of::<PIXELFORMATDESCRIPTOR>() as u16,
nVersion: 1,
dwFlags: PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
iPixelType: PFD_TYPE_RGBA,
cColorBits: 24,
cRedBits: 0,
cRedShift: 0,
cGreenBits: 0,
cGreenShift: 0,
cBlueBits: 0,
cBlueShift: 0,
cAlphaBits: 8,
cAlphaShift: 0,
cAccumBits: 0,
cAccumRedBits: 0,
cAccumGreenBits: 0,
cAccumBlueBits: 0,
cAccumAlphaBits: 0,
cDepthBits: 24,
cStencilBits: 8,
cAuxBuffers: 0,
iLayerType: PFD_MAIN_PLANE,
bReserved: 0,
dwLayerMask: 0,
dwVisibleMask: 0,
dwDamageMask: 0,
};
let format = unsafe { ChoosePixelFormat(hdc, &pfd) };
unsafe {
SetPixelFormat(hdc, format, &pfd);
}
let rc = unsafe { wgl.wgl.CreateContext(hdc as *mut _) };
unsafe {
wgl.wgl.MakeCurrent(hdc as *mut _, rc);
}
Ok(Self { wgl, rc, hdc })
}
}
unsafe impl glium::backend::Backend for GlState {
fn swap_buffers(&self) -> Result<(), glium::SwapBuffersError> {
unsafe {
SwapBuffers(self.hdc);
}
Ok(())
}
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");
if let Ok(sym) = self.wgl.lib.get(sym_name.as_bytes_with_nul()) {
//eprintln!("{} -> {:?}", symbol, sym);
return *sym;
}
let res = self.wgl.wgl.GetProcAddress(sym_name.as_ptr()) as *const c_void;
// eprintln!("{} -> {:?}", symbol, res);
res
}
fn get_framebuffer_dimensions(&self) -> (u32, u32) {
unimplemented!();
}
fn is_current(&self) -> bool {
unsafe { self.wgl.wgl.GetCurrentContext() == self.rc }
}
unsafe fn make_current(&self) {
self.wgl.wgl.MakeCurrent(self.hdc as *mut _, self.rc);
}
}

View File

@ -31,6 +31,8 @@ pub(crate) struct WindowInner {
hwnd: HWindow,
callbacks: RefCell<Box<dyn WindowCallbacks>>,
bitmap: RefCell<GdiBitmap>,
#[cfg(feature = "opengl")]
gl_state: Option<Rc<glium::backend::Context>>,
}
#[derive(Debug, Clone)]
@ -166,6 +168,8 @@ impl Window {
hwnd: HWindow(null_mut()),
callbacks: RefCell::new(callbacks),
bitmap: RefCell::new(GdiBitmap::new_empty()),
#[cfg(feature = "opengl")]
gl_state: None,
}));
// Careful: `raw` owns a ref to inner, but there is no Drop impl
@ -291,17 +295,23 @@ impl WindowOps for Window {
Connection::with_window_inner(self.0, move |inner| {
let window = Window(inner.hwnd);
let dc = unsafe { GetDC(inner.hwnd.0) };
match crate::egl::GlState::create(Some(dc as *const _), inner.hwnd.0) {
Ok(_) => eprintln!("EGL initialized!?"),
Err(err) => eprintln!("EGL: {}", err),
};
let gl_state = super::wgl::GlState::create(inner.hwnd.0)
.map(Rc::new)
.and_then(|state| unsafe {
Ok(glium::backend::Context::new(
Rc::clone(&state),
true,
if cfg!(debug_assertions) {
glium::debug::DebugCallbackBehavior::DebugMessageOnError
} else {
glium::debug::DebugCallbackBehavior::Ignore
},
)?)
});
func(
inner.callbacks.borrow_mut().as_any(),
&window,
Err(failure::err_msg("opengl not supported in this build")),
);
inner.gl_state = gl_state.as_ref().map(Rc::clone).ok();
func(inner.callbacks.borrow_mut().as_any(), &window, gl_state);
});
}
}
@ -449,6 +459,19 @@ unsafe fn wm_paint(hwnd: HWND, _msg: UINT, _wparam: WPARAM, _lparam: LPARAM) ->
let width = rect_width(&rect) as usize;
let height = rect_height(&rect) as usize;
#[cfg(feature = "opengl")]
{
if let Some(gl_context) = inner.gl_state.as_ref() {
let mut frame =
glium::Frame::new(Rc::clone(&gl_context), (width as u32, height as u32));
inner.callbacks.borrow_mut().paint_opengl(&mut frame);
frame.finish().expect("frame.finish failed");
EndPaint(hwnd, &mut ps);
return Some(0);
}
}
if width > 0 && height > 0 {
let mut bitmap = inner.bitmap.borrow_mut();
let (bm_width, bm_height) = bitmap.image_dimensions();