mirror of
https://github.com/emilk/egui.git
synced 2026-09-03 07:10:04 -04:00
Fix: First frame of Context::create_viewport_sync was always skiped because we didn't have a window to draw on!
Changes: Now Context::create_viewport_sync returns T, before was Option<T>
This commit is contained in:
@@ -29,6 +29,13 @@ pub const IS_DESKTOP: bool = cfg!(any(
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
thread_local! {
|
||||
/// This makes `Context::create_viewport_sync` to have a native window in the same frame!
|
||||
pub static WINIT_EVENT_LOOP: RwLock<*const EventLoopWindowTarget<UserEvent>> = RwLock::new(std::ptr::null());
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum UserEvent {
|
||||
RequestRepaint {
|
||||
@@ -152,6 +159,8 @@ fn run_and_return(
|
||||
let mut returned_result = Ok(());
|
||||
|
||||
event_loop.run_return(|event, event_loop, control_flow| {
|
||||
WINIT_EVENT_LOOP.with(|row_event_loop| *row_event_loop.write() = event_loop);
|
||||
|
||||
let events = match &event {
|
||||
winit::event::Event::LoopDestroyed => {
|
||||
// On Mac, Cmd-Q we get here and then `run_return` doesn't return (despite its name),
|
||||
@@ -309,6 +318,8 @@ fn run_and_exit(event_loop: EventLoop<UserEvent>, mut winit_app: impl WinitApp +
|
||||
let mut windows_next_repaint_times = HashMap::default();
|
||||
|
||||
event_loop.run(move |event, event_loop, control_flow| {
|
||||
WINIT_EVENT_LOOP.with(|row_event_loop| *row_event_loop.write() = event_loop);
|
||||
|
||||
let events = match event {
|
||||
winit::event::Event::LoopDestroyed => {
|
||||
log::debug!("Received Event::LoopDestroyed");
|
||||
@@ -654,14 +665,28 @@ mod glow_integration {
|
||||
/// 4. make surface and context current.
|
||||
///
|
||||
/// we presently assume that we will
|
||||
#[allow(unsafe_code)]
|
||||
fn on_resume(&mut self, event_loop: &EventLoopWindowTarget<UserEvent>) -> Result<()> {
|
||||
for win in self.windows.values_mut() {
|
||||
let mut win = win.write();
|
||||
if win.gl_surface.is_some() {
|
||||
let values = self
|
||||
.windows
|
||||
.values()
|
||||
.cloned()
|
||||
.collect::<Vec<Arc<RwLock<Window>>>>();
|
||||
for win in values {
|
||||
if win.read().gl_surface.is_some() {
|
||||
continue;
|
||||
}
|
||||
log::debug!("running on_resume fn.");
|
||||
self.init_window(&win, event_loop)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
pub(crate) fn init_window(
|
||||
&mut self,
|
||||
win: &Arc<RwLock<Window>>,
|
||||
event_loop: &EventLoopWindowTarget<UserEvent>,
|
||||
) -> Result<()> {
|
||||
let mut win = win.write();
|
||||
// make sure we have a window or create one.
|
||||
let window = win.window.take().unwrap_or_else(|| {
|
||||
log::debug!("window doesn't exist yet. creating one now with finalize_window");
|
||||
@@ -694,9 +719,7 @@ mod glow_integration {
|
||||
.display()
|
||||
.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.
|
||||
let not_current_gl_context =
|
||||
if let Some(not_current_context) = self.not_current_gl_context.take() {
|
||||
@@ -733,7 +756,6 @@ mod glow_integration {
|
||||
self.window_maps.insert(window.id(), win.window_id);
|
||||
}
|
||||
win.window = Some(window);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1006,8 +1028,19 @@ mod glow_integration {
|
||||
|
||||
// Sync Rendering
|
||||
integration.egui_ctx.set_render_sync_callback(
|
||||
move |_viewport_builder, viewport_id, parent_viewport_id, render| {
|
||||
// TODO: we should use `_viewport_builder` to create a new window in this frame!
|
||||
move |viewport_builder, viewport_id, parent_viewport_id, render| {
|
||||
let has_window = glutin.read().windows.get(&viewport_id).is_some();
|
||||
if !has_window{
|
||||
glutin.write().windows.entry(viewport_id).or_insert(Arc::new(RwLock::new(Window{ builder: viewport_builder, gl_surface: None, window: None, window_id: viewport_id, parent_id: parent_viewport_id, render: None, egui_winit: None })));
|
||||
let win = glutin.read().windows.get(&viewport_id).cloned().unwrap();
|
||||
let event_loop;
|
||||
#[allow(unsafe_code)]
|
||||
unsafe{
|
||||
event_loop = WINIT_EVENT_LOOP.with(|event_loop|event_loop.read().as_ref().unwrap());
|
||||
}
|
||||
glutin.write().init_window(&win, event_loop).expect("Cannot init window on egui::Context::create_viewport_sync");
|
||||
}
|
||||
|
||||
'try_render: {
|
||||
let window = glutin.read().windows.get(&viewport_id).cloned();
|
||||
if let Some(window) = window {
|
||||
@@ -1787,7 +1820,7 @@ mod wgpu_integration {
|
||||
integration: Arc<RwLock<epi_integration::EpiIntegration>>,
|
||||
app: Box<dyn epi::App>,
|
||||
windows: Windows,
|
||||
windows_id: HashMap<winit::window::WindowId, ViewportId>,
|
||||
windows_id: Arc<RwLock<HashMap<winit::window::WindowId, ViewportId>>>,
|
||||
}
|
||||
|
||||
struct WgpuWinitApp {
|
||||
@@ -1848,21 +1881,43 @@ mod wgpu_integration {
|
||||
let Some(running) = &mut self.running else {return};
|
||||
|
||||
for (id, (window, state, _, _, builder)) in running.windows.write().iter_mut() {
|
||||
if window.is_none() {
|
||||
if let Ok(new_window) = create_winit_window_builder(builder).build(event_loop) {
|
||||
running.windows_id.insert(new_window.id(), *id);
|
||||
if window.is_some() {
|
||||
continue;
|
||||
}
|
||||
|
||||
if let Err(err) = pollster::block_on(
|
||||
running.painter.write().set_window(*id, Some(&new_window)),
|
||||
Self::init_window(
|
||||
*id,
|
||||
builder,
|
||||
&mut running.windows_id.write(),
|
||||
&running.painter,
|
||||
window,
|
||||
state,
|
||||
event_loop,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn init_window(
|
||||
id: ViewportId,
|
||||
builder: &ViewportBuilder,
|
||||
windows_id: &mut HashMap<winit::window::WindowId, ViewportId>,
|
||||
painter: &Arc<RwLock<egui_wgpu::winit::Painter>>,
|
||||
window: &mut Option<Arc<RwLock<winit::window::Window>>>,
|
||||
state: &Arc<RwLock<Option<egui_winit::State>>>,
|
||||
event_loop: &EventLoopWindowTarget<UserEvent>,
|
||||
) {
|
||||
if let Ok(new_window) = create_winit_window_builder(builder).build(event_loop) {
|
||||
windows_id.insert(new_window.id(), id);
|
||||
|
||||
if let Err(err) =
|
||||
pollster::block_on(painter.write().set_window(id, Some(&new_window)))
|
||||
{
|
||||
log::error!("on set_window: viewport_id {id} {err}");
|
||||
}
|
||||
*window = Some(Arc::new(RwLock::new(new_window)));
|
||||
*state.write() = Some(egui_winit::State::new(event_loop));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn set_window(&mut self, id: ViewportId) -> std::result::Result<(), egui_wgpu::WgpuError> {
|
||||
if let Some(running) = &mut self.running {
|
||||
@@ -1974,6 +2029,7 @@ mod wgpu_integration {
|
||||
|
||||
let mut windows_id = HashMap::default();
|
||||
windows_id.insert(window.id(), ViewportId::MAIN);
|
||||
let windows_id = Arc::new(RwLock::new(windows_id));
|
||||
|
||||
let windows = Windows(Arc::new(RwLock::new(HashMap::default())));
|
||||
windows.write().insert(
|
||||
@@ -1993,10 +2049,22 @@ mod wgpu_integration {
|
||||
let time = integration.beginning;
|
||||
let painter = Arc::new(RwLock::new(painter));
|
||||
let _painter = painter.clone();
|
||||
let _windows_id = windows_id.clone();
|
||||
|
||||
integration.egui_ctx.set_render_sync_callback(
|
||||
move |_viewport_builder, viewport_id, parent_viewport_id, render| {
|
||||
// TODO: we should use `_viewport_builder` to create a new window in this frame!
|
||||
move |viewport_builder, viewport_id, parent_viewport_id, render| {
|
||||
if _windows.read().get(&viewport_id).is_none(){
|
||||
let mut _windows = _windows.write();
|
||||
let (window, state, _, _, _) = _windows.entry(viewport_id).or_insert((None, Arc::new(RwLock::new(None)), None, viewport_id, viewport_builder.clone()));
|
||||
|
||||
let event_loop;
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
unsafe{
|
||||
event_loop = WINIT_EVENT_LOOP.with(|event_loop|event_loop.read().as_ref().unwrap());
|
||||
}
|
||||
Self::init_window(viewport_id, &viewport_builder, &mut _windows_id.write(), &_painter, window, state, event_loop);
|
||||
}
|
||||
'try_render: {
|
||||
let window = _windows.read().get(&viewport_id).cloned();
|
||||
if let Some(window) = window {
|
||||
@@ -2116,6 +2184,7 @@ mod wgpu_integration {
|
||||
.as_ref()
|
||||
.and_then(|r| {
|
||||
r.windows_id
|
||||
.read()
|
||||
.get(&window_id)
|
||||
.and_then(|id| r.windows.read().get(id).map(|w| w.0.clone()))
|
||||
})
|
||||
@@ -2173,7 +2242,7 @@ mod wgpu_integration {
|
||||
viewport_commands,
|
||||
};
|
||||
{
|
||||
let Some((viewport_id, (Some(window), state, render, parent_viewport_id, _))) = windows_id.get(&window_id).and_then(|id|(windows.read().get(id).map(|w|(*id, w.clone())))) else{return vec![]};
|
||||
let Some((viewport_id, (Some(window), state, render, parent_viewport_id, _))) = windows_id.read().get(&window_id).and_then(|id|(windows.read().get(id).map(|w|(*id, w.clone())))) else{return vec![]};
|
||||
// This is used to not render a viewport if is sync
|
||||
if viewport_id != ViewportId::MAIN && render.is_none() {
|
||||
if let Some(window) = running.windows.read().get(&parent_viewport_id) {
|
||||
@@ -2265,7 +2334,9 @@ mod wgpu_integration {
|
||||
windows
|
||||
.write()
|
||||
.retain(|id, _| active_viewports_ids.contains(id));
|
||||
windows_id.retain(|_, id| active_viewports_ids.contains(id));
|
||||
windows_id
|
||||
.write()
|
||||
.retain(|_, id| active_viewports_ids.contains(id));
|
||||
painter.write().clean_surfaces(&active_viewports_ids);
|
||||
|
||||
let mut control_flow = vec![EventResult::Wait];
|
||||
@@ -2300,7 +2371,7 @@ mod wgpu_integration {
|
||||
});
|
||||
}
|
||||
|
||||
let Some((_, (Some(window), _, _, _, _))) = windows_id.get(&window_id).and_then(|id|(windows.read().get(id).map(|w|(*id, w.clone())))) else{return vec![]};
|
||||
let Some((_, (Some(window), _, _, _, _))) = windows_id.read().get(&window_id).and_then(|id|(windows.read().get(id).map(|w|(*id, w.clone())))) else{return vec![]};
|
||||
integration
|
||||
.write()
|
||||
.maybe_autosave(app.as_mut(), window.clone());
|
||||
@@ -2402,7 +2473,7 @@ mod wgpu_integration {
|
||||
// See: https://github.com/rust-windowing/winit/issues/208
|
||||
// This solves an issue where the app would panic when minimizing on Windows.
|
||||
if let Some(viewport_id) =
|
||||
running.windows_id.get(window_id).copied()
|
||||
running.windows_id.read().get(window_id).copied()
|
||||
{
|
||||
if physical_size.width > 0 && physical_size.height > 0 {
|
||||
running.painter.write().on_window_resized(
|
||||
@@ -2418,7 +2489,7 @@ mod wgpu_integration {
|
||||
..
|
||||
} => {
|
||||
if let Some(viewport_id) =
|
||||
running.windows_id.get(window_id).copied()
|
||||
running.windows_id.read().get(window_id).copied()
|
||||
{
|
||||
repaint_asap = true;
|
||||
running.painter.write().on_window_resized(
|
||||
@@ -2437,11 +2508,10 @@ mod wgpu_integration {
|
||||
_ => {}
|
||||
};
|
||||
|
||||
let event_response = if let Some((id, (_, state, _, _, _))) = running
|
||||
.windows_id
|
||||
.get(window_id)
|
||||
.and_then(|id| running.windows.read().get(id).map(|w| (*id, w.clone())))
|
||||
{
|
||||
let event_response = if let Some((id, (_, state, _, _, _))) =
|
||||
running.windows_id.read().get(window_id).and_then(|id| {
|
||||
running.windows.read().get(id).map(|w| (*id, w.clone()))
|
||||
}) {
|
||||
if let Some(state) = &mut *state.write() {
|
||||
Some(running.integration.write().on_event(
|
||||
running.app.as_mut(),
|
||||
@@ -2482,6 +2552,7 @@ mod wgpu_integration {
|
||||
if let Some(running) = &mut self.running {
|
||||
if let Some((_, state, _, _, _)) = running
|
||||
.windows_id
|
||||
.read()
|
||||
.get(window_id)
|
||||
.and_then(|id| running.windows.read().get(id).cloned())
|
||||
{
|
||||
@@ -2503,7 +2574,7 @@ mod wgpu_integration {
|
||||
fn get_window_id(&self, id: &winit::window::WindowId) -> Option<ViewportId> {
|
||||
self.running
|
||||
.as_ref()
|
||||
.and_then(|r| r.windows_id.get(id).copied())
|
||||
.and_then(|r| r.windows_id.read().get(id).copied())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -396,7 +396,7 @@ impl<'open> Window<'open> {
|
||||
.with_max_inner_size(Some((max_size.x as u32, max_size.y as u32)));
|
||||
}
|
||||
|
||||
return ctx.create_viewport_sync(window_builder, move |ctx| {
|
||||
return Some(ctx.create_viewport_sync(window_builder, move |ctx| {
|
||||
let mut op = is_open;
|
||||
let open = if show_close_button {
|
||||
Some(&mut op)
|
||||
@@ -625,7 +625,7 @@ impl<'open> Window<'open> {
|
||||
inner: content_inner,
|
||||
response: full_response,
|
||||
}
|
||||
});
|
||||
}));
|
||||
}
|
||||
}
|
||||
let frame = frame.unwrap_or_else(|| Frame::window(&ctx.style()));
|
||||
|
||||
@@ -2318,7 +2318,7 @@ impl Context {
|
||||
&self,
|
||||
viewport_builder: ViewportBuilder,
|
||||
func: impl FnOnce(&Context) -> T,
|
||||
) -> Option<T> {
|
||||
) -> T {
|
||||
if !self.force_embedding() {
|
||||
let mut viewport_id = ViewportId::MAIN;
|
||||
let mut parent_viewport_id = ViewportId::MAIN;
|
||||
@@ -2355,9 +2355,9 @@ impl Context {
|
||||
);
|
||||
}
|
||||
|
||||
out
|
||||
out.expect("egui backend is implemented incorrectly! Context::set_render_sync_callback")
|
||||
} else {
|
||||
Some(func(self))
|
||||
func(self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user