1
0
mirror of https://github.com/emilk/egui.git synced 2026-09-02 06:40:06 -04:00

create_viewport_sync prep Glutin

WGPU Unimplemented again, use Arc<RwLock<T>> for a lot of things
This commit is contained in:
Konkitoman
2023-08-01 17:30:36 +03:00
parent b75fe9bbc4
commit c7c9713bf8

View File

@@ -1,9 +1,9 @@
//! Note that this file contains two similar paths - one for [`glow`], one for [`wgpu`]. //! Note that this file contains two similar paths - one for [`glow`], one for [`wgpu`].
//! When making changes to one you often also want to apply it to the other. //! When making changes to one you often also want to apply it to the other.
use std::time::Instant; use std::{sync::Arc, time::Instant};
use egui::{epaint::ahash::HashMap, window::ViewportBuilder}; use egui::{epaint::ahash::HashMap, mutex::RwLock, window::ViewportBuilder};
use raw_window_handle::{HasRawDisplayHandle as _, HasRawWindowHandle as _}; use raw_window_handle::{HasRawDisplayHandle as _, HasRawWindowHandle as _};
use winit::{ use winit::{
event_loop::{ControlFlow, EventLoop, EventLoopBuilder, EventLoopProxy, EventLoopWindowTarget}, event_loop::{ControlFlow, EventLoop, EventLoopBuilder, EventLoopProxy, EventLoopWindowTarget},
@@ -72,9 +72,12 @@ trait WinitApp {
fn is_focused(&self, window_id: winit::window::WindowId) -> bool; fn is_focused(&self, window_id: winit::window::WindowId) -> bool;
fn integration(&self) -> Option<&EpiIntegration>; fn integration(&self) -> Option<Arc<RwLock<EpiIntegration>>>;
fn window(&self, window_id: winit::window::WindowId) -> Option<&winit::window::Window>; fn window(
&self,
window_id: winit::window::WindowId,
) -> Option<Arc<RwLock<winit::window::Window>>>;
fn get_window_winit_id(&self, id: u64) -> Option<winit::window::WindowId>; fn get_window_winit_id(&self, id: u64) -> Option<winit::window::WindowId>;
fn get_window_id(&self, id: &winit::window::WindowId) -> Option<u64>; fn get_window_id(&self, id: &winit::window::WindowId) -> Option<u64>;
@@ -248,7 +251,7 @@ fn run_and_return(
for (window_id, repaint_time) in windows_next_repaint_times.clone().iter() { for (window_id, repaint_time) in windows_next_repaint_times.clone().iter() {
if *repaint_time <= Instant::now() { if *repaint_time <= Instant::now() {
if let Some(window) = winit_app.window(*window_id) { if let Some(window) = winit_app.window(*window_id) {
window.request_redraw(); window.read().request_redraw();
windows_next_repaint_times.remove(window_id); windows_next_repaint_times.remove(window_id);
control_flow.set_poll(); control_flow.set_poll();
} else { } else {
@@ -387,7 +390,7 @@ fn run_and_exit(event_loop: EventLoop<UserEvent>, mut winit_app: impl WinitApp +
if *repaint_time <= Instant::now() { if *repaint_time <= Instant::now() {
if let Some(window) = winit_app.window(*window_id) { if let Some(window) = winit_app.window(*window_id) {
log::trace!("request_redraw"); log::trace!("request_redraw");
window.request_redraw(); window.read().request_redraw();
windows_next_repaint_times.remove(window_id); windows_next_repaint_times.remove(window_id);
} }
control_flow.set_poll(); control_flow.set_poll();
@@ -416,7 +419,9 @@ fn run_and_exit(event_loop: EventLoop<UserEvent>, mut winit_app: impl WinitApp +
mod glow_integration { mod glow_integration {
use std::sync::Arc; use std::sync::Arc;
use egui::{epaint::ahash::HashMap, window::ViewportBuilder, NumExt as _, ViewportRender}; use egui::{
epaint::ahash::HashMap, mutex::RwLock, window::ViewportBuilder, NumExt as _, ViewportRender,
};
use egui_winit::EventResponse; use egui_winit::EventResponse;
use glutin::{ use glutin::{
display::GetGlDisplay, display::GetGlDisplay,
@@ -446,17 +451,17 @@ mod glow_integration {
struct GlowWinitRunning { struct GlowWinitRunning {
gl: Arc<glow::Context>, gl: Arc<glow::Context>,
painter: egui_glow::Painter, painter: egui_glow::Painter,
integration: epi_integration::EpiIntegration, integration: Arc<RwLock<epi_integration::EpiIntegration>>,
app: Box<dyn epi::App>, app: Box<dyn epi::App>,
// Conceptually this will be split out eventually so that the rest of the state // Conceptually this will be split out eventually so that the rest of the state
// can be persistent. // can be persistent.
gl_window: GlutinWindowContext, glutin_ctx: Arc<RwLock<GlutinWindowContext>>,
} }
struct Window { struct Window {
builder: ViewportBuilder, builder: ViewportBuilder,
gl_surface: Option<glutin::surface::Surface<glutin::surface::WindowSurface>>, gl_surface: Option<glutin::surface::Surface<glutin::surface::WindowSurface>>,
window: Option<winit::window::Window>, window: Option<Arc<RwLock<winit::window::Window>>>,
window_id: u64, window_id: u64,
parent_id: u64, parent_id: u64,
render: Option<Arc<Box<ViewportRender>>>, render: Option<Arc<Box<ViewportRender>>>,
@@ -478,9 +483,11 @@ mod glow_integration {
struct GlutinWindowContext { struct GlutinWindowContext {
swap_interval: glutin::surface::SwapInterval, swap_interval: glutin::surface::SwapInterval,
gl_config: glutin::config::Config, gl_config: glutin::config::Config,
current_gl_context: Option<glutin::context::PossiblyCurrentContext>, current_gl_context: Option<glutin::context::PossiblyCurrentContext>,
not_current_gl_context: Option<glutin::context::NotCurrentContext>, not_current_gl_context: Option<glutin::context::NotCurrentContext>,
windows: Vec<Window>,
windows: HashMap<u64, Arc<RwLock<Window>>>,
window_maps: HashMap<winit::window::WindowId, u64>, window_maps: HashMap<winit::window::WindowId, u64>,
} }
@@ -592,6 +599,20 @@ mod glow_integration {
window_maps.insert(window.id(), 0); window_maps.insert(window.id(), 0);
} }
let mut windows = HashMap::default();
windows.insert(
0,
Arc::new(RwLock::new(Window {
builder: window_builder,
gl_surface: None,
window: window.map(|w| Arc::new(RwLock::new(w))),
window_id: 0,
egui_winit: None,
render: None,
parent_id: 0,
})),
);
// the fun part with opengl gl is that we never know whether there is an error. the context creation might have failed, but // the fun part with opengl gl is that we never know whether there is an error. the context creation might have failed, but
// it could keep working until we try to make surface current or swap buffers or something else. future glutin improvements might // it could keep working until we try to make surface current or swap buffers or something else. future glutin improvements might
// help us start from scratch again if we fail context creation and go back to preferEgl or try with different config etc.. // help us start from scratch again if we fail context creation and go back to preferEgl or try with different config etc..
@@ -601,15 +622,7 @@ mod glow_integration {
gl_config, gl_config,
current_gl_context: None, current_gl_context: None,
not_current_gl_context, not_current_gl_context,
windows: vec![Window { windows,
builder: window_builder,
gl_surface: None,
window,
window_id: 0,
egui_winit: None,
render: None,
parent_id: 0,
}],
window_maps, window_maps,
}) })
} }
@@ -624,7 +637,8 @@ mod glow_integration {
/// we presently assume that we will /// we presently assume that we will
#[allow(unsafe_code)] #[allow(unsafe_code)]
fn on_resume(&mut self, event_loop: &EventLoopWindowTarget<UserEvent>) -> Result<()> { fn on_resume(&mut self, event_loop: &EventLoopWindowTarget<UserEvent>) -> Result<()> {
for win in self.windows.iter_mut() { for (_, win) in self.windows.iter_mut() {
let mut win = win.write();
if win.gl_surface.is_some() { if win.gl_surface.is_some() {
continue; continue;
} }
@@ -632,13 +646,17 @@ mod glow_integration {
// make sure we have a window or create one. // make sure we have a window or create one.
let window = win.window.take().unwrap_or_else(|| { let window = win.window.take().unwrap_or_else(|| {
log::debug!("window doesn't exist yet. creating one now with finalize_window"); log::debug!("window doesn't exist yet. creating one now with finalize_window");
Arc::new(RwLock::new(
glutin_winit::finalize_window( glutin_winit::finalize_window(
event_loop, event_loop,
create_winit_window_builder(&win.builder), create_winit_window_builder(&win.builder),
&self.gl_config, &self.gl_config,
) )
.expect("failed to finalize glutin window") .expect("failed to finalize glutin window"),
))
}); });
{
let window = window.read();
// surface attributes // surface attributes
let (width, height): (u32, u32) = window.inner_size().into(); let (width, height): (u32, u32) = window.inner_size().into();
let width = std::num::NonZeroU32::new(width.at_least(1)).unwrap(); let width = std::num::NonZeroU32::new(width.at_least(1)).unwrap();
@@ -657,7 +675,9 @@ mod glow_integration {
.display() .display()
.create_window_surface(&self.gl_config, &surface_attributes)? .create_window_surface(&self.gl_config, &surface_attributes)?
}; };
log::debug!("surface created successfully: {gl_surface:?}.making context current"); log::debug!(
"surface created successfully: {gl_surface:?}.making context current"
);
// make surface and context current. // make surface and context current.
let not_current_gl_context = let not_current_gl_context =
if let Some(not_current_context) = self.not_current_gl_context.take() { if let Some(not_current_context) = self.not_current_gl_context.take() {
@@ -693,6 +713,7 @@ mod glow_integration {
self.current_gl_context = Some(current_gl_context); self.current_gl_context = Some(current_gl_context);
self.window_maps.insert(window.id(), win.window_id); self.window_maps.insert(window.id(), win.window_id);
window.request_redraw(); window.request_redraw();
}
win.window = Some(window); win.window = Some(window);
} }
Ok(()) Ok(())
@@ -701,7 +722,8 @@ mod glow_integration {
/// only applies for android. but we basically drop surface + window and make context not current /// only applies for android. but we basically drop surface + window and make context not current
fn on_suspend(&mut self) -> Result<()> { fn on_suspend(&mut self) -> Result<()> {
log::debug!("received suspend event. dropping window and surface"); log::debug!("received suspend event. dropping window and surface");
for window in self.windows.iter_mut() { for (_, window) in self.windows.iter_mut() {
let mut window = window.write();
window.gl_surface.take(); window.gl_surface.take();
window.window.take(); window.window.take();
} }
@@ -714,18 +736,19 @@ mod glow_integration {
Ok(()) Ok(())
} }
fn window(&self, index: usize) -> &winit::window::Window { fn window(&self, window_id: u64) -> Arc<RwLock<Window>> {
self.windows[index] self.windows
.window .get(&window_id)
.as_ref() .map(|w| w.clone())
.expect("winit window doesn't exist") .expect("winit window doesn't exist")
} }
fn resize(&mut self, window_id: u64, physical_size: winit::dpi::PhysicalSize<u32>) { fn resize(&mut self, window_id: u64, physical_size: winit::dpi::PhysicalSize<u32>) {
let width = std::num::NonZeroU32::new(physical_size.width.at_least(1)).unwrap(); let width = std::num::NonZeroU32::new(physical_size.width.at_least(1)).unwrap();
let height = std::num::NonZeroU32::new(physical_size.height.at_least(1)).unwrap(); let height = std::num::NonZeroU32::new(physical_size.height.at_least(1)).unwrap();
for window in self.windows.iter_mut() {
if window.window_id == window_id { if let Some(window) = self.windows.get(&window_id) {
let mut window = window.write();
if let Some(gl_surface) = &window.gl_surface { if let Some(gl_surface) = &window.gl_surface {
self.current_gl_context = Some( self.current_gl_context = Some(
self.current_gl_context self.current_gl_context
@@ -746,7 +769,6 @@ mod glow_integration {
} }
} }
} }
}
fn get_proc_address(&self, addr: &std::ffi::CStr) -> *const std::ffi::c_void { fn get_proc_address(&self, addr: &std::ffi::CStr) -> *const std::ffi::c_void {
self.gl_config.display().get_proc_address(addr) self.gl_config.display().get_proc_address(addr)
@@ -757,13 +779,13 @@ mod glow_integration {
repaint_proxy: Arc<egui::mutex::Mutex<EventLoopProxy<UserEvent>>>, repaint_proxy: Arc<egui::mutex::Mutex<EventLoopProxy<UserEvent>>>,
app_name: String, app_name: String,
native_options: epi::NativeOptions, native_options: epi::NativeOptions,
running: Option<GlowWinitRunning>, running: Arc<RwLock<Option<GlowWinitRunning>>>,
// Note that since this `AppCreator` is FnOnce we are currently unable to support // Note that since this `AppCreator` is FnOnce we are currently unable to support
// re-initializing the `GlowWinitRunning` state on Android if the application // re-initializing the `GlowWinitRunning` state on Android if the application
// suspends and resumes. // suspends and resumes.
app_creator: Option<epi::AppCreator>, app_creator: Option<epi::AppCreator>,
is_focused: Option<u64>, is_focused: Arc<RwLock<Option<u64>>>,
} }
impl GlowWinitApp { impl GlowWinitApp {
@@ -777,9 +799,9 @@ mod glow_integration {
repaint_proxy: Arc::new(egui::mutex::Mutex::new(event_loop.create_proxy())), repaint_proxy: Arc::new(egui::mutex::Mutex::new(event_loop.create_proxy())),
app_name: app_name.to_owned(), app_name: app_name.to_owned(),
native_options, native_options,
running: None, running: Arc::new(RwLock::new(None)),
app_creator: Some(app_creator), app_creator: Some(app_creator),
is_focused: Some(0), is_focused: Arc::new(RwLock::new(Some(0))),
} }
} }
@@ -801,8 +823,11 @@ mod glow_integration {
}; };
glutin_window_context.on_resume(event_loop)?; glutin_window_context.on_resume(event_loop)?;
if let Some(window) = &glutin_window_context.windows[0].window { if let Some(window) = &glutin_window_context.windows.get(&0) {
epi_integration::apply_native_options_to_window(window, native_options); let window = window.read();
if let Some(window) = &window.window {
epi_integration::apply_native_options_to_window(&window.read(), native_options);
}
} }
let gl = unsafe { let gl = unsafe {
@@ -837,11 +862,14 @@ mod glow_integration {
egui_glow::Painter::new(gl.clone(), "", self.native_options.shader_version) egui_glow::Painter::new(gl.clone(), "", self.native_options.shader_version)
.unwrap_or_else(|error| panic!("some OpenGL error occurred {}\n", error)); .unwrap_or_else(|error| panic!("some OpenGL error occurred {}\n", error));
let system_theme = system_theme(gl_window.window(0), &self.native_options); let system_theme = system_theme(
&gl_window.window(0).read().window.as_ref().unwrap().read(),
&self.native_options,
);
let mut integration = epi_integration::EpiIntegration::new( let mut integration = epi_integration::EpiIntegration::new(
event_loop, event_loop,
painter.max_texture_side(), painter.max_texture_side(),
gl_window.window(0), &gl_window.window(0).read().window.as_ref().unwrap().read(),
system_theme, system_theme,
&self.app_name, &self.app_name,
&self.native_options, &self.native_options,
@@ -852,10 +880,11 @@ mod glow_integration {
); );
#[cfg(feature = "accesskit")] #[cfg(feature = "accesskit")]
{ {
let window = &mut gl_window.windows[0]; let window = gl_window.windows.get(&0).unwrap();
let window = &mut *window.write();
integration.init_accesskit( integration.init_accesskit(
window.egui_winit.as_mut().unwrap(), window.egui_winit.as_mut().unwrap(),
window.window.as_ref().unwrap(), &window.window.as_ref().unwrap().read(),
self.repaint_proxy.lock().clone(), self.repaint_proxy.lock().clone(),
); );
} }
@@ -868,9 +897,24 @@ mod glow_integration {
integration.egui_ctx.set_desktop(true); integration.egui_ctx.set_desktop(true);
gl_window.window(0).set_ime_allowed(true); gl_window
.window(0)
.read()
.window
.as_ref()
.unwrap()
.read()
.set_ime_allowed(true);
if self.native_options.mouse_passthrough { if self.native_options.mouse_passthrough {
gl_window.window(0).set_cursor_hittest(false).unwrap(); gl_window
.window(0)
.read()
.window
.as_ref()
.unwrap()
.read()
.set_cursor_hittest(false)
.unwrap();
} }
{ {
@@ -894,31 +938,35 @@ mod glow_integration {
let app_creator = std::mem::take(&mut self.app_creator) let app_creator = std::mem::take(&mut self.app_creator)
.expect("Single-use AppCreator has unexpectedly already been taken"); .expect("Single-use AppCreator has unexpectedly already been taken");
let mut app = app_creator(&epi::CreationContext { let mut app;
{
let window = gl_window.window(0);
let window = &mut *window.write();
app = app_creator(&epi::CreationContext {
egui_ctx: integration.egui_ctx.clone(), egui_ctx: integration.egui_ctx.clone(),
integration_info: integration.frame.info(), integration_info: integration.frame.info(),
storage: integration.frame.storage(), storage: integration.frame.storage(),
gl: Some(gl.clone()), gl: Some(gl.clone()),
#[cfg(feature = "wgpu")] #[cfg(feature = "wgpu")]
wgpu_render_state: None, wgpu_render_state: None,
raw_display_handle: gl_window.window(0).raw_display_handle(), raw_display_handle: window.window.as_ref().unwrap().read().raw_display_handle(),
raw_window_handle: gl_window.window(0).raw_window_handle(), raw_window_handle: window.window.as_ref().unwrap().read().raw_window_handle(),
}); });
if app.warm_up_enabled() { if app.warm_up_enabled() {
let window = &mut gl_window.windows[0];
integration.warm_up( integration.warm_up(
app.as_mut(), app.as_mut(),
window.window.as_ref().unwrap(), &window.window.as_ref().unwrap().read(),
window.egui_winit.as_mut().unwrap(), window.egui_winit.as_mut().unwrap(),
); );
} }
}
self.running = Some(GlowWinitRunning { *self.running.write() = Some(GlowWinitRunning {
gl_window, glutin_ctx: Arc::new(RwLock::new(gl_window)),
gl, gl,
painter, painter,
integration, integration: Arc::new(RwLock::new(integration)),
app, app,
}); });
@@ -929,31 +977,36 @@ mod glow_integration {
impl WinitApp for GlowWinitApp { impl WinitApp for GlowWinitApp {
fn frame_nr(&self) -> u64 { fn frame_nr(&self) -> u64 {
self.running self.running
.read()
.as_ref() .as_ref()
.map_or(0, |r| r.integration.egui_ctx.frame_nr()) .map_or(0, |r| r.integration.read().egui_ctx.frame_nr())
} }
fn is_focused(&self, window_id: winit::window::WindowId) -> bool { fn is_focused(&self, window_id: winit::window::WindowId) -> bool {
if let Some(is_focused) = self.is_focused { if let Some(is_focused) = self.is_focused.read().as_ref() {
if let Some(running) = &self.running { if let Some(running) = self.running.read().as_ref() {
if let Some(window_id) = running.gl_window.window_maps.get(&window_id) { if let Some(window_id) = running.glutin_ctx.read().window_maps.get(&window_id) {
return is_focused == *window_id; return *is_focused == *window_id;
} }
} }
} }
false false
} }
fn integration(&self) -> Option<&EpiIntegration> { fn integration(&self) -> Option<Arc<RwLock<EpiIntegration>>> {
self.running.as_ref().map(|r| &r.integration) self.running.read().as_ref().map(|r| r.integration.clone())
} }
fn window(&self, window_id: winit::window::WindowId) -> Option<&winit::window::Window> { fn window(
self.running.as_ref().and_then(|r| { &self,
for window in r.gl_window.windows.iter() { window_id: winit::window::WindowId,
if let Some(window) = &window.window { ) -> Option<Arc<RwLock<winit::window::Window>>> {
if window.id() == window_id { self.running.read().as_ref().and_then(|r| {
return Some(window); let glutin_ctx = r.glutin_ctx.read();
if let Some(viewport_id) = glutin_ctx.window_maps.get(&window_id) {
if let Some(viewport) = glutin_ctx.windows.get(viewport_id) {
if let Some(window) = viewport.read().window.as_ref() {
return Some(window.clone());
} }
} }
} }
@@ -962,68 +1015,63 @@ mod glow_integration {
} }
fn get_window_winit_id(&self, id: u64) -> Option<winit::window::WindowId> { fn get_window_winit_id(&self, id: u64) -> Option<winit::window::WindowId> {
self.running.as_ref().and_then(|r| { self.running.read().as_ref().and_then(|r| {
for window in r.gl_window.windows.iter() { if let Some(window) = r.glutin_ctx.read().windows.get(&id) {
if window.window_id == id { return window.read().window.as_ref().map(|w| w.read().id());
return window.window.as_ref().map(|w| w.id());
}
} }
None None
}) })
} }
fn get_window_id(&self, id: &winit::window::WindowId) -> Option<u64> { fn get_window_id(&self, id: &winit::window::WindowId) -> Option<u64> {
self.running.as_ref().and_then(|r| { self.running
for window in r.gl_window.windows.iter() { .read()
if let Some(win) = &window.window { .as_ref()
if win.id() == *id { .and_then(|r| r.glutin_ctx.read().window_maps.get(id).cloned())
return Some(window.window_id);
}
}
}
None
})
} }
fn save_and_destroy(&mut self) { fn save_and_destroy(&mut self) {
if let Some(mut running) = self.running.take() { if let Some(mut running) = self.running.write().take() {
running running.integration.write().save(
.integration running.app.as_mut(),
.save(running.app.as_mut(), running.gl_window.window(0)); &running
.glutin_ctx
.read()
.window(0)
.read()
.window
.as_ref()
.unwrap()
.read(),
);
running.app.on_exit(Some(&running.gl)); running.app.on_exit(Some(&running.gl));
running.painter.destroy(); running.painter.destroy();
} }
} }
fn run_ui_and_paint(&mut self, window_id: winit::window::WindowId) -> Vec<EventResult> { fn run_ui_and_paint(&mut self, window_id: winit::window::WindowId) -> Vec<EventResult> {
if let Some(running) = &mut self.running { if self.running.read().is_none() {
let mut windows_indexes = vec![]; return vec![EventResult::Wait];
for (i, window) in running.gl_window.windows.iter().enumerate() {
if let Some(window) = &window.window {
if window.id() == window_id {
windows_indexes.push(i);
break;
}
}
} }
let mut inner = |window_index| { if let Some(viewport_id) = self.get_window_id(&window_id) {
#[cfg(feature = "puffin")] #[cfg(feature = "puffin")]
puffin::GlobalProfiler::lock().new_frame(); puffin::GlobalProfiler::lock().new_frame();
crate::profile_scope!("frame"); crate::profile_scope!("frame");
let mut running = self.running.write();
let GlowWinitRunning { let GlowWinitRunning {
gl_window, glutin_ctx: gl_window,
gl, gl,
app, app,
integration, integration,
painter, painter,
} = running; } = running.as_mut().unwrap();
let mut window_map = HashMap::default(); let mut window_map = HashMap::default();
for window in gl_window.windows.iter() { for (id, window) in gl_window.read().windows.iter() {
if let Some(win) = &window.window { if let Some(win) = &window.read().window {
window_map.insert(window.window_id, win.id()); window_map.insert(*id, win.read().id());
} }
} }
@@ -1039,8 +1087,10 @@ mod glow_integration {
let control_flow; let control_flow;
{ {
// let window = gl_window.window(window_index); // let window = gl_window.window(window_index);
let win: Option<&mut Window> = gl_window.windows.get_mut(window_index); let win = gl_window.read().windows.get(&viewport_id).cloned();
let win = win.unwrap(); let win = win.unwrap();
{
let mut gl_window = gl_window.write();
gl_window.current_gl_context = Some( gl_window.current_gl_context = Some(
gl_window gl_window
.current_gl_context .current_gl_context
@@ -1048,20 +1098,34 @@ mod glow_integration {
.unwrap() .unwrap()
.make_not_current() .make_not_current()
.unwrap() .unwrap()
.make_current(win.gl_surface.as_ref().unwrap()) .make_current(win.read().gl_surface.as_ref().unwrap())
.unwrap(), .unwrap(),
); );
};
let screen_size_in_pixels: [u32; 2] = let screen_size_in_pixels: [u32; 2] = win
win.window.as_ref().unwrap().inner_size().into(); .read()
.window
.as_ref()
.unwrap()
.read()
.inner_size()
.into();
win.window.as_mut().unwrap().set_transparent(true); win.write()
.window
.as_ref()
.unwrap()
.read()
.set_transparent(true);
egui_glow::painter::clear( egui_glow::painter::clear(
gl, gl,
screen_size_in_pixels, screen_size_in_pixels,
app.clear_color(&integration.egui_ctx.style().visuals), app.clear_color(&integration.read().egui_ctx.style().visuals),
); );
{
let win = &mut *win.write();
egui::FullOutput { egui::FullOutput {
platform_output, platform_output,
repaint_after, repaint_after,
@@ -1069,33 +1133,35 @@ mod glow_integration {
shapes, shapes,
viewports, viewports,
viewport_commands, viewport_commands,
} = integration.update( } = integration.write().update(
app.as_mut(), app.as_mut(),
win.window.as_ref().unwrap(), &win.window.as_ref().unwrap().read(),
win.egui_winit.as_mut().unwrap(), win.egui_winit.as_mut().unwrap(),
win.render.clone(), win.render.clone(),
win.window_id, win.window_id,
win.parent_id, win.parent_id,
); );
integration.handle_platform_output( integration.write().handle_platform_output(
win.window.as_ref().unwrap(), &win.window.as_ref().unwrap().read(),
platform_output, platform_output,
win.egui_winit.as_mut().unwrap(), win.egui_winit.as_mut().unwrap(),
); );
}
let clipped_primitives = { let clipped_primitives = {
crate::profile_scope!("tessellate"); crate::profile_scope!("tessellate");
integration.egui_ctx.tessellate(shapes) integration.read().egui_ctx.tessellate(shapes)
}; };
painter.paint_and_update_textures( painter.paint_and_update_textures(
screen_size_in_pixels, screen_size_in_pixels,
integration.egui_ctx.pixels_per_point(), integration.read().egui_ctx.pixels_per_point(),
&clipped_primitives, &clipped_primitives,
&textures_delta, &textures_delta,
); );
let mut integration = integration.write();
{
let screenshot_requested = let screenshot_requested =
&mut integration.frame.output.screenshot_requested; &mut integration.frame.output.screenshot_requested;
@@ -1105,22 +1171,29 @@ mod glow_integration {
integration.frame.screenshot.set(Some(screenshot)); integration.frame.screenshot.set(Some(screenshot));
} }
integration.post_rendering(app.as_mut(), win.window.as_ref().unwrap()); integration.post_rendering(
app.as_mut(),
{ &win.read().window.as_ref().unwrap().read(),
crate::profile_scope!("swap_buffers");
let _ =
win.gl_surface
.as_ref()
.expect("failed to get surface to swap buffers")
.swap_buffers(
gl_window.current_gl_context.as_ref().expect(
"failed to get current context to swap buffers",
),
); );
} }
integration.post_present(win.window.as_ref().unwrap()); {
crate::profile_scope!("swap_buffers");
let _ = win
.read()
.gl_surface
.as_ref()
.expect("failed to get surface to swap buffers")
.swap_buffers(
gl_window
.read()
.current_gl_context
.as_ref()
.expect("failed to get current context to swap buffers"),
);
}
integration.post_present(&win.read().window.as_ref().unwrap().read());
#[cfg(feature = "__screenshot")] #[cfg(feature = "__screenshot")]
// give it time to settle: // give it time to settle:
@@ -1173,9 +1246,10 @@ mod glow_integration {
.collect::<Vec<EventResult>>() .collect::<Vec<EventResult>>()
}; };
integration.maybe_autosave(app.as_mut(), win.window.as_ref().unwrap()); integration
.maybe_autosave(app.as_mut(), &win.read().window.as_ref().unwrap().read());
if win.window.as_ref().unwrap().is_minimized() == Some(true) { if win.read().window.as_ref().unwrap().read().is_minimized() == Some(true) {
// On Mac, a minimized Window uses up all CPU: // On Mac, a minimized Window uses up all CPU:
// https://github.com/emilk/egui/issues/325 // https://github.com/emilk/egui/issues/325
crate::profile_scope!("bg_sleep"); crate::profile_scope!("bg_sleep");
@@ -1187,11 +1261,11 @@ mod glow_integration {
let mut active_viewports_ids = vec![0]; let mut active_viewports_ids = vec![0];
viewports.retain_mut(|(id, _, builder, render)| { viewports.retain_mut(|(id, _, builder, render)| {
for w in gl_window.windows.iter_mut() { if let Some(w) = gl_window.read().windows.get(id) {
if w.window_id == *id { let mut w = w.write();
if w.builder != *builder { if w.builder != *builder {
if let Some(window) = &mut w.window { if let Some(window) = &mut w.window {
if let Ok(pos) = window.outer_position() { if let Ok(pos) = window.read().outer_position() {
builder.position = Some((pos.x, pos.y)); builder.position = Some((pos.x, pos.y));
} }
} }
@@ -1202,14 +1276,16 @@ mod glow_integration {
w.parent_id = *id; w.parent_id = *id;
} }
active_viewports_ids.push(*id); active_viewports_ids.push(*id);
return false; false
} } else {
}
true true
}
}); });
for (id, parent, builder, render) in viewports { for (id, parent, builder, render) in viewports {
gl_window.windows.push(Window { gl_window.write().windows.insert(
id,
Arc::new(RwLock::new(Window {
builder, builder,
gl_surface: None, gl_surface: None,
window: None, window: None,
@@ -1217,19 +1293,21 @@ mod glow_integration {
egui_winit: None, egui_winit: None,
render: render.clone(), render: render.clone(),
parent_id: parent, parent_id: parent,
}); })),
);
active_viewports_ids.push(id); active_viewports_ids.push(id);
} }
// TODO Make this more efficient
for (id, command) in viewport_commands { for (id, command) in viewport_commands {
for window in gl_window.windows.iter() { if let Some(window) = gl_window.read().windows.get(&id) {
if window.window_id == id { let window = window.read();
if let Some(win) = &window.window { if let Some(win) = &window.window {
let win = win.read();
match command { match command {
egui::window::ViewportCommand::Drag => { egui::window::ViewportCommand::Drag => {
// if this is not checked on x11 the input will be permanently taken until the app is killed! // if this is not checked on x11 the input will be permanently taken until the app is killed!
if let Some(focus) = self.is_focused { if let Some(focus) = self.is_focused.read().clone() {
if focus == id { if focus == id {
win.drag_window(); win.drag_window();
} }
@@ -1238,68 +1316,34 @@ mod glow_integration {
egui::window::ViewportCommand::InnerSize(width, height) => { egui::window::ViewportCommand::InnerSize(width, height) => {
win.set_inner_size(PhysicalSize::new(width, height)); win.set_inner_size(PhysicalSize::new(width, height));
} }
egui::window::ViewportCommand::Resize( egui::window::ViewportCommand::Resize(top, bottom, right, left) => {
top, win.drag_resize_window(match (top, bottom, right, left) {
bottom, (true, false, false, false) => ResizeDirection::North,
right, (false, true, false, false) => ResizeDirection::South,
left, (false, false, true, false) => ResizeDirection::East,
) => { (false, false, false, true) => ResizeDirection::West,
win.drag_resize_window( (true, false, true, false) => ResizeDirection::NorthEast,
match (top, bottom, right, left) { (false, true, true, false) => ResizeDirection::SouthEast,
(true, false, false, false) => { (true, false, false, true) => ResizeDirection::NorthWest,
ResizeDirection::North (false, true, false, true) => ResizeDirection::SouthWest,
}
(false, true, false, false) => {
ResizeDirection::South
}
(false, false, true, false) => {
ResizeDirection::East
}
(false, false, false, true) => {
ResizeDirection::West
}
(true, false, true, false) => {
ResizeDirection::NorthEast
}
(false, true, true, false) => {
ResizeDirection::SouthEast
}
(true, false, false, true) => {
ResizeDirection::NorthWest
}
(false, true, false, true) => {
ResizeDirection::SouthWest
}
_ => ResizeDirection::East, _ => ResizeDirection::East,
}, });
);
} }
} }
} }
break;
}
} }
} }
gl_window gl_window
.write()
.windows .windows
.retain(|w| active_viewports_ids.contains(&w.window_id)); .retain(|id, _| active_viewports_ids.contains(id));
gl_window gl_window
.write()
.window_maps .window_maps
.retain(|_, id| active_viewports_ids.contains(id)); .retain(|_, id| active_viewports_ids.contains(id));
control_flow control_flow
};
let mut events = vec![EventResult::Wait];
for event in windows_indexes
.into_iter()
.map(|window_index| inner(window_index))
{
events.extend(event)
}
events
} else { } else {
vec![EventResult::Wait] vec![EventResult::Wait]
} }
@@ -1315,33 +1359,55 @@ mod glow_integration {
// first resume event. // first resume event.
// we can actually move this outside of event loop. // we can actually move this outside of event loop.
// and just run the on_resume fn of gl_window // and just run the on_resume fn of gl_window
if self.running.is_none() { if self.running.read().is_none() {
self.init_run_state(event_loop)?; self.init_run_state(event_loop)?;
} else { } else {
// not the first resume event. create whatever you need. // not the first resume event. create whatever you need.
self.running self.running
.write()
.as_mut() .as_mut()
.unwrap() .unwrap()
.gl_window .glutin_ctx
.write()
.on_resume(event_loop)?; .on_resume(event_loop)?;
} }
EventResult::RepaintNow(self.running.as_ref().unwrap().gl_window.window(0).id()) EventResult::RepaintNow(
self.running
.read()
.as_ref()
.unwrap()
.glutin_ctx
.read()
.window(0)
.read()
.window
.as_ref()
.unwrap()
.read()
.id(),
)
} }
winit::event::Event::Suspended => { winit::event::Event::Suspended => {
self.running.as_mut().unwrap().gl_window.on_suspend()?; self.running
.write()
.as_mut()
.unwrap()
.glutin_ctx
.write()
.on_suspend()?;
EventResult::Wait EventResult::Wait
} }
winit::event::Event::MainEventsCleared => { winit::event::Event::MainEventsCleared => {
if let Some(running) = self.running.as_mut() { if let Some(running) = self.running.read().as_ref() {
let _ = running.gl_window.on_resume(event_loop); let _ = running.glutin_ctx.write().on_resume(event_loop);
} }
EventResult::Wait EventResult::Wait
} }
winit::event::Event::WindowEvent { event, window_id } => { winit::event::Event::WindowEvent { event, window_id } => {
if let Some(running) = &mut self.running { if let Some(running) = self.running.write().as_mut() {
// On Windows, if a window is resized by the user, it should repaint synchronously, inside the // On Windows, if a window is resized by the user, it should repaint synchronously, inside the
// event handler. // event handler.
// //
@@ -1359,8 +1425,15 @@ mod glow_integration {
match &event { match &event {
winit::event::WindowEvent::Focused(new_focused) => { winit::event::WindowEvent::Focused(new_focused) => {
self.is_focused = new_focused *self.is_focused.write() = new_focused
.then(|| running.gl_window.window_maps.get(window_id).cloned()) .then(|| {
running
.glutin_ctx
.write()
.window_maps
.get(window_id)
.cloned()
})
.flatten(); .flatten();
} }
winit::event::WindowEvent::Resized(physical_size) => { winit::event::WindowEvent::Resized(physical_size) => {
@@ -1369,9 +1442,10 @@ mod glow_integration {
// Resize with 0 width and height is used by winit to signal a minimize event on Windows. // Resize with 0 width and height is used by winit to signal a minimize event on Windows.
// See: https://github.com/rust-windowing/winit/issues/208 // See: https://github.com/rust-windowing/winit/issues/208
// This solves an issue where the app would panic when minimizing on Windows. // This solves an issue where the app would panic when minimizing on Windows.
let glutin_ctx = &mut *running.glutin_ctx.write();
if physical_size.width > 0 && physical_size.height > 0 { if physical_size.width > 0 && physical_size.height > 0 {
if let Some(id) = running.gl_window.window_maps.get(window_id) { if let Some(id) = glutin_ctx.window_maps.get(window_id) {
running.gl_window.resize(*id, *physical_size); glutin_ctx.resize(*id, *physical_size);
} }
} }
} }
@@ -1379,20 +1453,23 @@ mod glow_integration {
new_inner_size, new_inner_size,
.. ..
} => { } => {
let glutin_ctx = &mut *running.glutin_ctx.write();
repaint_asap = true; repaint_asap = true;
if let Some(id) = running.gl_window.window_maps.get(window_id) { if let Some(id) = glutin_ctx.window_maps.get(window_id) {
running.gl_window.resize(*id, **new_inner_size); glutin_ctx.resize(*id, **new_inner_size);
} }
} }
winit::event::WindowEvent::CloseRequested winit::event::WindowEvent::CloseRequested
if running if running
.gl_window .glutin_ctx
.write()
.windows .windows
.iter() .iter()
.flat_map(|window| { .flat_map(|(_, window)| {
if let Some(win) = &window.window { if let Some(win) = window.read().window.as_ref() {
let win = win.read();
if win.id() == *window_id { if win.id() == *window_id {
Some(window.window_id) Some(window.read().window_id)
} else { } else {
None None
} }
@@ -1403,7 +1480,7 @@ mod glow_integration {
.flat_map(|id| if id == 0 { Some(()) } else { None }) .flat_map(|id| if id == 0 { Some(()) } else { None })
.count() .count()
== 1 == 1
&& running.integration.should_close() => && running.integration.read().should_close() =>
{ {
log::debug!("Received WindowEvent::CloseRequested"); log::debug!("Received WindowEvent::CloseRequested");
return Ok(EventResult::Exit); return Ok(EventResult::Exit);
@@ -1412,24 +1489,32 @@ mod glow_integration {
} }
let event_response = 'res: { let event_response = 'res: {
for window in running.gl_window.windows.iter_mut() { let glutin_ctx = running.glutin_ctx.read();
if window.window.as_ref().unwrap().id() == *window_id { if let Some(viewport_id) =
break 'res running.integration.on_event( glutin_ctx.window_maps.get(window_id).cloned()
{
if let Some(viewport) =
glutin_ctx.windows.get(&viewport_id).cloned()
{
let viewport = &mut *viewport.write();
break 'res running.integration.write().on_event(
running.app.as_mut(), running.app.as_mut(),
event, event,
window_id, window_id,
window.egui_winit.as_mut().unwrap(), viewport.egui_winit.as_mut().unwrap(),
window.window_id, viewport.window_id,
); );
} }
} }
EventResponse { EventResponse {
consumed: false, consumed: false,
repaint: false, repaint: false,
} }
}; };
if running.integration.should_close() { if running.integration.read().should_close() {
EventResult::Exit EventResult::Exit
} else if event_response.repaint { } else if event_response.repaint {
if repaint_asap { if repaint_asap {
@@ -1448,20 +1533,21 @@ mod glow_integration {
winit::event::Event::UserEvent(UserEvent::AccessKitActionRequest( winit::event::Event::UserEvent(UserEvent::AccessKitActionRequest(
accesskit_winit::ActionRequestEvent { request, window_id }, accesskit_winit::ActionRequestEvent { request, window_id },
)) => { )) => {
if let Some(running) = &mut self.running { if let Some(running) = self.running.read().as_ref() {
for window in running.gl_window.windows.iter_mut() { let glutin_ctx = running.glutin_ctx.read();
if window.window.as_ref().unwrap().id() == *window_id { if let Some(viewport_id) = glutin_ctx.window_maps.get(window_id).cloned() {
running.integration.on_accesskit_action_request( if let Some(viewport) = glutin_ctx.windows.get(&viewport_id).cloned() {
let mut viewport = viewport.write();
running.integration.write().on_accesskit_action_request(
request.clone(), request.clone(),
window_id, window_id,
window.egui_winit.as_mut().unwrap(), viewport.egui_winit.as_mut().unwrap(),
); )
break;
} }
} }
// As a form of user input, accessibility actions should // As a form of user input, accessibility actions should
// lead to a repaint. // lead to a repaint.
EventResult::RepaintNext(running.gl_window.window(0).id()) EventResult::RepaintNext(*window_id)
} else { } else {
EventResult::Wait EventResult::Wait
} }
@@ -1726,16 +1812,21 @@ mod wgpu_integration {
self.is_focused self.is_focused
} }
fn integration(&self) -> Option<&EpiIntegration> { fn integration(&self) -> Option<Arc<RwLock<EpiIntegration>>> {
self.running.as_ref().map(|r| &r.integration) todo!()
// self.running.as_ref().map(|r| r.integration)
} }
fn window(&self, window_id: winit::window::WindowId) -> Option<&winit::window::Window> { fn window(
self.running &self,
.as_ref() window_id: winit::window::WindowId,
.and_then(|r| r.windows_id.get(&window_id).map(|id| r.windows.get(id))) ) -> Option<Arc<RwLock<winit::window::Window>>> {
.flatten() todo!()
.and_then(|w| w.0.as_ref()) // self.running
// .as_ref()
// .and_then(|r| r.windows_id.get(&window_id).map(|id| r.windows.get(id)))
// .flatten()
// .and_then(|w| w.0.as_ref())
} }
fn get_window_winit_id(&self, id: u64) -> Option<winit::window::WindowId> { fn get_window_winit_id(&self, id: u64) -> Option<winit::window::WindowId> {