From aad7ed23d2ed391c557e2af08ad613299c17d6b3 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Tue, 14 Nov 2023 07:58:04 +0100 Subject: [PATCH] "Final" touch-ups on wgpu integration --- crates/eframe/src/native/run.rs | 341 ++++++++++------------ crates/egui/src/context.rs | 16 +- crates/egui_demo_lib/benches/benchmark.rs | 5 +- crates/egui_demo_lib/src/lib.rs | 6 +- crates/egui_glow/src/winit.rs | 10 +- 5 files changed, 171 insertions(+), 207 deletions(-) diff --git a/crates/eframe/src/native/run.rs b/crates/eframe/src/native/run.rs index 27f2339f4..4e6c8de51 100644 --- a/crates/eframe/src/native/run.rs +++ b/crates/eframe/src/native/run.rs @@ -1,5 +1,9 @@ //! 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. +//! +//! This is also very complex code, and not very pretty. +//! There is a bunch of improvements we could do, +//! like removing a bunch of `unwraps`. use std::{cell::RefCell, rc::Rc, sync::Arc, time::Instant}; @@ -96,8 +100,6 @@ trait WinitApp { fn window_id_from_viewport_id(&self, id: ViewportId) -> Option; - fn viewport_id_from_window_id(&self, id: &WindowId) -> Option; - fn save_and_destroy(&mut self); fn run_ui_and_paint(&mut self, window_id: WindowId) -> EventResult; @@ -492,12 +494,7 @@ mod glow_integration { window_id: WindowId, focused_viewport: Option, ) -> EventResult { - let Some(viewport_id) = self - .glutin - .borrow() - .viewport_maps - .get(&window_id) - .copied() + let Some(viewport_id) = self.glutin.borrow().viewport_from_window.get(&window_id).copied() else { return EventResult::Wait; }; @@ -511,10 +508,10 @@ mod glow_integration { 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() { - // 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. return EventResult::RepaintNext(window.id()); } } @@ -553,6 +550,9 @@ mod glow_integration { .. } = self; + let mut glutin = glutin.borrow_mut(); + let mut painter = painter.borrow_mut(); + let egui::FullOutput { platform_output, textures_delta, @@ -561,7 +561,6 @@ mod glow_integration { viewport_commands, } = full_output; - let mut glutin = glutin.borrow_mut(); let GlutinWindowContext { viewports, current_gl_context, @@ -569,41 +568,36 @@ mod glow_integration { } = &mut *glutin; let viewport = viewports.get_mut(&viewport_id).unwrap(); let window = viewport.window.as_ref().unwrap(); + let gl_surface = viewport.gl_surface.as_ref().unwrap(); + let egui_winit = viewport.egui_winit.as_mut().unwrap(); integration.post_update(app.as_mut(), window); - integration.handle_platform_output( - window, - viewport_id, - platform_output, - viewport.egui_winit.as_mut().unwrap(), - ); - - let clipped_primitives = integration.egui_ctx.tessellate(shapes); - - if let Some(gl_surface) = &viewport.gl_surface { - *current_gl_context = Some( - current_gl_context - .take() - .unwrap() - .make_not_current() - .unwrap() - .make_current(gl_surface) - .unwrap(), - ); - } - - let screen_size_in_pixels: [u32; 2] = window.inner_size().into(); - - painter.borrow().clear( - screen_size_in_pixels, - app.clear_color(&integration.egui_ctx.style().visuals), - ); + integration.handle_platform_output(window, viewport_id, platform_output, egui_winit); let pixels_per_point = integration .egui_ctx .input_for(viewport_id, |i| i.pixels_per_point()); - painter.borrow_mut().paint_and_update_textures( + let clipped_primitives = integration.egui_ctx.tessellate(shapes, pixels_per_point); + + *current_gl_context = Some( + current_gl_context + .take() + .unwrap() + .make_not_current() + .unwrap() + .make_current(gl_surface) + .unwrap(), + ); + + let screen_size_in_pixels: [u32; 2] = window.inner_size().into(); + + painter.clear( + screen_size_in_pixels, + app.clear_color(&integration.egui_ctx.style().visuals), + ); + + painter.paint_and_update_textures( screen_size_in_pixels, pixels_per_point, &clipped_primitives, @@ -612,39 +606,32 @@ mod glow_integration { { let screenshot_requested = &mut integration.frame.output.screenshot_requested; - if *screenshot_requested { *screenshot_requested = false; - let screenshot = painter.borrow().read_screen_rgba(screen_size_in_pixels); + let screenshot = painter.read_screen_rgba(screen_size_in_pixels); integration.frame.screenshot.set(Some(screenshot)); } - - integration.post_rendering(app.as_mut(), viewport.window.as_ref().unwrap()); + integration.post_rendering(app.as_mut(), window); } { crate::profile_scope!("swap_buffers"); - if let Err(err) = viewport - .gl_surface - .as_ref() - .expect("failed to get surface to swap buffers") - .swap_buffers( - current_gl_context - .as_ref() - .expect("failed to get current context to swap buffers"), - ) - { + if let Err(err) = gl_surface.swap_buffers( + current_gl_context + .as_ref() + .expect("failed to get current context to swap buffers"), + ) { log::error!("swap_buffers failed: {err}"); } } - integration.post_present(viewport.window.as_ref().unwrap()); + integration.post_present(window); // give it time to settle: #[cfg(feature = "__screenshot")] if integration.egui_ctx.frame_nr() == 2 { if let Ok(path) = std::env::var("EFRAME_SCREENSHOT_TO") { - save_screeshot_and_exit(&path, painter, screen_size_in_pixels); + save_screeshot_and_exit(&path, &painter, screen_size_in_pixels); } } @@ -682,14 +669,14 @@ mod glow_integration { fn save_screeshot_and_exit( path: &str, - painter: &mut Rc>, + painter: &egui_glow::Painter, screen_size_in_pixels: [u32; 2], ) { assert!( path.ends_with(".png"), "Expected EFRAME_SCREENSHOT_TO to end with '.png', got {path:?}" ); - let screenshot = painter.borrow().read_screen_rgba(screen_size_in_pixels); + let screenshot = painter.read_screen_rgba(screen_size_in_pixels); image::save_buffer( path, screenshot.as_raw(), @@ -742,7 +729,7 @@ mod glow_integration { not_current_gl_context: Option, viewports: ViewportIdMap, - viewport_maps: HashMap, + viewport_from_window: HashMap, window_maps: ViewportIdMap, } @@ -859,10 +846,10 @@ mod glow_integration { }; let not_current_gl_context = Some(gl_context); - let mut viewport_maps = HashMap::default(); + let mut viewport_from_window = HashMap::default(); let mut window_maps = ViewportIdMap::default(); if let Some(window) = &window { - viewport_maps.insert(window.id(), ViewportId::ROOT); + viewport_from_window.insert(window.id(), ViewportId::ROOT); window_maps.insert(ViewportId::ROOT, window.id()); } @@ -890,7 +877,7 @@ mod glow_integration { current_gl_context: None, not_current_gl_context, viewports, - viewport_maps, + viewport_from_window, max_texture_side: None, window_maps, }; @@ -998,7 +985,8 @@ mod glow_integration { viewport.gl_surface = Some(gl_surface); self.current_gl_context = Some(current_gl_context); - self.viewport_maps.insert(window.id(), viewport.ids.this); + self.viewport_from_window + .insert(window.id(), viewport.ids.this); self.window_maps.insert(viewport.ids.this, window.id()); } viewport.window = Some(window); @@ -1102,7 +1090,7 @@ mod glow_integration { // GC old viewports self.viewports .retain(|id, _| active_viewports_ids.contains(id)); - self.viewport_maps + self.viewport_from_window .retain(|_, id| active_viewports_ids.contains(id)); self.window_maps .retain(|id, _| active_viewports_ids.contains(id)); @@ -1479,7 +1467,8 @@ mod glow_integration { let screen_size_in_pixels: [u32; 2] = window.inner_size().into(); - let clipped_primitives = egui_ctx.tessellate(output.shapes); + let pixels_per_point = egui_ctx.input_for(ids.this, |i| i.pixels_per_point()); + let clipped_primitives = egui_ctx.tessellate(output.shapes, pixels_per_point); let mut painter = painter.borrow_mut(); @@ -1507,7 +1496,6 @@ mod glow_integration { let gl = &painter.gl().clone(); egui_glow::painter::clear(gl, screen_size_in_pixels, [0.0, 0.0, 0.0, 0.0]); - let pixels_per_point = egui_ctx.input_for(ids.this, |i| i.pixels_per_point()); painter.paint_and_update_textures( screen_size_in_pixels, pixels_per_point, @@ -1540,7 +1528,9 @@ mod glow_integration { fn is_focused(&self, window_id: WindowId) -> bool { if let Some(focused_viewport) = self.focused_viewport { if let Some(running) = self.running.as_ref() { - if let Some(window_id) = running.glutin.borrow().viewport_maps.get(&window_id) { + if let Some(window_id) = + running.glutin.borrow().viewport_from_window.get(&window_id) + { return focused_viewport == *window_id; } } @@ -1555,7 +1545,7 @@ mod glow_integration { fn window(&self, window_id: WindowId) -> Option> { let running = self.running.as_ref()?; let glutin = running.glutin.borrow(); - let viewport_id = *glutin.viewport_maps.get(&window_id)?; + let viewport_id = *glutin.viewport_from_window.get(&window_id)?; if let Some(viewport) = glutin.viewports.get(&viewport_id) { viewport.window.clone() } else { @@ -1569,12 +1559,6 @@ mod glow_integration { .and_then(|r| r.glutin.borrow().window_maps.get(&id).copied()) } - fn viewport_id_from_window_id(&self, id: &WindowId) -> Option { - self.running - .as_ref() - .and_then(|r| r.glutin.borrow().viewport_maps.get(id).copied()) - } - fn save_and_destroy(&mut self) { if let Some(mut running) = self.running.take() { crate::profile_function!(); @@ -1670,7 +1654,7 @@ mod glow_integration { running .glutin .borrow_mut() - .viewport_maps + .viewport_from_window .get(window_id) .copied() }) @@ -1684,7 +1668,7 @@ mod glow_integration { // This solves an issue where the app would panic when minimizing on Windows. let glutin = &mut *running.glutin.borrow_mut(); if 0 < physical_size.width && 0 < physical_size.height { - if let Some(id) = glutin.viewport_maps.get(window_id) { + if let Some(id) = glutin.viewport_from_window.get(window_id) { glutin.resize(*id, *physical_size); } } @@ -1695,7 +1679,7 @@ mod glow_integration { } => { let glutin = &mut *running.glutin.borrow_mut(); repaint_asap = true; - if let Some(id) = glutin.viewport_maps.get(window_id) { + if let Some(id) = glutin.viewport_from_window.get(window_id) { glutin.resize(*id, **new_inner_size); } } @@ -1703,7 +1687,7 @@ mod glow_integration { if running .glutin .borrow() - .viewport_maps + .viewport_from_window .get(window_id) .map_or(false, |id| *id == ViewportId::ROOT) && running.integration.should_close() => @@ -1716,7 +1700,8 @@ mod glow_integration { let event_response = 'res: { let mut glutin = running.glutin.borrow_mut(); - if let Some(viewport_id) = glutin.viewport_maps.get(window_id).copied() + if let Some(viewport_id) = + glutin.viewport_from_window.get(window_id).copied() { if let Some(viewport) = glutin.viewports.get_mut(&viewport_id) { break 'res running.integration.on_event( @@ -1758,7 +1743,9 @@ mod glow_integration { crate::profile_scope!("on_accesskit_action_request"); let mut glutin = running.glutin.borrow_mut(); - if let Some(viewport_id) = glutin.viewport_maps.get(window_id).copied() { + if let Some(viewport_id) = + glutin.viewport_from_window.get(window_id).copied() + { if let Some(viewport) = glutin.viewports.get_mut(&viewport_id) { viewport .egui_winit @@ -1823,8 +1810,11 @@ mod wgpu_integration { /// `None` for sync viewports. viewport_ui_cb: Option>, - // `window` and `egui_winit` are initialized together. + /// Window surface state that's initialized when the app starts running via a Resumed event + /// and on Android will also be destroyed if the application is paused. window: Option>, + + /// `window` and `egui_winit` are initialized together. egui_winit: Option, } @@ -1837,13 +1827,15 @@ mod wgpu_integration { ) { crate::profile_function!(); - let id = self.ids.this; + let viewport_id = self.ids.this; if let Ok(new_window) = create_winit_window_builder(&self.builder).build(event_loop) { - windows_id.insert(new_window.id(), id); + windows_id.insert(new_window.id(), viewport_id); - if let Err(err) = pollster::block_on(painter.set_window(id, Some(&new_window))) { - log::error!("on set_window: viewport_id {id:?} {err}"); + if let Err(err) = + pollster::block_on(painter.set_window(viewport_id, Some(&new_window))) + { + log::error!("on set_window: viewport_id {viewport_id:?} {err}"); } self.egui_winit = Some(egui_winit::State::new( @@ -1865,7 +1857,7 @@ mod wgpu_integration { pub struct SharedState { viewports: Viewports, painter: egui_wgpu::winit::Painter, - viewport_maps: HashMap, + viewport_from_window: HashMap, } /// State that is initialized when the application is first starts running via @@ -1873,20 +1865,25 @@ mod wgpu_integration { /// initialized once the application has an associated `SurfaceView`. struct WgpuWinitRunning { integration: epi_integration::EpiIntegration, + + /// The users application. app: Box, /// Wrapped in an `Rc>` so it can be re-entrantly shared via a weak-pointer. shared: Rc>, } + struct WgpuWinitApp { repaint_proxy: Arc>>, app_name: String, native_options: epi::NativeOptions, + + /// Set at initialization, then taken and set to `None` in `init_run_state`. app_creator: Option, + + /// Set when we are actually up and running. running: Option, - /// Window surface state that's initialized when the app starts running via a Resumed event - /// and on Android will also be destroyed if the application is paused. focused_viewport: Option, } @@ -1898,6 +1895,7 @@ mod wgpu_integration { app_creator: epi::AppCreator, ) -> Self { crate::profile_function!(); + #[cfg(feature = "__screenshot")] assert!( std::env::var("EFRAME_SCREENSHOT_TO").is_err(), @@ -1922,12 +1920,12 @@ mod wgpu_integration { let SharedState { viewports, painter, - viewport_maps, + viewport_from_window, } = &mut *shared; for viewport in viewports.values_mut() { if viewport.window.is_none() { - viewport.init_window(viewport_maps, painter, event_loop); + viewport.init_window(viewport_from_window, painter, event_loop); } } } @@ -2034,8 +2032,8 @@ mod wgpu_integration { integration.warm_up(app.as_mut(), &window, &mut egui_winit); } - let mut viewport_maps = HashMap::default(); - viewport_maps.insert(window.id(), ViewportId::ROOT); + let mut viewport_from_window = HashMap::default(); + viewport_from_window.insert(window.id(), ViewportId::ROOT); let mut viewports = Viewports::default(); viewports.insert( @@ -2050,7 +2048,7 @@ mod wgpu_integration { ); let shared = Rc::new(RefCell::new(SharedState { - viewport_maps, + viewport_from_window, viewports, painter, })); @@ -2127,22 +2125,18 @@ mod wgpu_integration { } = immediate_viewport; let input = { - let mut shared = shared.borrow_mut(); let SharedState { viewports, painter, - viewport_maps, - } = &mut *shared; + viewport_from_window, + } = &mut *shared.borrow_mut(); let viewport = initialize_or_update_viewport(viewports, ids, builder, None, None); if viewport.window.is_none() { - viewport.init_window(viewport_maps, painter, event_loop); + viewport.init_window(viewport_from_window, painter, event_loop); } - let Some(winit_state) = &mut viewport.egui_winit else { - return; - }; - let Some(window) = &viewport.window else { + let (Some(window), Some(winit_state)) = (&viewport.window, &mut viewport.egui_winit) else { return; }; @@ -2153,7 +2147,8 @@ mod wgpu_integration { // ------------------------------------------ - // Run the user code, which could re-entrantly call this function again (!) + // Run the user code, which could re-entrantly call this function again (!). + // Make sure no locks are held during this call. let output = egui_ctx.run(input, |ctx| { viewport_ui_cb(ctx); }); @@ -2183,7 +2178,7 @@ mod wgpu_integration { } let pixels_per_point = egui_ctx.input_for(ids.this, |i| i.pixels_per_point()); - let clipped_primitives = egui_ctx.tessellate(output.shapes); + let clipped_primitives = egui_ctx.tessellate(output.shapes, pixels_per_point); painter.paint_and_update_textures( ids.this, pixels_per_point, @@ -2204,12 +2199,15 @@ mod wgpu_integration { } fn is_focused(&self, window_id: WindowId) -> bool { - if let Some(focus) = self.focused_viewport { - self.viewport_id_from_window_id(&window_id) - .map_or(false, |i| i == focus) - } else { - false - } + let viewport_id = self.running.as_ref().and_then(|r| { + r.shared + .borrow() + .viewport_from_window + .get(&window_id) + .copied() + }); + + self.focused_viewport.is_some() && self.focused_viewport == viewport_id } fn integration(&self) -> Option<&EpiIntegration> { @@ -2222,7 +2220,7 @@ mod wgpu_integration { .and_then(|r| { let shared = r.shared.borrow(); shared - .viewport_maps + .viewport_from_window .get(&window_id) .and_then(|id| shared.viewports.get(id).map(|v| v.window.clone())) }) @@ -2230,13 +2228,17 @@ mod wgpu_integration { } fn window_id_from_viewport_id(&self, id: ViewportId) -> Option { - self.running.as_ref().and_then(|r| { - r.shared + Some( + self.running + .as_ref()? + .shared .borrow() .viewports - .get(&id) - .and_then(|v| v.window.as_ref().map(|w| w.id())) - }) + .get(&id)? + .window + .as_ref()? + .id(), + ) } fn save_and_destroy(&mut self) { @@ -2295,6 +2297,7 @@ mod wgpu_integration { )?; self.init_run_state(event_loop, storage, window, builder)? }; + EventResult::RepaintNow( running.shared.borrow().viewports[&ViewportId::ROOT] .window @@ -2325,11 +2328,11 @@ mod wgpu_integration { if let Some(running) = &mut self.running { let mut shared_lock = running.shared.borrow_mut(); let SharedState { - viewport_maps, + viewport_from_window, viewports, .. } = &mut *shared_lock; - if let Some(viewport) = viewport_maps + if let Some(viewport) = viewport_from_window .get(window_id) .and_then(|id| viewports.get_mut(id)) { @@ -2347,12 +2350,6 @@ mod wgpu_integration { _ => EventResult::Wait, }) } - - fn viewport_id_from_window_id(&self, id: &WindowId) -> Option { - self.running - .as_ref() - .and_then(|r| r.shared.borrow().viewport_maps.get(id).copied()) - } } impl WgpuWinitRunning { @@ -2391,6 +2388,11 @@ mod wgpu_integration { window_id: WindowId, focused_viewport: Option, ) -> EventResult { + let Some(viewport_id) = self.shared.borrow().viewport_from_window.get(&window_id).copied() + else { + return EventResult::Wait; + }; + #[cfg(feature = "puffin")] puffin::GlobalProfiler::lock().new_frame(); @@ -2406,21 +2408,16 @@ mod wgpu_integration { let mut shared_lock = shared.borrow_mut(); let SharedState { - viewports, - painter, - viewport_maps, + viewports, painter, .. } = &mut *shared_lock; - let Some(viewport_id) = viewport_maps.get(&window_id).copied() else { - return EventResult::Wait; - }; - let Some(viewport) = viewports.get(&viewport_id) else { return EventResult::Wait; }; - // This is used to not render a viewport if is sync if viewport_id != ViewportId::ROOT && viewport.viewport_ui_cb.is_none() { + // 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 EventResult::RepaintNext(window.id()); @@ -2477,22 +2474,19 @@ mod wgpu_integration { let SharedState { viewports, painter, - viewport_maps, + viewport_from_window, } = &mut *shared; - let Some(viewport_id) = viewport_maps.get(&window_id).copied() else { - return EventResult::Wait; - }; - let Some(viewport) = viewports.get_mut(&viewport_id) else { return EventResult::Wait; }; let Viewport { - window, egui_winit, .. - } = viewport; - - let Some(window) = window else { + window: Some(window), + egui_winit: Some(egui_winit), + .. + } = viewport + else { return EventResult::Wait; }; @@ -2502,35 +2496,31 @@ mod wgpu_integration { platform_output, textures_delta, shapes, - viewports: mut out_viewports, + viewports: out_viewports, viewport_commands, } = full_output; - integration.handle_platform_output( - window, - viewport_id, - platform_output, - egui_winit.as_mut().unwrap(), - ); + integration.handle_platform_output(window, viewport_id, platform_output, egui_winit); - let clipped_primitives = integration.egui_ctx.tessellate(shapes); + { + let pixels_per_point = integration + .egui_ctx + .input_for(viewport_id, |i| i.pixels_per_point()); - let screenshot_requested = &mut integration.frame.output.screenshot_requested; + let clipped_primitives = integration.egui_ctx.tessellate(shapes, pixels_per_point); - let pixels_per_point = integration - .egui_ctx - .input_for(viewport_id, |i| i.pixels_per_point()); - - let screenshot = painter.paint_and_update_textures( - viewport_id, - pixels_per_point, - app.clear_color(&integration.egui_ctx.style().visuals), - &clipped_primitives, - &textures_delta, - *screenshot_requested, - ); - *screenshot_requested = false; - integration.frame.screenshot.set(screenshot); + let screenshot_requested = &mut integration.frame.output.screenshot_requested; + let screenshot = painter.paint_and_update_textures( + viewport_id, + pixels_per_point, + app.clear_color(&integration.egui_ctx.style().visuals), + &clipped_primitives, + &textures_delta, + *screenshot_requested, + ); + *screenshot_requested = false; + integration.frame.screenshot.set(screenshot); + } integration.post_rendering(app.as_mut(), window); integration.post_present(window); @@ -2538,24 +2528,6 @@ mod wgpu_integration { let mut active_viewports_ids = ViewportIdSet::default(); active_viewports_ids.insert(ViewportId::ROOT); - // Update exisitng viewports: - out_viewports.retain_mut( - |ViewportOutput { - ids: ViewportIdPair { this, parent }, - viewport_ui_cb, - .. - }| { - if let Some(viewport) = viewports.get_mut(this) { - viewport.viewport_ui_cb = viewport_ui_cb.clone(); - viewport.ids.parent = *parent; - active_viewports_ids.insert(*this); - false - } else { - true - } - }, - ); - // Add new viewports, and update existing ones: for ViewportOutput { ids, @@ -2574,6 +2546,7 @@ mod wgpu_integration { ); } + // Handle viewport commands: for (viewport_id, command) in viewport_commands { if let Some(window) = viewports .get(&viewport_id) @@ -2590,10 +2563,10 @@ mod wgpu_integration { // Prune dead viewports: viewports.retain(|id, _| active_viewports_ids.contains(id)); - viewport_maps.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_maps + let window = viewport_from_window .get(&window_id) .and_then(|id| viewports.get(id)) .and_then(|vp| vp.window.as_ref()); @@ -2629,7 +2602,7 @@ mod wgpu_integration { } = self; let mut shared = shared.borrow_mut(); - let viewport_id = shared.viewport_maps.get(&window_id).copied(); + let viewport_id = shared.viewport_from_window.get(&window_id).copied(); // On Windows, if a window is resized by the user, it should repaint synchronously, inside the // event handler. @@ -2671,7 +2644,7 @@ mod wgpu_integration { if let (Some(width), Some(height), Some(viewport_id)) = ( NonZeroU32::new(new_inner_size.width), NonZeroU32::new(new_inner_size.height), - shared.viewport_maps.get(&window_id).copied(), + shared.viewport_from_window.get(&window_id).copied(), ) { repaint_asap = true; shared.painter.on_window_resized(viewport_id, width, height); diff --git a/crates/egui/src/context.rs b/crates/egui/src/context.rs index 716d8f884..897c46993 100644 --- a/crates/egui/src/context.rs +++ b/crates/egui/src/context.rs @@ -1631,22 +1631,12 @@ impl Context { }) } - /// Tessellate the given shapes into triangle meshes. - /// - /// Will use the `pixels_per_point` of the last viewport for feathering (anti-aliasing). - pub fn tessellate(&self, shapes: Vec) -> Vec { - let last_viewport = self.read(|ctx| ctx.last_viewport); - - // here we expect that we are the only user of context, since frame is ended - let pixels_per_point = self.input_for(last_viewport, |i| i.pixels_per_point()); - - self.tessellate_with_pixels_per_point(shapes, pixels_per_point) - } - /// Tessellate the given shapes into triangle meshes. /// /// `pixels_per_point` is used for feathering (anti-aliasing). - pub fn tessellate_with_pixels_per_point( + /// You can use [`Self::pixels_per_point`] for this, + /// or whatever is appropiate for your viewport. + pub fn tessellate( &self, shapes: Vec, pixels_per_point: f32, diff --git a/crates/egui_demo_lib/benches/benchmark.rs b/crates/egui_demo_lib/benches/benchmark.rs index dcc55ea6e..1cecf3038 100644 --- a/crates/egui_demo_lib/benches/benchmark.rs +++ b/crates/egui_demo_lib/benches/benchmark.rs @@ -9,6 +9,7 @@ pub fn criterion_benchmark(c: &mut Criterion) { { let ctx = egui::Context::default(); let mut demo_windows = egui_demo_lib::DemoWindows::default(); + let pixels_per_point = 1.0; // The most end-to-end benchmark. c.bench_function("demo_with_tessellate__realistic", |b| { @@ -16,7 +17,7 @@ pub fn criterion_benchmark(c: &mut Criterion) { let full_output = ctx.run(RawInput::default(), |ctx| { demo_windows.ui(ctx); }); - ctx.tessellate(full_output.shapes) + ctx.tessellate(full_output.shapes, pixels_per_point) }); }); @@ -32,7 +33,7 @@ pub fn criterion_benchmark(c: &mut Criterion) { demo_windows.ui(ctx); }); c.bench_function("demo_only_tessellate", |b| { - b.iter(|| ctx.tessellate(full_output.shapes.clone())); + b.iter(|| ctx.tessellate(full_output.shapes.clone(), pixels_per_point)); }); } diff --git a/crates/egui_demo_lib/src/lib.rs b/crates/egui_demo_lib/src/lib.rs index 9d7eaa536..4d0fe58d0 100644 --- a/crates/egui_demo_lib/src/lib.rs +++ b/crates/egui_demo_lib/src/lib.rs @@ -71,13 +71,14 @@ fn test_egui_e2e() { let mut demo_windows = crate::DemoWindows::default(); let ctx = egui::Context::default(); let raw_input = egui::RawInput::default(); + let pixels_per_point = 1.0; const NUM_FRAMES: usize = 5; for _ in 0..NUM_FRAMES { let full_output = ctx.run(raw_input.clone(), |ctx| { demo_windows.ui(ctx); }); - let clipped_primitives = ctx.tessellate(full_output.shapes); + let clipped_primitives = ctx.tessellate(full_output.shapes, pixels_per_point); assert!(!clipped_primitives.is_empty()); } } @@ -90,13 +91,14 @@ fn test_egui_zero_window_size() { screen_rect: Some(egui::Rect::from_min_max(egui::Pos2::ZERO, egui::Pos2::ZERO)), ..Default::default() }; + let pixels_per_point = 1.0; const NUM_FRAMES: usize = 5; for _ in 0..NUM_FRAMES { let full_output = ctx.run(raw_input.clone(), |ctx| { demo_windows.ui(ctx); }); - let clipped_primitives = ctx.tessellate(full_output.shapes); + let clipped_primitives = ctx.tessellate(full_output.shapes, pixels_per_point); assert!( clipped_primitives.is_empty(), "There should be nothing to show, has at least one primitive with clip_rect: {:?}", diff --git a/crates/egui_glow/src/winit.rs b/crates/egui_glow/src/winit.rs index 5bbd19adb..e591efdc8 100644 --- a/crates/egui_glow/src/winit.rs +++ b/crates/egui_glow/src/winit.rs @@ -88,13 +88,11 @@ impl EguiGlow { self.painter.set_texture(id, &image_delta); } - let clipped_primitives = self.egui_ctx.tessellate(shapes); + let pixels_per_point = self.egui_ctx.pixels_per_point(); + let clipped_primitives = self.egui_ctx.tessellate(shapes, pixels_per_point); let dimensions: [u32; 2] = window.inner_size().into(); - self.painter.paint_primitives( - dimensions, - self.egui_ctx.pixels_per_point(), - &clipped_primitives, - ); + self.painter + .paint_primitives(dimensions, pixels_per_point, &clipped_primitives); for id in textures_delta.free.drain(..) { self.painter.free_texture(id);