diff --git a/crates/eframe/src/native/glow_integration.rs b/crates/eframe/src/native/glow_integration.rs index 476b1bdd466..fcea2a44c52 100644 --- a/crates/eframe/src/native/glow_integration.rs +++ b/crates/eframe/src/native/glow_integration.rs @@ -84,8 +84,6 @@ struct GlowWinitRunning<'app> { /// The setup is divided between the `new` fn and `on_resume` fn. we can just assume that `on_resume` is a continuation of /// `new` fn on all platforms. only on android, do we get multiple resumed events because app can be suspended. struct GlutinWindowContext { - egui_ctx: egui::Context, - swap_interval: glutin::surface::SwapInterval, gl_config: glutin::config::Config, @@ -163,7 +161,7 @@ impl<'app> GlowWinitApp<'app> { }; // Creates the window - must come before we create our glow context - glutin_window_context.initialize_window(ViewportId::ROOT, event_loop)?; + glutin_window_context.initialize_window(egui_ctx, ViewportId::ROOT, event_loop)?; { let viewport = &glutin_window_context.viewports[&ViewportId::ROOT]; @@ -400,7 +398,7 @@ impl<'app> WinitApp for GlowWinitApp<'app> { running .glutin .borrow_mut() - .initialize_all_windows(event_loop); + .initialize_all_windows(&running.integration.egui_ctx, event_loop); running } else { // First resume event. Create our root window etc. @@ -504,38 +502,49 @@ impl<'app> GlowWinitRunning<'app> { let mut frame_timer = crate::stopwatch::Stopwatch::new(); frame_timer.start(); - { - let glutin = self.glutin.borrow(); - let viewport = &glutin.viewports[&viewport_id]; - let is_immediate = viewport.viewport_ui_cb.is_none(); - if is_immediate && viewport_id != ViewportId::ROOT { - // This will only happen if this is an immediate viewport. - // That means that the viewport cannot be rendered by itself and needs his parent to be rendered. - if let Some(parent_viewport) = glutin.viewports.get(&viewport.ids.parent) { - if let Some(window) = parent_viewport.window.as_ref() { - return Ok(EventResult::RepaintNext(window.id())); + let (raw_input, viewport_ui_cb) = { + let mut glutin = self.glutin.borrow_mut(); + + if viewport_id != ViewportId::ROOT { + let Some(viewport) = glutin.viewports.get(&viewport_id) else { + return Ok(EventResult::Wait); + }; + + let is_immediate = viewport.viewport_ui_cb.is_none(); + if is_immediate { + // This will only happen if this is an immediate viewport. + // That means that the viewport cannot be rendered by itself and needs his parent to be rendered. + if let Some(parent_viewport) = glutin.viewports.get(&viewport.ids.parent) { + if let Some(window) = parent_viewport.window.as_ref() { + return Ok(EventResult::RepaintNow(window.id())); + } } + return Ok(EventResult::Wait); } - return Ok(EventResult::Wait); } - } - let (raw_input, viewport_ui_cb) = { - let mut glutin = self.glutin.borrow_mut(); - let egui_ctx = glutin.egui_ctx.clone(); let Some(viewport) = glutin.viewports.get_mut(&viewport_id) else { return Ok(EventResult::Wait); }; - let Some(window) = viewport.window.as_ref() else { + + let Viewport { + viewport_ui_cb, + window, + egui_winit, + info, + .. + } = viewport; + + let Some(window) = window.as_ref() else { return Ok(EventResult::Wait); }; - egui_winit::update_viewport_info(&mut viewport.info, &egui_ctx, window, false); + egui_winit::update_viewport_info(info, &self.integration.egui_ctx, window, false); - let Some(egui_winit) = viewport.egui_winit.as_mut() else { + let Some(egui_winit) = egui_winit.as_mut() else { return Ok(EventResult::Wait); }; let mut raw_input = egui_winit.take_egui_input(window); - let viewport_ui_cb = viewport.viewport_ui_cb.clone(); + let viewport_ui_cb = viewport_ui_cb.clone(); self.integration.pre_update(); @@ -630,11 +639,15 @@ impl<'app> GlowWinitRunning<'app> { }; viewport.info.events.clear(); // they should have been processed - let window = viewport.window.clone().unwrap(); - let gl_surface = viewport.gl_surface.as_ref().unwrap(); - let egui_winit = viewport.egui_winit.as_mut().unwrap(); + let (Some(egui_winit), Some(window), Some(gl_surface)) = ( + viewport.egui_winit.as_mut(), + &viewport.window.clone(), + &viewport.gl_surface, + ) else { + return Ok(EventResult::Wait); + }; - egui_winit.handle_platform_output(&window, platform_output); + egui_winit.handle_platform_output(window, platform_output); let clipped_primitives = integration.egui_ctx.tessellate(shapes, pixels_per_point); @@ -691,7 +704,7 @@ impl<'app> GlowWinitRunning<'app> { } } - integration.post_rendering(&window); + integration.post_rendering(window); } { @@ -716,11 +729,11 @@ impl<'app> GlowWinitRunning<'app> { } } - glutin.handle_viewport_output(event_loop, &integration.egui_ctx, &viewport_output); + glutin.handle_viewport_output(&integration.egui_ctx, event_loop, &viewport_output); integration.report_frame_time(frame_timer.total_time_sec()); // don't count auto-save time as part of regular frame time - integration.maybe_autosave(app.as_mut(), Some(&window)); + integration.maybe_autosave(app.as_mut(), Some(window)); if window.is_minimized() == Some(true) { // On Mac, a minimized Window uses up all CPU: @@ -1046,7 +1059,6 @@ impl GlutinWindowContext { // https://github.com/emilk/egui/pull/2541#issuecomment-1370767582 let mut slf = Self { - egui_ctx: egui_ctx.clone(), swap_interval, gl_config, current_gl_context: None, @@ -1058,7 +1070,7 @@ impl GlutinWindowContext { focused_viewport: Some(ViewportId::ROOT), }; - slf.initialize_window(ViewportId::ROOT, event_loop)?; + slf.initialize_window(egui_ctx, ViewportId::ROOT, event_loop)?; Ok(slf) } @@ -1066,13 +1078,13 @@ impl GlutinWindowContext { /// Create a surface, window, and winit integration for all viewports lacking any of that. /// /// Errors will be logged. - fn initialize_all_windows(&mut self, event_loop: &ActiveEventLoop) { + fn initialize_all_windows(&mut self, egui_ctx: &egui::Context, event_loop: &ActiveEventLoop) { crate::profile_function!(); let viewports: Vec = self.viewports.keys().copied().collect(); for viewport_id in viewports { - if let Err(err) = self.initialize_window(viewport_id, event_loop) { + if let Err(err) = self.initialize_window(egui_ctx, viewport_id, event_loop) { log::error!("Failed to initialize a window for viewport {viewport_id:?}: {err}"); } } @@ -1082,6 +1094,7 @@ impl GlutinWindowContext { #[allow(unsafe_code)] pub(crate) fn initialize_window( &mut self, + egui_ctx: &egui::Context, viewport_id: ViewportId, event_loop: &ActiveEventLoop, ) -> Result { @@ -1097,7 +1110,7 @@ impl GlutinWindowContext { } else { log::debug!("Creating a window for viewport {viewport_id:?}"); let window_attributes = egui_winit::create_winit_window_attributes( - &self.egui_ctx, + egui_ctx, event_loop, viewport.builder.clone(), ); @@ -1108,20 +1121,16 @@ impl GlutinWindowContext { } let window = glutin_winit::finalize_window(event_loop, window_attributes, &self.gl_config)?; - egui_winit::apply_viewport_builder_to_window( - &self.egui_ctx, - &window, - &viewport.builder, - ); + egui_winit::apply_viewport_builder_to_window(egui_ctx, &window, &viewport.builder); - egui_winit::update_viewport_info(&mut viewport.info, &self.egui_ctx, &window, true); + egui_winit::update_viewport_info(&mut viewport.info, egui_ctx, &window, true); viewport.window.insert(Arc::new(window)) }; viewport.egui_winit.get_or_insert_with(|| { log::debug!("Initializing egui_winit for viewport {viewport_id:?}"); egui_winit::State::new( - self.egui_ctx.clone(), + (*egui_ctx).clone(), viewport_id, event_loop, Some(window.scale_factor() as f32), @@ -1261,8 +1270,8 @@ impl GlutinWindowContext { fn handle_viewport_output( &mut self, - event_loop: &ActiveEventLoop, egui_ctx: &egui::Context, + event_loop: &ActiveEventLoop, viewport_output: &ViewportIdMap, ) { crate::profile_function!(); @@ -1313,7 +1322,7 @@ impl GlutinWindowContext { } // Create windows for any new viewports: - self.initialize_all_windows(event_loop); + self.initialize_all_windows(egui_ctx, event_loop); self.remove_viewports_not_in(viewport_output); } @@ -1412,7 +1421,7 @@ fn render_immediate_viewport( ); let ret = event_loop_context::with_current_event_loop(|event_loop| { - glutin.initialize_window(viewport_id, event_loop) + glutin.initialize_window(egui_ctx, viewport_id, event_loop) }); if let Some(Err(err)) = ret { @@ -1478,7 +1487,7 @@ fn render_immediate_viewport( viewport.info.events.clear(); // they should have been processed let (Some(egui_winit), Some(window), Some(gl_surface)) = ( - &mut viewport.egui_winit, + viewport.egui_winit.as_mut(), &viewport.window, &viewport.gl_surface, ) else { @@ -1522,7 +1531,7 @@ fn render_immediate_viewport( egui_winit.handle_platform_output(window, platform_output); event_loop_context::with_current_event_loop(|event_loop| { - glutin.handle_viewport_output(event_loop, egui_ctx, &viewport_output); + glutin.handle_viewport_output(egui_ctx, event_loop, &viewport_output); }); } diff --git a/crates/eframe/src/native/wgpu_integration.rs b/crates/eframe/src/native/wgpu_integration.rs index 997383f85c3..f5625a0cbbf 100644 --- a/crates/eframe/src/native/wgpu_integration.rs +++ b/crates/eframe/src/native/wgpu_integration.rs @@ -65,7 +65,6 @@ struct WgpuWinitRunning<'app> { /// /// Wrapped in an `Rc>` so it can be re-entrantly shared via a weak-pointer. pub struct SharedState { - egui_ctx: egui::Context, viewports: Viewports, painter: egui_wgpu::winit::Painter, viewport_from_window: HashMap, @@ -134,8 +133,8 @@ impl<'app> WgpuWinitApp<'app> { for viewport in viewports.values_mut() { viewport.initialize_window( - event_loop, &running.integration.egui_ctx, + event_loop, viewport_from_window, painter, ); @@ -145,7 +144,6 @@ impl<'app> WgpuWinitApp<'app> { #[cfg(target_os = "android")] fn recreate_window(&self, event_loop: &ActiveEventLoop, running: &WgpuWinitRunning<'app>) { let SharedState { - egui_ctx, viewports, viewport_from_window, painter, @@ -160,7 +158,12 @@ impl<'app> WgpuWinitApp<'app> { None, painter, ) - .initialize_window(event_loop, egui_ctx, viewport_from_window, painter); + .initialize_window( + &running.integration.egui_ctx, + event_loop, + viewport_from_window, + painter, + ); } #[cfg(target_os = "android")] @@ -294,7 +297,6 @@ impl<'app> WgpuWinitApp<'app> { ); let shared = Rc::new(RefCell::new(SharedState { - egui_ctx, viewport_from_window, viewports, painter, @@ -308,7 +310,7 @@ impl<'app> WgpuWinitApp<'app> { egui::Context::set_immediate_viewport_renderer(move |_egui_ctx, immediate_viewport| { if let Some(shared) = shared.upgrade() { - render_immediate_viewport(beginning, &shared, immediate_viewport); + render_immediate_viewport(&egui_ctx, beginning, &shared, immediate_viewport); } else { log::warn!("render_sync_callback called after window closed"); } @@ -544,12 +546,13 @@ impl<'app> WgpuWinitRunning<'app> { return Ok(EventResult::Wait); }; - if viewport.viewport_ui_cb.is_none() { + let is_immediate = viewport.viewport_ui_cb.is_none(); + if is_immediate { // This will only happen if this is an immediate viewport. // That means that the viewport cannot be rendered by itself and needs his parent to be rendered. - if let Some(viewport) = viewports.get(&viewport.ids.parent) { - if let Some(window) = viewport.window.as_ref() { - return Ok(EventResult::RepaintNext(window.id())); + if let Some(parent_viewport) = viewports.get(&viewport.ids.parent) { + if let Some(window) = parent_viewport.window.as_ref() { + return Ok(EventResult::RepaintNow(window.id())); } } return Ok(EventResult::Wait); @@ -607,7 +610,6 @@ impl<'app> WgpuWinitRunning<'app> { let mut shared_mut = shared.borrow_mut(); let SharedState { - egui_ctx, viewports, painter, viewport_from_window, @@ -641,7 +643,7 @@ impl<'app> WgpuWinitRunning<'app> { egui_winit.handle_platform_output(window, platform_output); - let clipped_primitives = egui_ctx.tessellate(shapes, pixels_per_point); + let clipped_primitives = integration.egui_ctx.tessellate(shapes, pixels_per_point); let screenshot_requested = viewport .actions_requested @@ -650,7 +652,7 @@ impl<'app> WgpuWinitRunning<'app> { let (vsync_secs, screenshot) = painter.paint_and_update_textures( viewport_id, pixels_per_point, - app.clear_color(&egui_ctx.style().visuals), + app.clear_color(&integration.egui_ctx.style().visuals), &clipped_primitives, &textures_delta, screenshot_requested, @@ -692,8 +694,6 @@ impl<'app> WgpuWinitRunning<'app> { integration.post_rendering(window); - let active_viewports_ids: ViewportIdSet = viewport_output.keys().copied().collect(); - handle_viewport_output( &integration.egui_ctx, &viewport_output, @@ -702,11 +702,6 @@ impl<'app> WgpuWinitRunning<'app> { viewport_from_window, ); - // Prune dead viewports: - viewports.retain(|id, _| active_viewports_ids.contains(id)); - viewport_from_window.retain(|_, id| active_viewports_ids.contains(id)); - painter.gc_viewports(&active_viewports_ids); - let window = viewport_from_window .get(&window_id) .and_then(|id| viewports.get(id)) @@ -838,8 +833,8 @@ impl Viewport { /// Create winit window, if needed. fn initialize_window( &mut self, - event_loop: &ActiveEventLoop, egui_ctx: &egui::Context, + event_loop: &ActiveEventLoop, windows_id: &mut HashMap, painter: &mut egui_wgpu::winit::Painter, ) { @@ -905,6 +900,7 @@ fn create_window( } fn render_immediate_viewport( + egui_ctx: &egui::Context, beginning: Instant, shared: &RefCell, immediate_viewport: ImmediateViewport<'_>, @@ -919,7 +915,6 @@ fn render_immediate_viewport( let input = { let SharedState { - egui_ctx, viewports, painter, viewport_from_window, @@ -936,7 +931,7 @@ fn render_immediate_viewport( ); if viewport.window.is_none() { event_loop_context::with_current_event_loop(|event_loop| { - viewport.initialize_window(event_loop, egui_ctx, viewport_from_window, painter); + viewport.initialize_window(egui_ctx, event_loop, viewport_from_window, painter); }); } @@ -954,8 +949,6 @@ fn render_immediate_viewport( input }; - let egui_ctx = shared.borrow().egui_ctx.clone(); - // ------------------------------------------ // Run the user code, which could re-entrantly call this function again (!). @@ -1011,7 +1004,7 @@ fn render_immediate_viewport( egui_winit.handle_platform_output(window, platform_output); handle_viewport_output( - &egui_ctx, + egui_ctx, &viewport_output, viewports, painter,