mirror of
https://github.com/emilk/egui.git
synced 2026-08-29 12:50:04 -04:00
Glutin Upgrade (#2187)
* working. but x11 blurry * fixed x11 blurry. was just accidentally using multisampling even when user didnt request it * allow dbg macro temporarily * add windows WGL fallback support when EGL fails * fmt * glutin features explicitly added * extract glutin context creation into a fn * fix warnings
This commit is contained in:
@@ -87,7 +87,16 @@ egui-winit = { version = "0.19.0", path = "../egui-winit", default-features = fa
|
||||
"clipboard",
|
||||
"links",
|
||||
] }
|
||||
glutin = { version = "0.29.0" }
|
||||
# we can expose these to user so that they can select which backends they want to enable to avoid compiling useless deps.
|
||||
# this can be done at the same time we expose x11/wayland features of winit crate.
|
||||
glutin = { version = "0.30.0", features = [
|
||||
"egl",
|
||||
"glx",
|
||||
"x11",
|
||||
"wayland",
|
||||
"wgl",
|
||||
] }
|
||||
raw-window-handle = { version = "0.5.0" }
|
||||
winit = "0.27.2"
|
||||
|
||||
# optional native:
|
||||
@@ -95,7 +104,7 @@ dark-light = { version = "0.2.1", optional = true }
|
||||
directories-next = { version = "2", optional = true }
|
||||
egui-wgpu = { version = "0.19.0", path = "../egui-wgpu", optional = true, features = [
|
||||
"winit",
|
||||
] }
|
||||
] } # if wgpu is used, use it with winit
|
||||
image = { version = "0.24", optional = true, default-features = false, features = [
|
||||
"png",
|
||||
] }
|
||||
|
||||
@@ -305,7 +305,145 @@ mod glow_integration {
|
||||
|
||||
// Conceptually this will be split out eventually so that the rest of the state
|
||||
// can be persistent.
|
||||
gl_window: glutin::WindowedContext<glutin::PossiblyCurrent>,
|
||||
gl_window: GlutinWindowContext,
|
||||
}
|
||||
struct GlutinWindowContext {
|
||||
window: winit::window::Window,
|
||||
gl_context: glutin::context::PossiblyCurrentContext,
|
||||
gl_display: glutin::display::Display,
|
||||
gl_surface: glutin::surface::Surface<glutin::surface::WindowSurface>,
|
||||
}
|
||||
|
||||
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,
|
||||
native_options: &epi::NativeOptions,
|
||||
) -> Self {
|
||||
use glutin::prelude::*;
|
||||
use raw_window_handle::*;
|
||||
let hardware_acceleration = match native_options.hardware_acceleration {
|
||||
crate::HardwareAcceleration::Required => Some(true),
|
||||
crate::HardwareAcceleration::Preferred => None,
|
||||
crate::HardwareAcceleration::Off => Some(false),
|
||||
};
|
||||
|
||||
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.
|
||||
// TODO: check whether we can expose these options as "features", so that users can select the relevant backend they want.
|
||||
|
||||
// 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)
|
||||
.expect("failed to create glutin display");
|
||||
let swap_interval = if native_options.vsync {
|
||||
glutin::surface::SwapInterval::Wait(std::num::NonZeroU32::new(1).unwrap())
|
||||
} else {
|
||||
glutin::surface::SwapInterval::DontWait
|
||||
};
|
||||
|
||||
let config_template = glutin::config::ConfigTemplateBuilder::new()
|
||||
.prefer_hardware_accelerated(hardware_acceleration)
|
||||
.with_depth_size(native_options.depth_buffer);
|
||||
// we don't know if multi sampling option is set. so, check if its more than 0.
|
||||
let config_template = if native_options.multisampling > 0 {
|
||||
config_template.with_multisampling(
|
||||
native_options
|
||||
.multisampling
|
||||
.try_into()
|
||||
.expect("failed to fit multisamples into u8"),
|
||||
)
|
||||
} else {
|
||||
config_template
|
||||
};
|
||||
let config_template = config_template
|
||||
.with_stencil_size(native_options.stencil_buffer)
|
||||
.with_transparency(native_options.transparent)
|
||||
.compatible_with_native_window(raw_window_handle)
|
||||
.build();
|
||||
// finds all valid configurations supported by this display that match the config_template
|
||||
// this is where we will try to get a "fallback" config if we are okay with ignoring some native
|
||||
// options required by user like multi sampling, srgb, transparency etc..
|
||||
// TODO: need to figure out a good fallback config template
|
||||
let config = gl_display
|
||||
.find_configs(config_template)
|
||||
.expect("failed to find even a single matching configuration")
|
||||
.next()
|
||||
.expect("failed to find a matching configuration for creating opengl context");
|
||||
|
||||
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::<glutin::surface::WindowSurface>::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)
|
||||
.expect("failed to create opengl context");
|
||||
|
||||
let gl_surface = gl_display
|
||||
.create_window_surface(&config, &surface_attributes)
|
||||
.expect("failed to create glutin window surface");
|
||||
let gl_context = gl_context
|
||||
.make_current(&gl_surface)
|
||||
.expect("failed to make gl context current");
|
||||
gl_surface
|
||||
.set_swap_interval(&gl_context, swap_interval)
|
||||
.expect("failed to set vsync swap interval");
|
||||
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<u32>) {
|
||||
use glutin::surface::GlSurface;
|
||||
self.gl_surface.resize(
|
||||
&self.gl_context,
|
||||
physical_size
|
||||
.width
|
||||
.try_into()
|
||||
.expect("physical size must not be zero"),
|
||||
physical_size
|
||||
.height
|
||||
.try_into()
|
||||
.expect("physical size must not be zero"),
|
||||
);
|
||||
}
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
struct GlowWinitApp {
|
||||
@@ -347,44 +485,33 @@ mod glow_integration {
|
||||
storage: Option<&dyn epi::Storage>,
|
||||
title: &String,
|
||||
native_options: &NativeOptions,
|
||||
) -> (
|
||||
glutin::WindowedContext<glutin::PossiblyCurrent>,
|
||||
glow::Context,
|
||||
) {
|
||||
) -> (GlutinWindowContext, glow::Context) {
|
||||
crate::profile_function!();
|
||||
|
||||
use crate::HardwareAcceleration;
|
||||
|
||||
let hardware_acceleration = match native_options.hardware_acceleration {
|
||||
HardwareAcceleration::Required => Some(true),
|
||||
HardwareAcceleration::Preferred => None,
|
||||
HardwareAcceleration::Off => Some(false),
|
||||
};
|
||||
let window_settings = epi_integration::load_window_settings(storage);
|
||||
|
||||
let window_builder = epi_integration::window_builder(native_options, &window_settings)
|
||||
.with_title(title)
|
||||
.with_transparent(native_options.transparent)
|
||||
// Keep hidden until we've painted something. See https://github.com/emilk/egui/pull/2279
|
||||
// We must also keep the window hidden until AccessKit is initialized.
|
||||
.with_visible(false);
|
||||
let winit_window = window_builder
|
||||
.build(event_loop)
|
||||
.expect("failed to create winit window");
|
||||
// a lot of the code below has been lifted from glutin example in their repo.
|
||||
let glutin_window_context =
|
||||
unsafe { GlutinWindowContext::new(winit_window, native_options) };
|
||||
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");
|
||||
|
||||
let gl_window = unsafe {
|
||||
glutin::ContextBuilder::new()
|
||||
.with_hardware_acceleration(hardware_acceleration)
|
||||
.with_depth_buffer(native_options.depth_buffer)
|
||||
.with_multisampling(native_options.multisampling)
|
||||
.with_stencil_buffer(native_options.stencil_buffer)
|
||||
.with_vsync(native_options.vsync)
|
||||
.build_windowed(window_builder, event_loop)
|
||||
.unwrap()
|
||||
.make_current()
|
||||
.unwrap()
|
||||
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)
|
||||
}
|
||||
|
||||
fn init_run_state(&mut self, event_loop: &EventLoopWindowTarget<UserEvent>) {
|
||||
|
||||
Reference in New Issue
Block a user