diff --git a/Cargo.lock b/Cargo.lock index 51cfa905..424cda23 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1306,7 +1306,7 @@ dependencies = [ "egui-winit", "egui_glow", "glow", - "glutin 0.30.0", + "glutin 0.30.2", "image", "js-sys", "percent-encoding", @@ -1445,9 +1445,10 @@ dependencies = [ "egui", "egui-winit", "glow", - "glutin 0.29.1", + "glutin 0.30.2", "memoffset", "puffin", + "raw-window-handle 0.5.0", "tracing", "wasm-bindgen", "web-sys", @@ -1969,23 +1970,23 @@ dependencies = [ [[package]] name = "glutin" -version = "0.30.0" +version = "0.30.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34acbf502536f1d125f0fc09b6ad8824e93e6da7b99e86d3383e6b8310ba3554" +checksum = "0282c380a3adb52ae095e5847cc575c6bf79d296dcbf333e00be4a3fca07235e" dependencies = [ "bitflags", "cfg_aliases", "cgl", "cocoa", "core-foundation", - "glutin_egl_sys 0.3.0", + "glutin_egl_sys 0.3.1", "glutin_glx_sys 0.3.0", "glutin_wgl_sys 0.3.0", "libloading", "objc", "once_cell", "raw-window-handle 0.5.0", - "wayland-sys 0.30.0-beta.12", + "wayland-sys 0.30.0", "windows-sys 0.36.1", "x11-dl", ] @@ -2002,9 +2003,9 @@ dependencies = [ [[package]] name = "glutin_egl_sys" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c3c95a2d7a54bab0c74759794efb5cd63470d4504cbe85ed4114dc82c98bdc1" +checksum = "3adbb8fec0e18e340f990c78f79f5f0e142d0d83f46b10909aaa7d251c00afdf" dependencies = [ "gl_generator", "windows-sys 0.36.1", @@ -4460,9 +4461,9 @@ dependencies = [ [[package]] name = "wayland-sys" -version = "0.30.0-beta.12" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1117fe4570fe063122ba2b1b1e39e56fb1a73921d395f9288af06af0dd1c7f55" +checksum = "8bcdbc325d8a78a9f49dcb77b39e92656e93b3f69eb4d60245f2116ec4bb0a97" dependencies = [ "dlib", "lazy_static", diff --git a/crates/egui_glow/Cargo.toml b/crates/egui_glow/Cargo.toml index 1f09feeb..89eb8755 100644 --- a/crates/egui_glow/Cargo.toml +++ b/crates/egui_glow/Cargo.toml @@ -72,7 +72,8 @@ wasm-bindgen = { version = "0.2" } [dev-dependencies] -glutin = "0.29.0" # examples/pure_glow +glutin = "0.30.2" # examples/pure_glow +raw-window-handle = "0.5.0" [[example]] diff --git a/crates/egui_glow/examples/pure_glow.rs b/crates/egui_glow/examples/pure_glow.rs index 54d94dd1..15f6dc2e 100644 --- a/crates/egui_glow/examples/pure_glow.rs +++ b/crates/egui_glow/examples/pure_glow.rs @@ -3,10 +3,124 @@ #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release #![allow(unsafe_code)] +use egui_winit::winit; + +/// The majority of `GlutinWindowContext` is taken from `eframe` +struct GlutinWindowContext { + window: winit::window::Window, + gl_context: glutin::context::PossiblyCurrentContext, + gl_display: glutin::display::Display, + gl_surface: glutin::surface::Surface, +} + +impl GlutinWindowContext { + // refactor this function to use `glutin-winit` crate eventually. + // preferably add android support at the same time. + #[allow(unsafe_code)] + unsafe fn new(winit_window: winit::window::Window) -> Self { + use glutin::prelude::*; + use raw_window_handle::*; + + let raw_display_handle = winit_window.raw_display_handle(); + let raw_window_handle = winit_window.raw_window_handle(); + + // EGL is crossplatform and the official khronos way + // but sometimes platforms/drivers may not have it, so we use back up options where possible. + + // try egl and fallback to windows wgl. Windows is the only platform that *requires* window handle to create display. + #[cfg(target_os = "windows")] + let preference = glutin::display::DisplayApiPreference::EglThenWgl(Some(window_handle)); + // try egl and fallback to x11 glx + #[cfg(target_os = "linux")] + let preference = glutin::display::DisplayApiPreference::EglThenGlx(Box::new( + winit::platform::unix::register_xlib_error_hook, + )); + #[cfg(target_os = "macos")] + let preference = glutin::display::DisplayApiPreference::Cgl; + #[cfg(target_os = "android")] + let preference = glutin::display::DisplayApiPreference::Egl; + + let gl_display = glutin::display::Display::new(raw_display_handle, preference).unwrap(); + + let config_template = glutin::config::ConfigTemplateBuilder::new() + .prefer_hardware_accelerated(None) + .with_depth_size(0) + .with_stencil_size(0) + .with_transparency(false) + .compatible_with_native_window(raw_window_handle) + .build(); + + let config = gl_display + .find_configs(config_template) + .unwrap() + .next() + .unwrap(); + + let context_attributes = + glutin::context::ContextAttributesBuilder::new().build(Some(raw_window_handle)); + // for surface creation. + let (width, height): (u32, u32) = winit_window.inner_size().into(); + let surface_attributes = + glutin::surface::SurfaceAttributesBuilder::::new() + .build( + raw_window_handle, + std::num::NonZeroU32::new(width).unwrap(), + std::num::NonZeroU32::new(height).unwrap(), + ); + // start creating the gl objects + let gl_context = gl_display + .create_context(&config, &context_attributes) + .unwrap(); + + let gl_surface = gl_display + .create_window_surface(&config, &surface_attributes) + .unwrap(); + + let gl_context = gl_context.make_current(&gl_surface).unwrap(); + + gl_surface + .set_swap_interval( + &gl_context, + glutin::surface::SwapInterval::Wait(std::num::NonZeroU32::new(1).unwrap()), + ) + .unwrap(); + + GlutinWindowContext { + window: winit_window, + gl_context, + gl_display, + gl_surface, + } + } + + fn window(&self) -> &winit::window::Window { + &self.window + } + + fn resize(&self, physical_size: winit::dpi::PhysicalSize) { + use glutin::surface::GlSurface; + self.gl_surface.resize( + &self.gl_context, + physical_size.width.try_into().unwrap(), + physical_size.height.try_into().unwrap(), + ); + } + + fn swap_buffers(&self) -> glutin::error::Result<()> { + use glutin::surface::GlSurface; + self.gl_surface.swap_buffers(&self.gl_context) + } + + fn get_proc_address(&self, addr: &std::ffi::CStr) -> *const std::ffi::c_void { + use glutin::display::GlDisplay; + self.gl_display.get_proc_address(addr) + } +} + fn main() { let mut clear_color = [0.1, 0.1, 0.1]; - let event_loop = glutin::event_loop::EventLoopBuilder::with_user_event().build(); + let event_loop = winit::event_loop::EventLoopBuilder::with_user_event().build(); let (gl_window, gl) = create_display(&event_loop); let gl = std::sync::Arc::new(gl); @@ -27,16 +141,16 @@ fn main() { }); *control_flow = if quit { - glutin::event_loop::ControlFlow::Exit + winit::event_loop::ControlFlow::Exit } else if repaint_after.is_zero() { gl_window.window().request_redraw(); - glutin::event_loop::ControlFlow::Poll + winit::event_loop::ControlFlow::Poll } else if let Some(repaint_after_instant) = std::time::Instant::now().checked_add(repaint_after) { - glutin::event_loop::ControlFlow::WaitUntil(repaint_after_instant) + winit::event_loop::ControlFlow::WaitUntil(repaint_after_instant) } else { - glutin::event_loop::ControlFlow::Wait + winit::event_loop::ControlFlow::Wait }; { @@ -61,20 +175,19 @@ fn main() { // Platform-dependent event handlers to workaround a winit bug // See: https://github.com/rust-windowing/winit/issues/987 // See: https://github.com/rust-windowing/winit/issues/1619 - glutin::event::Event::RedrawEventsCleared if cfg!(windows) => redraw(), - glutin::event::Event::RedrawRequested(_) if !cfg!(windows) => redraw(), + winit::event::Event::RedrawEventsCleared if cfg!(windows) => redraw(), + winit::event::Event::RedrawRequested(_) if !cfg!(windows) => redraw(), - glutin::event::Event::WindowEvent { event, .. } => { - use glutin::event::WindowEvent; + winit::event::Event::WindowEvent { event, .. } => { + use winit::event::WindowEvent; if matches!(event, WindowEvent::CloseRequested | WindowEvent::Destroyed) { - *control_flow = glutin::event_loop::ControlFlow::Exit; + *control_flow = winit::event_loop::ControlFlow::Exit; } - if let glutin::event::WindowEvent::Resized(physical_size) = &event { + if let winit::event::WindowEvent::Resized(physical_size) = &event { gl_window.resize(*physical_size); - } else if let glutin::event::WindowEvent::ScaleFactorChanged { - new_inner_size, - .. + } else if let winit::event::WindowEvent::ScaleFactorChanged { + new_inner_size, .. } = &event { gl_window.resize(**new_inner_size); @@ -86,10 +199,10 @@ fn main() { gl_window.window().request_redraw(); } } - glutin::event::Event::LoopDestroyed => { + winit::event::Event::LoopDestroyed => { egui_glow.destroy(); } - glutin::event::Event::NewEvents(glutin::event::StartCause::ResumeTimeReached { + winit::event::Event::NewEvents(winit::event::StartCause::ResumeTimeReached { .. }) => { gl_window.window().request_redraw(); @@ -101,32 +214,29 @@ fn main() { } fn create_display( - event_loop: &glutin::event_loop::EventLoop<()>, -) -> ( - glutin::WindowedContext, - glow::Context, -) { - let window_builder = glutin::window::WindowBuilder::new() + event_loop: &winit::event_loop::EventLoopWindowTarget<()>, +) -> (GlutinWindowContext, glow::Context) { + let winit_window = winit::window::WindowBuilder::new() .with_resizable(true) - .with_inner_size(glutin::dpi::LogicalSize { + .with_inner_size(winit::dpi::LogicalSize { width: 800.0, height: 600.0, }) .with_title("egui_glow example") - .with_visible(false); // Keep hidden until we've painted something. See https://github.com/emilk/egui/pull/2279 + .with_visible(false) + .build(event_loop) + .unwrap(); // Keep hidden until we've painted something. See https://github.com/emilk/egui/pull/2279 - let gl_window = unsafe { - glutin::ContextBuilder::new() - .with_depth_buffer(0) - .with_stencil_buffer(0) - .with_vsync(true) - .build_windowed(window_builder, event_loop) - .unwrap() - .make_current() - .unwrap() + // a lot of the code below has been lifted from glutin example in their repo. + let glutin_window_context = unsafe { GlutinWindowContext::new(winit_window) }; + let gl = unsafe { + glow::Context::from_loader_function(|s| { + let s = std::ffi::CString::new(s) + .expect("failed to construct C string from string for gl proc address"); + + glutin_window_context.get_proc_address(&s) + }) }; - let gl = unsafe { glow::Context::from_loader_function(|s| gl_window.get_proc_address(s)) }; - - (gl_window, gl) + (glutin_window_context, gl) }