Browse Source

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
pull/2389/head
Red Artist 2 years ago
committed by GitHub
parent
commit
8eb687cf04
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 83
      Cargo.lock
  2. 13
      crates/eframe/Cargo.toml
  3. 183
      crates/eframe/src/native/run.rs

83
Cargo.lock

@ -1261,11 +1261,12 @@ dependencies = [
"egui-winit",
"egui_glow",
"glow",
"glutin",
"glutin 0.30.0",
"image",
"js-sys",
"percent-encoding",
"puffin",
"raw-window-handle 0.5.0",
"ron",
"serde",
"tracing",
@ -1399,7 +1400,7 @@ dependencies = [
"egui",
"egui-winit",
"glow",
"glutin",
"glutin 0.29.1",
"memoffset",
"puffin",
"tracing",
@ -1863,7 +1864,7 @@ dependencies = [
"backtrace",
"fnv",
"gl_generator",
"glutin",
"glutin 0.29.1",
"lazy_static",
"memoffset",
"smallvec",
@ -1897,10 +1898,10 @@ dependencies = [
"cgl",
"cocoa",
"core-foundation",
"glutin_egl_sys",
"glutin_egl_sys 0.1.6",
"glutin_gles2_sys",
"glutin_glx_sys",
"glutin_wgl_sys",
"glutin_glx_sys 0.1.8",
"glutin_wgl_sys 0.1.5",
"libloading",
"log",
"objc",
@ -1914,6 +1915,29 @@ dependencies = [
"winit",
]
[[package]]
name = "glutin"
version = "0.30.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34acbf502536f1d125f0fc09b6ad8824e93e6da7b99e86d3383e6b8310ba3554"
dependencies = [
"bitflags",
"cfg_aliases",
"cgl",
"cocoa",
"core-foundation",
"glutin_egl_sys 0.3.0",
"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",
"windows-sys",
"x11-dl",
]
[[package]]
name = "glutin_egl_sys"
version = "0.1.6"
@ -1924,6 +1948,16 @@ dependencies = [
"winapi",
]
[[package]]
name = "glutin_egl_sys"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c3c95a2d7a54bab0c74759794efb5cd63470d4504cbe85ed4114dc82c98bdc1"
dependencies = [
"gl_generator",
"windows-sys",
]
[[package]]
name = "glutin_gles2_sys"
version = "0.1.5"
@ -1944,6 +1978,16 @@ dependencies = [
"x11-dl",
]
[[package]]
name = "glutin_glx_sys"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "947c4850c58211c9627969c2b4e2674764b81ae5b47bab2c9a477d7942f96e0f"
dependencies = [
"gl_generator",
"x11-dl",
]
[[package]]
name = "glutin_wgl_sys"
version = "0.1.5"
@ -1953,6 +1997,15 @@ dependencies = [
"gl_generator",
]
[[package]]
name = "glutin_wgl_sys"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "20c33975a6c9d49d72c8f032a60079bf8df536954fbf9e4cee90396ace815c57"
dependencies = [
"gl_generator",
]
[[package]]
name = "gobject-sys"
version = "0.15.10"
@ -4246,7 +4299,7 @@ dependencies = [
"scoped-tls",
"wayland-commons",
"wayland-scanner",
"wayland-sys",
"wayland-sys 0.29.4",
]
[[package]]
@ -4258,7 +4311,7 @@ dependencies = [
"nix 0.22.3",
"once_cell",
"smallvec",
"wayland-sys",
"wayland-sys 0.29.4",
]
[[package]]
@ -4279,7 +4332,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83281d69ee162b59031c666385e93bde4039ec553b90c4191cdb128ceea29a3a"
dependencies = [
"wayland-client",
"wayland-sys",
"wayland-sys 0.29.4",
]
[[package]]
@ -4316,6 +4369,18 @@ dependencies = [
"pkg-config",
]
[[package]]
name = "wayland-sys"
version = "0.30.0-beta.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1117fe4570fe063122ba2b1b1e39e56fb1a73921d395f9288af06af0dd1c7f55"
dependencies = [
"dlib",
"lazy_static",
"log",
"pkg-config",
]
[[package]]
name = "web-sys"
version = "0.3.60"

13
crates/eframe/Cargo.toml

@ -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",
] }

183
crates/eframe/src/native/run.rs

@ -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 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()
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");
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>) {

Loading…
Cancel
Save