1
0
mirror of https://github.com/emilk/egui.git synced 2026-09-03 07:10:04 -04:00

Replace four locks with a single lock

This commit is contained in:
Emil Ernerfeldt
2023-11-11 19:51:51 +01:00
parent 9c420b9644
commit d439965322

View File

@@ -1858,16 +1858,20 @@ mod wgpu_integration {
pub type Viewports = ViewportIdMap<Viewport>; pub type Viewports = ViewportIdMap<Viewport>;
pub struct SharedState {
viewports: Viewports,
builders: ViewportIdMap<ViewportBuilder>,
painter: egui_wgpu::winit::Painter,
viewport_maps: HashMap<winit::window::WindowId, ViewportId>,
}
/// State that is initialized when the application is first starts running via /// State that is initialized when the application is first starts running via
/// a Resumed event. On Android this ensures that any graphics state is only /// a Resumed event. On Android this ensures that any graphics state is only
/// initialized once the application has an associated `SurfaceView`. /// initialized once the application has an associated `SurfaceView`.
struct WgpuWinitRunning { struct WgpuWinitRunning {
painter: Rc<RefCell<egui_wgpu::winit::Painter>>,
integration: epi_integration::EpiIntegration, integration: epi_integration::EpiIntegration,
app: Box<dyn epi::App>, app: Box<dyn epi::App>,
viewports: Rc<RefCell<Viewports>>, shared: Rc<RefCell<SharedState>>,
builders: Rc<RefCell<ViewportIdMap<ViewportBuilder>>>,
viewport_maps: Rc<RefCell<HashMap<winit::window::WindowId, ViewportId>>>,
} }
struct WgpuWinitApp { struct WgpuWinitApp {
@@ -1934,10 +1938,16 @@ mod wgpu_integration {
let Some(running) = &mut self.running else { let Some(running) = &mut self.running else {
return; return;
}; };
let viewport_builders = running.builders.borrow(); let mut shared = running.shared.borrow_mut();
let SharedState {
viewports,
builders,
painter,
viewport_maps,
} = &mut *shared;
for (id, viewport) in running.viewports.borrow_mut().iter_mut() { for (id, viewport) in viewports.iter_mut() {
let builder = viewport_builders.get(id).unwrap(); let builder = builders.get(id).unwrap();
if viewport.window.is_some() { if viewport.window.is_some() {
continue; continue;
} }
@@ -1945,8 +1955,8 @@ mod wgpu_integration {
Self::init_window( Self::init_window(
*id, *id,
builder, builder,
&mut running.viewport_maps.borrow_mut(), viewport_maps,
&mut running.painter.borrow_mut(), painter,
&mut viewport.window, &mut viewport.window,
&mut viewport.egui_winit.borrow_mut(), &mut viewport.egui_winit.borrow_mut(),
event_loop, event_loop,
@@ -1985,19 +1995,15 @@ mod wgpu_integration {
fn set_window(&mut self, id: ViewportId) -> std::result::Result<(), egui_wgpu::WgpuError> { fn set_window(&mut self, id: ViewportId) -> std::result::Result<(), egui_wgpu::WgpuError> {
if let Some(running) = &mut self.running { if let Some(running) = &mut self.running {
crate::profile_function!(); crate::profile_function!();
if let Some(Viewport { window, .. }) = running.viewports.borrow().get(&id) { let mut shared = running.shared.borrow_mut();
if let Some(Viewport { window, .. }) = shared.viewports.get(&id) {
let window = window.clone(); let window = window.clone();
if let Some(window) = &window { if let Some(window) = &window {
return pollster::block_on( return pollster::block_on(
running shared.painter.set_window(id, Some(&*window.borrow())),
.painter
.borrow_mut()
.set_window(id, Some(&*window.borrow())),
); );
} else { } else {
return pollster::block_on( return pollster::block_on(shared.painter.set_window(id, None));
running.painter.borrow_mut().set_window(id, None),
);
}; };
} }
} }
@@ -2113,10 +2119,9 @@ mod wgpu_integration {
let mut viewport_maps = HashMap::default(); let mut viewport_maps = HashMap::default();
viewport_maps.insert(window.id(), ViewportId::ROOT); viewport_maps.insert(window.id(), ViewportId::ROOT);
let viewport_maps = Rc::new(RefCell::new(viewport_maps));
let viewports = Rc::new(RefCell::new(Viewports::default())); let mut viewports = Viewports::default();
viewports.borrow_mut().insert( viewports.insert(
ViewportId::ROOT, ViewportId::ROOT,
Viewport { Viewport {
window: Some(Rc::new(RefCell::new(window))), window: Some(Rc::new(RefCell::new(window))),
@@ -2126,43 +2131,31 @@ mod wgpu_integration {
}, },
); );
let builders = Rc::new(RefCell::new(ViewportIdMap::default())); let mut builders = ViewportIdMap::default();
builders.borrow_mut().insert(ViewportId::ROOT, builder); builders.insert(ViewportId::ROOT, builder);
let painter = Rc::new(RefCell::new(painter)); let shared = Rc::new(RefCell::new(SharedState {
viewport_maps,
viewports,
builders,
painter,
}));
{ {
// Create weak pointers so that we don't keep // Create a weak pointer so that we don't keep state alive for too long.
// state alive for too long. let shared = Rc::downgrade(&shared);
let viewports = Rc::downgrade(&viewports);
let builders = Rc::downgrade(&builders);
let painter = Rc::downgrade(&painter);
let viewport_maps = Rc::downgrade(&viewport_maps);
let beginning = integration.beginning; let beginning = integration.beginning;
integration.egui_ctx.set_immediate_viewport_renderer( integration.egui_ctx.set_immediate_viewport_renderer(
move |egui_ctx, viewport_builder, id_pair, viewport_ui_cb| { move |egui_ctx, viewport_builder, id_pair, viewport_ui_cb| {
if let ( if let Some(shared) = shared.upgrade() {
Some(viewports),
Some(builders),
Some(painter),
Some(viewport_maps),
) = (
viewports.upgrade(),
builders.upgrade(),
painter.upgrade(),
viewport_maps.upgrade(),
) {
Self::render_immediate_viewport( Self::render_immediate_viewport(
egui_ctx, egui_ctx,
viewport_builder, viewport_builder,
id_pair, id_pair,
viewport_ui_cb, viewport_ui_cb,
&viewports,
&builders,
beginning, beginning,
&painter, &shared,
&viewport_maps,
); );
} else { } else {
log::warn!("render_sync_callback called after window closed"); log::warn!("render_sync_callback called after window closed");
@@ -2172,12 +2165,9 @@ mod wgpu_integration {
} }
self.running = Some(WgpuWinitRunning { self.running = Some(WgpuWinitRunning {
painter,
integration, integration,
app, app,
viewports, shared,
viewport_maps,
builders,
}); });
Ok(()) Ok(())
@@ -2190,27 +2180,30 @@ mod wgpu_integration {
mut viewport_builder: ViewportBuilder, mut viewport_builder: ViewportBuilder,
id_pair: ViewportIdPair, id_pair: ViewportIdPair,
viewport_ui_cb: Box<dyn FnOnce(&egui::Context) + '_>, viewport_ui_cb: Box<dyn FnOnce(&egui::Context) + '_>,
viewports: &RefCell<Viewports>,
builders: &RefCell<ViewportIdMap<ViewportBuilder>>,
beginning: Instant, beginning: Instant,
painter: &RefCell<egui_wgpu::winit::Painter>, shared: &RefCell<SharedState>,
viewport_maps: &RefCell<HashMap<winit::window::WindowId, ViewportId>>,
) { ) {
crate::profile_function!(); crate::profile_function!();
// Creating a new native window if is needed let input = {
if viewports.borrow().get(&id_pair.this).is_none() { let mut shared = shared.borrow_mut();
let mut builders = builders.borrow_mut(); let SharedState {
viewports,
builders,
painter,
viewport_maps,
} = &mut *shared;
// Creating a new native window if is needed
if !viewports.contains_key(&id_pair.this) {
{
if viewport_builder.icon.is_none() && builders.get(&id_pair.this).is_none()
{ {
if viewport_builder.icon.is_none() && builders.get(&id_pair.this).is_none() {
viewport_builder.icon = viewport_builder.icon =
builders.get(&id_pair.parent).and_then(|b| b.icon.clone()); builders.get(&id_pair.parent).and_then(|b| b.icon.clone());
} }
} }
let mut viewports = viewports.borrow_mut();
let Viewport { let Viewport {
window, window,
egui_winit: state, egui_winit: state,
@@ -2235,8 +2228,8 @@ mod wgpu_integration {
Self::init_window( Self::init_window(
id_pair.this, id_pair.this,
&viewport_builder, &viewport_builder,
&mut viewport_maps.borrow_mut(), viewport_maps,
&mut painter.borrow_mut(), painter,
window, window,
&mut state.borrow_mut(), &mut state.borrow_mut(),
event_loop, event_loop,
@@ -2244,7 +2237,7 @@ mod wgpu_integration {
} }
// Render sync viewport: // Render sync viewport:
let viewport = viewports.borrow().get(&id_pair.this).cloned(); let viewport = viewports.get(&id_pair.this).cloned();
let Some(viewport) = viewport else { return }; let Some(viewport) = viewport else { return };
let Some(winit_state) = &mut *viewport.egui_winit.borrow_mut() else { let Some(winit_state) = &mut *viewport.egui_winit.borrow_mut() else {
return; return;
@@ -2252,16 +2245,37 @@ mod wgpu_integration {
let Some(window) = viewport.window else { let Some(window) = viewport.window else {
return; return;
}; };
let win = window.borrow(); let window = window.borrow();
let mut input = winit_state.take_egui_input(&win, id_pair); let mut input = winit_state.take_egui_input(&window, id_pair);
input.time = Some(beginning.elapsed().as_secs_f64()); input.time = Some(beginning.elapsed().as_secs_f64());
input
};
// ------------------------------------------
// Run the user code, which could re-entrantly call this function again (!)
let output = egui_ctx.run(input, |ctx| { let output = egui_ctx.run(input, |ctx| {
viewport_ui_cb(ctx); viewport_ui_cb(ctx);
}); });
let mut painter = painter.borrow_mut(); // ------------------------------------------
if let Err(err) = pollster::block_on(painter.set_window(id_pair.this, Some(&win))) { let mut shared = shared.borrow_mut();
let SharedState {
viewports, painter, ..
} = &mut *shared;
let viewport = viewports.get(&id_pair.this).cloned();
let Some(viewport) = viewport else { return };
let Some(winit_state) = &mut *viewport.egui_winit.borrow_mut() else {
return;
};
let Some(window) = viewport.window else {
return;
};
let window = window.borrow();
if let Err(err) = pollster::block_on(painter.set_window(id_pair.this, Some(&window))) {
log::error!( log::error!(
"when rendering viewport_id={:?}, set_window Error {err}", "when rendering viewport_id={:?}, set_window Error {err}",
id_pair.this id_pair.this
@@ -2280,7 +2294,7 @@ mod wgpu_integration {
); );
winit_state.handle_platform_output( winit_state.handle_platform_output(
&win, &window,
id_pair.this, id_pair.this,
egui_ctx, egui_ctx,
output.platform_output, output.platform_output,
@@ -2315,29 +2329,31 @@ mod wgpu_integration {
self.running self.running
.as_ref() .as_ref()
.and_then(|r| { .and_then(|r| {
r.viewport_maps let shared = r.shared.borrow();
.borrow() shared
.viewport_maps
.get(&window_id) .get(&window_id)
.and_then(|id| r.viewports.borrow().get(id).map(|w| w.window.clone())) .and_then(|id| shared.viewports.get(id).map(|w| w.window.clone()))
}) })
.flatten() .flatten()
} }
fn window_id_from_viewport_id(&self, id: ViewportId) -> Option<winit::window::WindowId> { fn window_id_from_viewport_id(&self, id: ViewportId) -> Option<winit::window::WindowId> {
self.running.as_ref().and_then(|r| { self.running.as_ref().and_then(|r| {
r.viewports r.shared
.borrow() .borrow()
.viewports
.get(&id) .get(&id)
.and_then(|w| w.window.as_ref().map(|w| w.borrow().id())) .and_then(|w| w.window.as_ref().map(|w| w.borrow().id()))
}) })
} }
fn save_and_destroy(&mut self) { fn save_and_destroy(&mut self) {
if let Some(mut running) = self.running.take() {
crate::profile_function!(); crate::profile_function!();
if let Some(Viewport { window, .. }) =
running.viewports.borrow().get(&ViewportId::ROOT) if let Some(mut running) = self.running.take() {
{ let mut shared = running.shared.borrow_mut();
if let Some(Viewport { window, .. }) = shared.viewports.get(&ViewportId::ROOT) {
running.integration.save( running.integration.save(
running.app.as_mut(), running.app.as_mut(),
window.as_ref().map(|w| w.borrow()).as_deref(), window.as_ref().map(|w| w.borrow()).as_deref(),
@@ -2350,7 +2366,7 @@ mod wgpu_integration {
#[cfg(not(feature = "glow"))] #[cfg(not(feature = "glow"))]
running.app.on_exit(); running.app.on_exit();
running.painter.borrow_mut().destroy(); shared.painter.destroy();
} }
} }
@@ -2366,10 +2382,7 @@ mod wgpu_integration {
let WgpuWinitRunning { let WgpuWinitRunning {
app, app,
integration, integration,
painter, shared,
viewports,
viewport_maps,
builders,
} = running; } = running;
let egui::FullOutput { let egui::FullOutput {
@@ -2381,24 +2394,30 @@ mod wgpu_integration {
}; };
{ {
let Some(( let mut shared_lock = shared.borrow_mut();
viewport_id,
Viewport { let Some(viewport_id) = shared_lock.viewport_maps.get(&window_id).copied() else {
window: Some(window),
egui_winit: state,
viewport_ui_cb,
parent_id,
},
)) = viewport_maps
.borrow()
.get(&window_id)
.and_then(|id| (viewports.borrow().get(id).map(|w| (*id, w.clone()))))
else {
return EventResult::Wait; return EventResult::Wait;
}; };
let Some(viewport) = shared_lock.viewports.get(&viewport_id).cloned() else {
return EventResult::Wait;
};
let Viewport {
window,
egui_winit,
viewport_ui_cb,
parent_id,
} = viewport;
let Some(window) = window else {
return EventResult::Wait;
};
// This is used to not render a viewport if is sync // This is used to not render a viewport if is sync
if viewport_id != ViewportId::ROOT && viewport_ui_cb.is_none() { if viewport_id != ViewportId::ROOT && viewport_ui_cb.is_none() {
if let Some(viewport) = running.viewports.borrow().get(&parent_id) { if let Some(viewport) = shared_lock.viewports.get(&parent_id) {
if let Some(window) = viewport.window.as_ref() { if let Some(window) = viewport.window.as_ref() {
return EventResult::RepaintNext(window.borrow().id()); return EventResult::RepaintNext(window.borrow().id());
} }
@@ -2407,11 +2426,15 @@ mod wgpu_integration {
} }
let _ = pollster::block_on( let _ = pollster::block_on(
painter shared_lock
.borrow_mut() .painter
.set_window(viewport_id, Some(&window.borrow())), .set_window(viewport_id, Some(&window.borrow())),
); );
drop(shared_lock); // Release lock!
// Runs the update, which could call immedaite viewports,
// so make sure we hold no locks here!
egui::FullOutput { egui::FullOutput {
platform_output, platform_output,
textures_delta, textures_delta,
@@ -2421,7 +2444,7 @@ mod wgpu_integration {
} = integration.update( } = integration.update(
app.as_mut(), app.as_mut(),
&window.borrow(), &window.borrow(),
state.borrow_mut().as_mut().unwrap(), egui_winit.borrow_mut().as_mut().unwrap(),
viewport_ui_cb.as_deref(), viewport_ui_cb.as_deref(),
ViewportIdPair { ViewportIdPair {
this: viewport_id, this: viewport_id,
@@ -2433,7 +2456,7 @@ mod wgpu_integration {
&window.borrow(), &window.borrow(),
viewport_id, viewport_id,
platform_output, platform_output,
state.borrow_mut().as_mut().unwrap(), egui_winit.borrow_mut().as_mut().unwrap(),
); );
let clipped_primitives = integration.egui_ctx.tessellate(shapes); let clipped_primitives = integration.egui_ctx.tessellate(shapes);
@@ -2444,7 +2467,7 @@ mod wgpu_integration {
.egui_ctx .egui_ctx
.input_for(viewport_id, |i| i.pixels_per_point()); .input_for(viewport_id, |i| i.pixels_per_point());
let screenshot = painter.borrow_mut().paint_and_update_textures( let screenshot = shared.borrow_mut().painter.paint_and_update_textures(
viewport_id, viewport_id,
pixels_per_point, pixels_per_point,
app.clear_color(&integration.egui_ctx.style().visuals), app.clear_color(&integration.egui_ctx.style().visuals),
@@ -2459,6 +2482,14 @@ mod wgpu_integration {
integration.post_present(&window.borrow()); integration.post_present(&window.borrow());
} }
let mut shared = shared.borrow_mut();
let SharedState {
viewports,
builders,
painter,
viewport_maps,
} = &mut *shared;
let mut active_viewports_ids = ViewportIdSet::default(); let mut active_viewports_ids = ViewportIdSet::default();
active_viewports_ids.insert(ViewportId::ROOT); active_viewports_ids.insert(ViewportId::ROOT);
@@ -2468,7 +2499,7 @@ mod wgpu_integration {
viewport_ui_cb, viewport_ui_cb,
.. ..
}| { }| {
if let Some(viewport) = viewports.borrow_mut().get_mut(this) { if let Some(viewport) = viewports.get_mut(this) {
viewport.viewport_ui_cb = viewport_ui_cb.clone(); viewport.viewport_ui_cb = viewport_ui_cb.clone();
viewport.parent_id = *parent; viewport.parent_id = *parent;
active_viewports_ids.insert(*this); active_viewports_ids.insert(*this);
@@ -2485,9 +2516,6 @@ mod wgpu_integration {
viewport_ui_cb, viewport_ui_cb,
} in out_viewports } in out_viewports
{ {
let mut builders = builders.borrow_mut();
let mut viewports = viewports.borrow_mut();
if new_builder.icon.is_none() { if new_builder.icon.is_none() {
new_builder.icon = builders new_builder.icon = builders
.get_mut(&id_pair.parent) .get_mut(&id_pair.parent)
@@ -2526,11 +2554,7 @@ mod wgpu_integration {
} }
for (viewport_id, command) in viewport_commands { for (viewport_id, command) in viewport_commands {
if let Some(window) = viewports if let Some(window) = viewports.get(&viewport_id).and_then(|w| w.window.clone()) {
.borrow()
.get(&viewport_id)
.and_then(|w| w.window.clone())
{
egui_winit::process_viewport_commands( egui_winit::process_viewport_commands(
vec![command], vec![command],
viewport_id, viewport_id,
@@ -2540,24 +2564,17 @@ mod wgpu_integration {
} }
} }
viewports viewports.retain(|id, _| active_viewports_ids.contains(id));
.borrow_mut() builders.retain(|id, _| active_viewports_ids.contains(id));
.retain(|id, _| active_viewports_ids.contains(id)); viewport_maps.retain(|_, id| active_viewports_ids.contains(id));
builders painter.gc_viewports(&active_viewports_ids);
.borrow_mut()
.retain(|id, _| active_viewports_ids.contains(id));
viewport_maps
.borrow_mut()
.retain(|_, id| active_viewports_ids.contains(id));
painter.borrow_mut().gc_viewports(&active_viewports_ids);
let Some(Viewport { let Some(Viewport {
window: Some(window), window: Some(window),
.. ..
}) = viewport_maps }) = viewport_maps
.borrow()
.get(&window_id) .get(&window_id)
.and_then(|id| viewports.borrow().get(id).cloned()) .and_then(|id| viewports.get(id).cloned())
else { else {
return EventResult::Wait; return EventResult::Wait;
}; };
@@ -2588,7 +2605,12 @@ mod wgpu_integration {
Ok(match event { Ok(match event {
winit::event::Event::Resumed => { winit::event::Event::Resumed => {
if let Some(running) = &self.running { if let Some(running) = &self.running {
if running.viewports.borrow().get(&ViewportId::ROOT).is_none() { if !running
.shared
.borrow()
.viewports
.contains_key(&ViewportId::ROOT)
{
let _ = Self::create_window( let _ = Self::create_window(
event_loop, event_loop,
running.integration.frame.storage(), running.integration.frame.storage(),
@@ -2612,14 +2634,9 @@ mod wgpu_integration {
)?; )?;
self.init_run_state(event_loop, storage, window, builder)?; self.init_run_state(event_loop, storage, window, builder)?;
} }
let running = self.running.as_ref().unwrap(); // Can't fail - we just initialized it
EventResult::RepaintNow( EventResult::RepaintNow(
self.running running.shared.borrow().viewports[&ViewportId::ROOT]
.as_ref()
.unwrap()
.viewports
.borrow()
.get(&ViewportId::ROOT)
.unwrap()
.window .window
.as_ref() .as_ref()
.unwrap() .unwrap()
@@ -2668,7 +2685,7 @@ mod wgpu_integration {
NonZeroU32::new(physical_size.width), NonZeroU32::new(physical_size.width),
NonZeroU32::new(physical_size.height), NonZeroU32::new(physical_size.height),
) { ) {
running.painter.borrow_mut().on_window_resized( running.shared.borrow_mut().painter.on_window_resized(
viewport_id, viewport_id,
width, width,
height, height,
@@ -2684,10 +2701,15 @@ mod wgpu_integration {
if let (Some(width), Some(height), Some(viewport_id)) = ( if let (Some(width), Some(height), Some(viewport_id)) = (
NonZeroU32::new(new_inner_size.width), NonZeroU32::new(new_inner_size.width),
NonZeroU32::new(new_inner_size.height), NonZeroU32::new(new_inner_size.height),
running.viewport_maps.borrow().get(window_id).copied(), running
.shared
.borrow()
.viewport_maps
.get(window_id)
.copied(),
) { ) {
repaint_asap = true; repaint_asap = true;
running.painter.borrow_mut().on_window_resized( running.shared.borrow_mut().painter.on_window_resized(
viewport_id, viewport_id,
width, width,
height, height,
@@ -2705,7 +2727,12 @@ mod wgpu_integration {
let event_response = if let Some((id, viewport)) = let event_response = if let Some((id, viewport)) =
viewport_id.and_then(|id| { viewport_id.and_then(|id| {
running.viewports.borrow().get(&id).map(|w| (id, w.clone())) running
.shared
.borrow()
.viewports
.get(&id)
.map(|w| (id, w.clone()))
}) { }) {
if let Some(state) = &mut *viewport.egui_winit.borrow_mut() { if let Some(state) = &mut *viewport.egui_winit.borrow_mut() {
Some(running.integration.on_event( Some(running.integration.on_event(
@@ -2745,11 +2772,11 @@ mod wgpu_integration {
accesskit_winit::ActionRequestEvent { request, window_id }, accesskit_winit::ActionRequestEvent { request, window_id },
)) => { )) => {
if let Some(running) = &mut self.running { if let Some(running) = &mut self.running {
if let Some(viewport) = running let shared = running.shared.borrow();
if let Some(viewport) = shared
.viewport_maps .viewport_maps
.borrow()
.get(window_id) .get(window_id)
.and_then(|id| running.viewports.borrow().get(id).cloned()) .and_then(|id| shared.viewports.get(id).cloned())
{ {
if let Some(state) = &mut *viewport.egui_winit.borrow_mut() { if let Some(state) = &mut *viewport.egui_winit.borrow_mut() {
state.on_accesskit_action_request(request.clone()); state.on_accesskit_action_request(request.clone());
@@ -2769,7 +2796,7 @@ mod wgpu_integration {
fn viewport_id_from_window_id(&self, id: &winit::window::WindowId) -> Option<ViewportId> { fn viewport_id_from_window_id(&self, id: &winit::window::WindowId) -> Option<ViewportId> {
self.running self.running
.as_ref() .as_ref()
.and_then(|r| r.viewport_maps.borrow().get(id).copied()) .and_then(|r| r.shared.borrow().viewport_maps.get(id).copied())
} }
} }